1use bytes::Bytes;
41use ndn_packet::tlv_type;
42use ndn_tlv::{TlvReader, TlvWriter};
43
44use crate::file_tpm::{FileTpmError, TpmKeyKind};
45
46const TLV_SAFE_BAG: u64 = 0x80; const TLV_ENCRYPTED_KEY: u64 = 0x81; #[derive(Debug, thiserror::Error)]
52pub enum SafeBagError {
53 #[error("malformed SafeBag TLV: {0}")]
54 Malformed(String),
55 #[error("PKCS#8 encryption error: {0}")]
56 Pkcs8(String),
57 #[error("key conversion error: {0}")]
58 KeyConversion(String),
59 #[error("file tpm error: {0}")]
60 Tpm(#[from] FileTpmError),
61 #[error("unsupported algorithm in SafeBag: {0}")]
62 UnsupportedAlgorithm(String),
63}
64
65#[derive(Clone, Debug)]
68pub struct SafeBag {
69 pub certificate: Bytes,
73 pub encrypted_key: Bytes,
77}
78
79impl SafeBag {
80 pub fn encode(&self) -> Bytes {
84 let mut w = TlvWriter::new();
85 w.write_nested(TLV_SAFE_BAG, |w| {
86 w.write_raw(&self.certificate);
90 w.write_tlv(TLV_ENCRYPTED_KEY, &self.encrypted_key);
91 });
92 w.finish()
93 }
94
95 pub fn decode(wire: &[u8]) -> Result<Self, SafeBagError> {
99 let mut outer = TlvReader::new(Bytes::copy_from_slice(wire));
100 let (typ, body) = outer
101 .read_tlv()
102 .map_err(|e| SafeBagError::Malformed(format!("outer TLV: {e:?}")))?;
103 if typ != TLV_SAFE_BAG {
104 return Err(SafeBagError::Malformed(format!(
105 "expected SafeBag (0x80), got 0x{typ:x}"
106 )));
107 }
108
109 let mut inner = TlvReader::new(body);
115
116 let (cert_type, cert_body) = inner
117 .read_tlv()
118 .map_err(|e| SafeBagError::Malformed(format!("certificate TLV: {e:?}")))?;
119 if cert_type != tlv_type::DATA {
120 return Err(SafeBagError::Malformed(format!(
121 "expected Data (0x06) inside SafeBag, got 0x{cert_type:x}"
122 )));
123 }
124 let mut cert_w = TlvWriter::new();
127 cert_w.write_tlv(tlv_type::DATA, &cert_body);
128 let certificate = cert_w.finish();
129
130 let (ek_type, ek_body) = inner
131 .read_tlv()
132 .map_err(|e| SafeBagError::Malformed(format!("EncryptedKey TLV: {e:?}")))?;
133 if ek_type != TLV_ENCRYPTED_KEY {
134 return Err(SafeBagError::Malformed(format!(
135 "expected EncryptedKey (0x81) inside SafeBag, got 0x{ek_type:x}"
136 )));
137 }
138
139 Ok(Self {
140 certificate,
141 encrypted_key: ek_body,
142 })
143 }
144
145 pub fn encrypt(
152 certificate: Bytes,
153 pkcs8_pki_der: &[u8],
154 password: &[u8],
155 ) -> Result<Self, SafeBagError> {
156 use pkcs8::PrivateKeyInfo;
157 let pki = PrivateKeyInfo::try_from(pkcs8_pki_der)
158 .map_err(|e| SafeBagError::Pkcs8(format!("parse PrivateKeyInfo: {e}")))?;
159 let encrypted = pki
160 .encrypt(rsa::rand_core::OsRng, password)
161 .map_err(|e| SafeBagError::Pkcs8(format!("encrypt: {e}")))?;
162 Ok(Self {
163 certificate,
164 encrypted_key: Bytes::copy_from_slice(encrypted.as_bytes()),
165 })
166 }
167
168 pub fn decrypt_key(&self, password: &[u8]) -> Result<Vec<u8>, SafeBagError> {
172 use pkcs8::EncryptedPrivateKeyInfo;
173 let epki = EncryptedPrivateKeyInfo::try_from(&self.encrypted_key[..])
174 .map_err(|e| SafeBagError::Pkcs8(format!("parse EncryptedPrivateKeyInfo: {e}")))?;
175 let decrypted = epki
176 .decrypt(password)
177 .map_err(|e| SafeBagError::Pkcs8(format!("decrypt: {e}")))?;
178 Ok(decrypted.as_bytes().to_vec())
179 }
180}
181
182pub(crate) fn rsa_pkcs1_to_pkcs8(pkcs1_der: &[u8]) -> Result<Vec<u8>, SafeBagError> {
195 use pkcs1::DecodeRsaPrivateKey;
196 use rsa::RsaPrivateKey;
197 use rsa::pkcs8::EncodePrivateKey;
198 let sk = RsaPrivateKey::from_pkcs1_der(pkcs1_der)
199 .map_err(|e| SafeBagError::KeyConversion(format!("rsa pkcs1 parse: {e}")))?;
200 let pkcs8_doc = sk
201 .to_pkcs8_der()
202 .map_err(|e| SafeBagError::KeyConversion(format!("rsa to pkcs8: {e}")))?;
203 Ok(pkcs8_doc.as_bytes().to_vec())
204}
205
206pub(crate) fn rsa_pkcs8_to_pkcs1(pkcs8_der: &[u8]) -> Result<Vec<u8>, SafeBagError> {
209 use pkcs1::EncodeRsaPrivateKey;
210 use rsa::RsaPrivateKey;
211 use rsa::pkcs8::DecodePrivateKey;
212 let sk = RsaPrivateKey::from_pkcs8_der(pkcs8_der)
213 .map_err(|e| SafeBagError::KeyConversion(format!("rsa pkcs8 parse: {e}")))?;
214 let pkcs1_doc = sk
215 .to_pkcs1_der()
216 .map_err(|e| SafeBagError::KeyConversion(format!("rsa to pkcs1: {e}")))?;
217 Ok(pkcs1_doc.as_bytes().to_vec())
218}
219
220pub(crate) fn ec_sec1_to_pkcs8(sec1_der: &[u8]) -> Result<Vec<u8>, SafeBagError> {
227 use p256_ecdsa::SecretKey;
228 use p256_ecdsa::pkcs8::EncodePrivateKey;
229
230 let scalar = crate::file_tpm::parse_sec1_p256_priv_scalar(sec1_der)?;
231 let secret = SecretKey::from_slice(&scalar)
232 .map_err(|e| SafeBagError::KeyConversion(format!("p256 from scalar: {e}")))?;
233 let pkcs8_doc = secret
234 .to_pkcs8_der()
235 .map_err(|e| SafeBagError::KeyConversion(format!("p256 to pkcs8: {e}")))?;
236 Ok(pkcs8_doc.as_bytes().to_vec())
237}
238
239pub(crate) fn ec_pkcs8_to_sec1(pkcs8_der: &[u8]) -> Result<Vec<u8>, SafeBagError> {
242 use p256_ecdsa::SecretKey;
243 use p256_ecdsa::pkcs8::DecodePrivateKey;
244
245 let secret = SecretKey::from_pkcs8_der(pkcs8_der)
246 .map_err(|e| SafeBagError::KeyConversion(format!("p256 pkcs8 parse: {e}")))?;
247 let sec1_doc = secret
248 .to_sec1_der()
249 .map_err(|e| SafeBagError::KeyConversion(format!("p256 to sec1: {e}")))?;
250 Ok(sec1_doc.as_slice().to_vec())
251}
252
253pub(crate) fn detect_pkcs8_algorithm(pkcs8_der: &[u8]) -> Result<TpmKeyKind, SafeBagError> {
257 use pkcs8::PrivateKeyInfo;
258 let pki = PrivateKeyInfo::try_from(pkcs8_der)
259 .map_err(|e| SafeBagError::Pkcs8(format!("PrivateKeyInfo parse: {e}")))?;
260 let oid = pki.algorithm.oid;
262 if oid.to_string() == "1.2.840.113549.1.1.1" {
263 Ok(TpmKeyKind::Rsa)
264 } else if oid.to_string() == "1.2.840.10045.2.1" {
265 Ok(TpmKeyKind::EcdsaP256)
269 } else if oid.to_string() == "1.3.101.112" {
270 Ok(TpmKeyKind::Ed25519)
272 } else {
273 Err(SafeBagError::UnsupportedAlgorithm(format!(
274 "unknown PKCS#8 algorithm OID {oid}"
275 )))
276 }
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282
283 fn fake_cert(body: &[u8]) -> Bytes {
288 let mut w = TlvWriter::new();
289 w.write_tlv(tlv_type::DATA, body);
290 w.finish()
291 }
292
293 #[test]
294 fn safebag_tlv_roundtrip() {
295 let cert = fake_cert(b"fake certificate body");
296 let sb = SafeBag {
297 certificate: cert.clone(),
298 encrypted_key: Bytes::from_static(b"opaque encrypted key bytes"),
299 };
300 let wire = sb.encode();
301 assert_eq!(wire[0], 0x80);
303 let decoded = SafeBag::decode(&wire).unwrap();
304 assert_eq!(decoded.certificate, cert);
305 assert_eq!(decoded.encrypted_key, sb.encrypted_key);
306 }
307
308 #[test]
309 fn safebag_decode_rejects_wrong_outer_type() {
310 let mut w = TlvWriter::new();
312 w.write_tlv(tlv_type::DATA, b"oops");
313 let wire = w.finish();
314 match SafeBag::decode(&wire) {
315 Err(SafeBagError::Malformed(_)) => {}
316 other => panic!("expected Malformed, got {other:?}"),
317 }
318 }
319
320 #[test]
321 fn pkcs8_encrypt_decrypt_roundtrip_ed25519() {
322 use ed25519_dalek::SigningKey;
325 use ed25519_dalek::pkcs8::EncodePrivateKey;
326 let mut seed = [0u8; 32];
327 ring::rand::SecureRandom::fill(&ring::rand::SystemRandom::new(), &mut seed).unwrap();
328 let sk = SigningKey::from_bytes(&seed);
329 let pkcs8 = sk.to_pkcs8_der().unwrap();
330
331 let cert = fake_cert(b"ed25519 cert");
332 let pw = b"correct horse battery staple";
333
334 let sb = SafeBag::encrypt(cert.clone(), pkcs8.as_bytes(), pw).unwrap();
335 assert!(
337 sb.encrypted_key.windows(32).all(|w| w != seed),
338 "encrypted key leaked the seed"
339 );
340 let decrypted = sb.decrypt_key(pw).unwrap();
341 assert_eq!(&decrypted[..], pkcs8.as_bytes());
344
345 assert!(sb.decrypt_key(b"wrong password").is_err());
347
348 let wire = sb.encode();
350 let sb2 = SafeBag::decode(&wire).unwrap();
351 assert_eq!(sb2.decrypt_key(pw).unwrap(), decrypted);
352 }
353
354 #[test]
355 fn rsa_pkcs1_pkcs8_roundtrip() {
356 use pkcs1::EncodeRsaPrivateKey;
357 use rsa::RsaPrivateKey;
358 let mut rng = rsa::rand_core::OsRng;
361 let sk = RsaPrivateKey::new(&mut rng, 1024).unwrap();
362 let pkcs1 = sk.to_pkcs1_der().unwrap();
363 let pkcs8 = rsa_pkcs1_to_pkcs8(pkcs1.as_bytes()).unwrap();
364 let pkcs1_again = rsa_pkcs8_to_pkcs1(&pkcs8).unwrap();
365 assert_eq!(pkcs1.as_bytes(), pkcs1_again.as_slice());
366 }
367
368 #[test]
369 fn ec_sec1_pkcs8_roundtrip() {
370 use p256_ecdsa::SecretKey;
371 use p256_ecdsa::pkcs8::EncodePrivateKey;
372 let scalar = [
377 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0,
378 0xF0, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9A, 0xAB, 0xBC, 0xCD,
379 0xDE, 0xEF, 0xFE, 0xED,
380 ];
381 let secret = SecretKey::from_slice(&scalar).unwrap();
382 let pkcs8 = secret.to_pkcs8_der().unwrap();
383
384 let sec1 = ec_pkcs8_to_sec1(pkcs8.as_bytes()).unwrap();
386 let pkcs8_again = ec_sec1_to_pkcs8(&sec1).unwrap();
387 assert_eq!(pkcs8.as_bytes(), pkcs8_again.as_slice());
388 }
389
390 #[test]
391 fn detect_pkcs8_algorithm_recognises_each_kind() {
392 {
394 use ed25519_dalek::SigningKey;
395 use ed25519_dalek::pkcs8::EncodePrivateKey;
396 let sk = SigningKey::from_bytes(&[5u8; 32]);
397 let pkcs8 = sk.to_pkcs8_der().unwrap();
398 assert_eq!(
399 detect_pkcs8_algorithm(pkcs8.as_bytes()).unwrap(),
400 TpmKeyKind::Ed25519
401 );
402 }
403 {
405 use rsa::RsaPrivateKey;
406 use rsa::pkcs8::EncodePrivateKey;
407 let mut rng = rsa::rand_core::OsRng;
408 let sk = RsaPrivateKey::new(&mut rng, 1024).unwrap();
409 let pkcs8 = sk.to_pkcs8_der().unwrap();
410 assert_eq!(
411 detect_pkcs8_algorithm(pkcs8.as_bytes()).unwrap(),
412 TpmKeyKind::Rsa
413 );
414 }
415 {
417 use p256_ecdsa::SecretKey;
418 use p256_ecdsa::pkcs8::EncodePrivateKey;
419 let secret = SecretKey::from_slice(&[7u8; 32]).unwrap();
420 let pkcs8 = secret.to_pkcs8_der().unwrap();
421 assert_eq!(
422 detect_pkcs8_algorithm(pkcs8.as_bytes()).unwrap(),
423 TpmKeyKind::EcdsaP256
424 );
425 }
426 }
427}