1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use crate::chip::boot_svc::{OwnershipActivateRequest, OwnershipUnlockRequest, UnlockMode};
use crate::crypto::ecdsa::{EcdsaPrivateKey, EcdsaPublicKey, EcdsaRawPublicKey, EcdsaRawSignature};
use crate::util::parse_int::ParseInt;
use anyhow::Result;
use clap::Args;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

#[derive(Debug, Args)]
pub struct OwnershipUnlockParams {
    #[arg(long, value_enum, help = "Requested unlock mode")]
    pub mode: Option<UnlockMode>,
    #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")]
    pub nonce: Option<u64>,
    #[arg(long, help = "A path to the next owner key (for endorsed mode)")]
    pub next_owner: Option<PathBuf>,
    #[arg(long, help = "A path to a detached signature for the unlock request")]
    pub signature: Option<PathBuf>,
    #[arg(long, help = "A path to a private key to sign the request")]
    pub sign: Option<PathBuf>,
}

impl OwnershipUnlockParams {
    /// Applies the parameters to the unlock request.
    pub fn apply(&self, unlock: &mut OwnershipUnlockRequest) -> Result<()> {
        if let Some(mode) = &self.mode {
            unlock.unlock_mode = *mode;
        }
        if let Some(nonce) = &self.nonce {
            unlock.nonce = *nonce;
        }
        if let Some(next_owner) = &self.next_owner {
            let key = EcdsaPublicKey::load(next_owner)?;
            unlock.next_owner_key = EcdsaRawPublicKey::try_from(&key)?;
        }
        if let Some(signature) = &self.signature {
            let mut f = File::open(signature)?;
            unlock.signature = EcdsaRawSignature::read(&mut f)?;
        }
        if let Some(sign) = &self.sign {
            let key = EcdsaPrivateKey::load(sign)?;
            unlock.sign(&key)?;
        }
        Ok(())
    }

    /// Reads an unlock request (or creates a default request) and applies the aprameters.
    pub fn apply_to(&self, reader: Option<&mut impl Read>) -> Result<OwnershipUnlockRequest> {
        let mut unlock = if let Some(r) = reader {
            let mut data = Vec::new();
            r.read_to_end(&mut data)?;
            OwnershipUnlockRequest::try_from(data.as_slice())?
        } else {
            OwnershipUnlockRequest::default()
        };
        self.apply(&mut unlock)?;
        Ok(unlock)
    }
}

#[derive(Debug, Args)]
pub struct OwnershipActivateParams {
    #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")]
    pub nonce: Option<u64>,
    #[arg(long, help = "A path to a detached signature for the activate request")]
    pub signature: Option<PathBuf>,
    #[arg(long, help = "A path to a private key to sign the request")]
    pub sign: Option<PathBuf>,
}

impl OwnershipActivateParams {
    /// Applies the parameters to the activate request.
    pub fn apply(&self, activate: &mut OwnershipActivateRequest) -> Result<()> {
        if let Some(nonce) = &self.nonce {
            activate.nonce = *nonce;
        }
        if let Some(signature) = &self.signature {
            let mut f = File::open(signature)?;
            activate.signature = EcdsaRawSignature::read(&mut f)?;
        }
        if let Some(sign) = &self.sign {
            let key = EcdsaPrivateKey::load(sign)?;
            activate.sign(&key)?;
        }
        Ok(())
    }

    /// Reads an activate request (or creates a default request) and applies the parameters.
    pub fn apply_to(&self, reader: Option<&mut impl Read>) -> Result<OwnershipActivateRequest> {
        let mut activate = if let Some(r) = reader {
            let mut data = Vec::new();
            r.read_to_end(&mut data)?;
            OwnershipActivateRequest::try_from(data.as_slice())?
        } else {
            OwnershipActivateRequest::default()
        };
        self.apply(&mut activate)?;
        Ok(activate)
    }
}