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_key = EcdsaRawPublicKey::try_from(&key)?;
55 }
56 if let Some(signature) = &self.signature {
57 let mut f = File::open(signature)?;
60 unlock.signature = EcdsaRawSignature::read(&mut f)?;
61 }
62 if self.ecdsa_key.is_some() || self.spx_key.is_some() {
63 let ecdsa_key = self
64 .ecdsa_key
65 .as_ref()
66 .map(EcdsaPrivateKey::load)
67 .transpose()?;
68 let spx_key = self
69 .spx_key
70 .as_ref()
71 .map(SpxSecretKey::read_pem_file)
72 .transpose()?;
73 let signature =
74 unlock.detached_sign(self.algorithm, ecdsa_key.as_ref(), spx_key.as_ref())?;
75 if !self.algorithm.is_detached() {
76 unlock.signature = signature.ecdsa.clone().expect("ECDSA signature");
77 }
78 Ok(Some(signature))
79 } else {
80 Ok(None)
81 }
82 }
83
84 pub fn apply_to(
86 &self,
87 reader: Option<&mut impl Read>,
88 ) -> Result<(OwnershipUnlockRequest, Option<DetachedSignature>)> {
89 let mut unlock = if let Some(r) = reader {
90 let mut data = Vec::new();
91 r.read_to_end(&mut data)?;
92 OwnershipUnlockRequest::try_from(data.as_slice())?
93 } else {
94 OwnershipUnlockRequest::default()
95 };
96 let signature = self.apply(&mut unlock)?;
97 Ok((unlock, signature))
98 }
99}
100
101#[derive(Debug, Default, Args)]
102pub struct OwnershipActivateParams {
103 #[arg(long, value_parser = u64::from_str, help="Current ROM_EXT nonce")]
104 pub nonce: Option<u64>,
105 #[arg(long, value_parser = u64::from_str, help="Device Identification Number of the chip")]
106 pub din: Option<u64>,
107 #[arg(
108 long,
109 help = "A path to an external ECDSA signature for the activate request"
110 )]
111 pub signature: Option<PathBuf>,
112 #[arg(long, default_value_t = OwnershipKeyAlg::EcdsaP256, help = "The algorithm used to sign the request")]
113 pub algorithm: OwnershipKeyAlg,
114 #[arg(long, help = "A path to a private ECDSA key to sign the request")]
115 pub ecdsa_key: Option<PathBuf>,
116 #[arg(long, help = "A path to a private SPX key to sign the request")]
117 pub spx_key: Option<PathBuf>,
118}
119
120impl OwnershipActivateParams {
121 pub fn apply(
123 &self,
124 activate: &mut OwnershipActivateRequest,
125 ) -> Result<Option<DetachedSignature>> {
126 if let Some(nonce) = &self.nonce {
127 activate.nonce = *nonce;
128 }
129 if let Some(din) = &self.din {
130 activate.din = *din;
131 }
132 if let Some(signature) = &self.signature {
133 let mut f = File::open(signature)?;
136 activate.signature = EcdsaRawSignature::read(&mut f)?;
137 }
138 if self.ecdsa_key.is_some() || self.spx_key.is_some() {
139 let ecdsa_key = self
140 .ecdsa_key
141 .as_ref()
142 .map(EcdsaPrivateKey::load)
143 .transpose()?;
144 let spx_key = self
145 .spx_key
146 .as_ref()
147 .map(SpxSecretKey::read_pem_file)
148 .transpose()?;
149 let signature =
150 activate.detached_sign(self.algorithm, ecdsa_key.as_ref(), spx_key.as_ref())?;
151 if !self.algorithm.is_detached() {
152 activate.signature = signature.ecdsa.clone().expect("ECDSA signature");
153 }
154 Ok(Some(signature))
155 } else {
156 Ok(None)
157 }
158 }
159
160 pub fn apply_to(
162 &self,
163 reader: Option<&mut impl Read>,
164 ) -> Result<(OwnershipActivateRequest, Option<DetachedSignature>)> {
165 let mut activate = if let Some(r) = reader {
166 let mut data = Vec::new();
167 r.read_to_end(&mut data)?;
168 OwnershipActivateRequest::try_from(data.as_slice())?
169 } else {
170 OwnershipActivateRequest::default()
171 };
172 let signature = self.apply(&mut activate)?;
173 Ok((activate, signature))
174 }
175}