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