opentitanlib/chip/
helper.rs1use anyhow::Result;
6use clap::Args;
7use sphincsplus::{DecodeKey, SpxSecretKey};
8use std::fs::File;
9use std::io::Read;
10use std::path::PathBuf;
11
12use crate::chip::boot_svc::{OwnershipActivateRequest, OwnershipUnlockRequest, UnlockMode};
13use crate::crypto::ecdsa::{EcdsaPrivateKey, EcdsaPublicKey, EcdsaRawPublicKey, EcdsaRawSignature};
14use crate::ownership::{DetachedSignature, OwnershipKeyAlg};
15use crate::util::parse_int::ParseInt;
16
17#[derive(Debug, Default, Args)]
18pub struct OwnershipUnlockParams {
19 #[arg(long, value_enum, help = "Requested unlock mode")]
20 pub mode: Option<UnlockMode>,
21 #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")]
22 pub nonce: Option<u64>,
23 #[arg(long, value_parser = u64::from_str, help="Device Identification Number of the chip")]
24 pub din: Option<u64>,
25 #[arg(long, help = "A path to the next owner key (for endorsed mode)")]
26 pub next_owner: Option<PathBuf>,
27 #[arg(
28 long,
29 help = "A path to an external ECDSA signature for the unlock request"
30 )]
31 pub signature: Option<PathBuf>,
32 #[arg(long, default_value_t = OwnershipKeyAlg::EcdsaP256, help = "The algorithm used to sign the request")]
33 pub algorithm: OwnershipKeyAlg,
34 #[arg(long, help = "A path to a private ECDSA key to sign the request")]
35 pub ecdsa_key: Option<PathBuf>,
36 #[arg(long, help = "A path to a private SPX key to sign the request")]
37 pub spx_key: Option<PathBuf>,
38}
39
40impl OwnershipUnlockParams {
41 pub fn apply(&self, unlock: &mut OwnershipUnlockRequest) -> Result<Option<DetachedSignature>> {
43 if let Some(mode) = &self.mode {
44 unlock.unlock_mode = *mode;
45 }
46 if let Some(nonce) = &self.nonce {
47 unlock.nonce = *nonce;
48 }
49 if let Some(din) = &self.din {
50 unlock.din = *din;
51 }
52 if let Some(next_owner) = &self.next_owner {
53 let key = EcdsaPublicKey::load(next_owner)?;
54 unlock.next_owner_alg = self.algorithm;
56 unlock.next_owner_key = EcdsaRawPublicKey::try_from(&key)?;
57 }
58 if let Some(signature) = &self.signature {
59 let mut f = File::open(signature)?;
62 unlock.signature = EcdsaRawSignature::read(&mut f)?;
63 }
64 if self.ecdsa_key.is_some() || self.spx_key.is_some() {
65 let ecdsa_key = self
66 .ecdsa_key
67 .as_ref()
68 .map(EcdsaPrivateKey::load)
69 .transpose()?;
70 let spx_key = self
71 .spx_key
72 .as_ref()
73 .map(SpxSecretKey::read_pem_file)
74 .transpose()?;
75 let signature =
76 unlock.detached_sign(self.algorithm, ecdsa_key.as_ref(), spx_key.as_ref())?;
77 if !self.algorithm.is_detached() {
78 unlock.signature = signature.ecdsa.clone().expect("ECDSA signature");
79 }
80 Ok(Some(signature))
81 } else {
82 Ok(None)
83 }
84 }
85
86 pub fn apply_to(
88 &self,
89 reader: Option<&mut impl Read>,
90 ) -> Result<(OwnershipUnlockRequest, Option<DetachedSignature>)> {
91 let mut unlock = if let Some(r) = reader {
92 let mut data = Vec::new();
93 r.read_to_end(&mut data)?;
94 OwnershipUnlockRequest::try_from(data.as_slice())?
95 } else {
96 OwnershipUnlockRequest::default()
97 };
98 let signature = self.apply(&mut unlock)?;
99 Ok((unlock, signature))
100 }
101}
102
103#[derive(Debug, Default, Args)]
104pub struct OwnershipActivateParams {
105 #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")]
106 pub nonce: Option<u64>,
107 #[arg(long, value_parser = u64::from_str, help="Device Identification Number of the chip")]
108 pub din: Option<u64>,
109 #[arg(
110 long,
111 help = "A path to an external ECDSA signature for the activate request"
112 )]
113 pub signature: Option<PathBuf>,
114 #[arg(long, default_value_t = OwnershipKeyAlg::EcdsaP256, help = "The algorithm used to sign the request")]
115 pub algorithm: OwnershipKeyAlg,
116 #[arg(long, help = "A path to a private ECDSA key to sign the request")]
117 pub ecdsa_key: Option<PathBuf>,
118 #[arg(long, help = "A path to a private SPX key to sign the request")]
119 pub spx_key: Option<PathBuf>,
120}
121
122impl OwnershipActivateParams {
123 pub fn apply(
125 &self,
126 activate: &mut OwnershipActivateRequest,
127 ) -> Result<Option<DetachedSignature>> {
128 if let Some(nonce) = &self.nonce {
129 activate.nonce = *nonce;
130 }
131 if let Some(din) = &self.din {
132 activate.din = *din;
133 }
134 if let Some(signature) = &self.signature {
135 let mut f = File::open(signature)?;
138 activate.signature = EcdsaRawSignature::read(&mut f)?;
139 }
140 if self.ecdsa_key.is_some() || self.spx_key.is_some() {
141 let ecdsa_key = self
142 .ecdsa_key
143 .as_ref()
144 .map(EcdsaPrivateKey::load)
145 .transpose()?;
146 let spx_key = self
147 .spx_key
148 .as_ref()
149 .map(SpxSecretKey::read_pem_file)
150 .transpose()?;
151 let signature =
152 activate.detached_sign(self.algorithm, ecdsa_key.as_ref(), spx_key.as_ref())?;
153 if !self.algorithm.is_detached() {
154 activate.signature = signature.ecdsa.clone().expect("ECDSA signature");
155 }
156 Ok(Some(signature))
157 } else {
158 Ok(None)
159 }
160 }
161
162 pub fn apply_to(
164 &self,
165 reader: Option<&mut impl Read>,
166 ) -> Result<(OwnershipActivateRequest, Option<DetachedSignature>)> {
167 let mut activate = if let Some(r) = reader {
168 let mut data = Vec::new();
169 r.read_to_end(&mut data)?;
170 OwnershipActivateRequest::try_from(data.as_slice())?
171 } else {
172 OwnershipActivateRequest::default()
173 };
174 let signature = self.apply(&mut activate)?;
175 Ok((activate, signature))
176 }
177}