1use std::io::Read;
4use buffered_reader::BufferedReader;
5use crate::{
6 Result,
7 Error,
8 PublicKeyAlgorithm,
9 SymmetricAlgorithm,
10 HashAlgorithm,
11};
12use crate::types::Curve;
13use crate::crypto::{
14 mem::Protected,
15 mpi::{self, MPI, ProtectedMPI},
16};
17use crate::parse::{
18 PacketHeaderParser,
19 Cookie,
20};
21
22impl mpi::PublicKey {
23 pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
29 {
30 let bio = buffered_reader::Generic::with_cookie(
31 reader, None, Cookie::default());
32 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
33 Self::_parse(algo, &mut php)
34 }
35
36 pub(crate) fn _parse(
42 algo: PublicKeyAlgorithm,
43 php: &mut PacketHeaderParser<'_>)
44 -> Result<Self>
45 {
46 use crate::PublicKeyAlgorithm::*;
47
48 #[allow(deprecated)]
49 match algo {
50 RSAEncryptSign | RSAEncrypt | RSASign => {
51 let n = MPI::parse("rsa_public_n_len", "rsa_public_n", php)?;
52 let e = MPI::parse("rsa_public_e_len", "rsa_public_e", php)?;
53
54 Ok(mpi::PublicKey::RSA { e, n })
55 }
56
57 DSA => {
58 let p = MPI::parse("dsa_public_p_len", "dsa_public_p", php)?;
59 let q = MPI::parse("dsa_public_q_len", "dsa_public_q", php)?;
60 let g = MPI::parse("dsa_public_g_len", "dsa_public_g", php)?;
61 let y = MPI::parse("dsa_public_y_len", "dsa_public_y", php)?;
62
63 Ok(mpi::PublicKey::DSA {
64 p,
65 q,
66 g,
67 y,
68 })
69 }
70
71 ElGamalEncrypt | ElGamalEncryptSign => {
72 let p = MPI::parse("elgamal_public_p_len", "elgamal_public_p",
73 php)?;
74 let g = MPI::parse("elgamal_public_g_len", "elgamal_public_g",
75 php)?;
76 let y = MPI::parse("elgamal_public_y_len", "elgamal_public_y",
77 php)?;
78
79 Ok(mpi::PublicKey::ElGamal {
80 p,
81 g,
82 y,
83 })
84 }
85
86 EdDSA => {
87 let curve_len = php.parse_u8("curve_len")? as usize;
88 let curve = php.parse_bytes("curve", curve_len)?;
89 let q = MPI::parse("eddsa_public_len", "eddsa_public", php)?;
90
91 Ok(mpi::PublicKey::EdDSA {
92 curve: Curve::from_oid(&curve),
93 q
94 })
95 }
96
97 ECDSA => {
98 let curve_len = php.parse_u8("curve_len")? as usize;
99 let curve = php.parse_bytes("curve", curve_len)?;
100 let q = MPI::parse("ecdsa_public_len", "ecdsa_public", php)?;
101
102 Ok(mpi::PublicKey::ECDSA {
103 curve: Curve::from_oid(&curve),
104 q
105 })
106 }
107
108 ECDH => {
109 let curve_len = php.parse_u8("curve_len")? as usize;
110 let curve = php.parse_bytes("curve", curve_len)?;
111 let q = MPI::parse("ecdh_public_len", "ecdh_public", php)?;
112 let kdf_len = php.parse_u8("kdf_len")?;
113
114 if kdf_len != 3 {
115 return Err(Error::MalformedPacket(
116 "wrong kdf length".into()).into());
117 }
118
119 let reserved = php.parse_u8("kdf_reserved")?;
120 if reserved != 1 {
121 return Err(Error::MalformedPacket(
122 format!("Reserved kdf field must be 0x01, \
123 got 0x{:x}", reserved)).into());
124 }
125 let hash: HashAlgorithm = php.parse_u8("kdf_hash")?.into();
126 let sym: SymmetricAlgorithm = php.parse_u8("kek_symm")?.into();
127
128 Ok(mpi::PublicKey::ECDH {
129 curve: Curve::from_oid(&curve),
130 q,
131 hash,
132 sym
133 })
134 }
135
136 X25519 => {
137 let mut u = [0; 32];
138 php.parse_bytes_into("x25519_public", &mut u)?;
139 Ok(mpi::PublicKey::X25519 { u })
140 },
141
142 X448 => {
143 let mut u = [0; 56];
144 php.parse_bytes_into("x448_public", &mut u)?;
145 Ok(mpi::PublicKey::X448 { u: Box::new(u) })
146 },
147
148 Ed25519 => {
149 let mut a = [0; 32];
150 php.parse_bytes_into("ed25519_public", &mut a)?;
151 Ok(mpi::PublicKey::Ed25519 { a })
152 },
153
154 Ed448 => {
155 let mut a = [0; 57];
156 php.parse_bytes_into("ed448_public", &mut a)?;
157 Ok(mpi::PublicKey::Ed448 { a: Box::new(a) })
158 },
159
160 Unknown(_) | Private(_) => {
161 let mut mpis = Vec::new();
162 while let Ok(mpi) = MPI::parse("unknown_len",
163 "unknown", php) {
164 mpis.push(mpi);
165 }
166 let rest = php.parse_bytes_eof("rest")?;
167
168 Ok(mpi::PublicKey::Unknown {
169 mpis: mpis.into_boxed_slice(),
170 rest: rest.into_boxed_slice(),
171 })
172 }
173 }
174 }
175}
176
177impl mpi::SecretKeyMaterial {
178 #[deprecated(
182 since = "1.14.0",
183 note = "Leaks secrets into the heap, use [`SecretKeyMaterial::from_bytes_with_checksum`]")]
184 pub fn parse_with_checksum<R: Read + Send + Sync>(algo: PublicKeyAlgorithm,
185 reader: R,
186 checksum: mpi::SecretKeyChecksum)
187 -> Result<Self> {
188 let bio = buffered_reader::Generic::with_cookie(
189 reader, None, Cookie::default());
190 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
191 Self::_parse(algo, &mut php, Some(checksum))
192 }
193
194 pub fn from_bytes_with_checksum(algo: PublicKeyAlgorithm,
198 bytes: &[u8],
199 checksum: mpi::SecretKeyChecksum)
200 -> Result<Self> {
201 let bio = buffered_reader::Memory::with_cookie(
202 bytes, Cookie::default());
203 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
204 Self::_parse(algo, &mut php, Some(checksum))
205 }
206
207 #[deprecated(
213 since = "1.14.0",
214 note = "Leaks secrets into the heap, use [`SecretKeyMaterial::from_bytes`]")]
215 pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
216 {
217 let bio = buffered_reader::Generic::with_cookie(
218 reader, None, Cookie::default());
219 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
220 Self::_parse(algo, &mut php, None)
221 }
222
223 pub fn from_bytes(algo: PublicKeyAlgorithm, buf: &[u8]) -> Result<Self> {
229 let bio = buffered_reader::Memory::with_cookie(
230 buf, Cookie::default());
231 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
232 Self::_parse(algo, &mut php, None)
233 }
234
235 pub(crate) fn _parse(
241 algo: PublicKeyAlgorithm,
242 php: &mut PacketHeaderParser<'_>,
243 checksum: Option<mpi::SecretKeyChecksum>,
244 )
245 -> Result<Self>
246 {
247 use crate::PublicKeyAlgorithm::*;
248
249 let mpis_start = php.reader.total_out();
253
254 #[allow(deprecated)]
255 let mpis: Result<Self> = match algo {
256 RSAEncryptSign | RSAEncrypt | RSASign => {
257 Ok(mpi::SecretKeyMaterial::RSA {
258 d: ProtectedMPI::parse(
259 "rsa_secret_d_len", "rsa_secret_d", php)?,
260 p: ProtectedMPI::parse(
261 "rsa_secret_p_len", "rsa_secret_p", php)?,
262 q: ProtectedMPI::parse(
263 "rsa_secret_q_len", "rsa_secret_q", php)?,
264 u: ProtectedMPI::parse(
265 "rsa_secret_u_len", "rsa_secret_u", php)?,
266 })
267 }
268
269 DSA => {
270 Ok(mpi::SecretKeyMaterial::DSA {
271 x: ProtectedMPI::parse(
272 "dsa_secret_len", "dsa_secret", php)?,
273 })
274 }
275
276 ElGamalEncrypt | ElGamalEncryptSign => {
277 Ok(mpi::SecretKeyMaterial::ElGamal {
278 x: ProtectedMPI::parse(
279 "elgamal_secret_len", "elgamal_secret", php)?,
280 })
281 }
282
283 EdDSA => {
284 Ok(mpi::SecretKeyMaterial::EdDSA {
285 scalar: ProtectedMPI::parse(
286 "eddsa_secret_len", "eddsa_secret", php)?,
287 })
288 }
289
290 ECDSA => {
291 Ok(mpi::SecretKeyMaterial::ECDSA {
292 scalar: ProtectedMPI::parse(
293 "ecdsa_secret_len", "ecdsa_secret", php)?,
294 })
295 }
296
297 ECDH => {
298 Ok(mpi::SecretKeyMaterial::ECDH {
299 scalar: ProtectedMPI::parse(
300 "ecdh_secret_len", "ecdh_secret", php)?,
301 })
302 }
303
304 X25519 => {
305 let mut x: Protected = vec![0; 32].into();
306 php.parse_bytes_into("x25519_secret", &mut x)?;
307 Ok(mpi::SecretKeyMaterial::X25519 { x })
308 },
309
310 X448 => {
311 let mut x: Protected = vec![0; 56].into();
312 php.parse_bytes_into("x448_secret", &mut x)?;
313 Ok(mpi::SecretKeyMaterial::X448 { x })
314 },
315
316 Ed25519 => {
317 let mut x: Protected = vec![0; 32].into();
318 php.parse_bytes_into("ed25519_secret", &mut x)?;
319 Ok(mpi::SecretKeyMaterial::Ed25519 { x })
320 },
321
322 Ed448 => {
323 let mut x: Protected = vec![0; 57].into();
324 php.parse_bytes_into("ed448_secret", &mut x)?;
325 Ok(mpi::SecretKeyMaterial::Ed448 { x })
326 },
327
328 Unknown(_) | Private(_) => {
329 let mut mpis = Vec::new();
330 while let Ok(mpi) = ProtectedMPI::parse("unknown_len",
331 "unknown", php) {
332 mpis.push(mpi);
333 }
334 let rest = php.parse_bytes_eof("rest")?;
335
336 Ok(mpi::SecretKeyMaterial::Unknown {
337 mpis: mpis.into_boxed_slice(),
338 rest: rest.into(),
339 })
340 }
341 };
342 let mpis = mpis?;
343
344 if let Some(checksum) = checksum {
345 let mpis_len = php.reader.total_out() - mpis_start;
350
351 let their_chksum = php.parse_bytes("checksum", checksum.len())?;
356
357 let total_out = php.reader.total_out();
359
360 php.reader.rewind();
362 php.reader.consume(mpis_start);
363 let data = &php.reader.data_consume_hard(mpis_len)?[..mpis_len];
364
365 let good = match checksum {
366 mpi::SecretKeyChecksum::SHA1 => {
367 let mut hsh = HashAlgorithm::SHA1.context().unwrap()
369 .for_digest();
370 hsh.update(data);
371 let mut our_chksum = [0u8; 20];
372 let _ = hsh.digest(&mut our_chksum);
373
374 our_chksum == their_chksum[..]
375 },
376
377 mpi::SecretKeyChecksum::Sum16 => {
378 let our_chksum = data.iter()
380 .fold(0u16, |acc, v| acc.wrapping_add(*v as u16))
381 .to_be_bytes();
382
383 our_chksum == their_chksum[..]
384 },
385 };
386
387 php.reader.consume(checksum.len());
390
391 debug_assert_eq!(total_out, php.reader.total_out());
393
394 if good {
395 Ok(mpis)
396 } else {
397 Err(Error::MalformedMPI("checksum wrong".to_string()).into())
398 }
399 } else {
400 Ok(mpis)
401 }
402 }
403}
404
405impl mpi::Ciphertext {
406 pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
413 {
414 let bio = buffered_reader::Generic::with_cookie(
415 reader, None, Cookie::default());
416 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
417 Self::_parse(algo, &mut php)
418 }
419
420 pub(crate) fn _parse(
427 algo: PublicKeyAlgorithm,
428 php: &mut PacketHeaderParser<'_>)
429 -> Result<Self> {
430 use crate::PublicKeyAlgorithm::*;
431
432 #[allow(deprecated)]
433 match algo {
434 RSAEncryptSign | RSAEncrypt => {
435 let c = MPI::parse("rsa_ciphertxt_len", "rsa_ciphertxt",
436 php)?;
437
438 Ok(mpi::Ciphertext::RSA {
439 c,
440 })
441 }
442
443 ElGamalEncrypt | ElGamalEncryptSign => {
444 let e = MPI::parse("elgamal_e_len", "elgamal_e", php)?;
445 let c = MPI::parse("elgamal_c_len", "elgamal_c", php)?;
446
447 Ok(mpi::Ciphertext::ElGamal {
448 e,
449 c,
450 })
451 }
452
453 ECDH => {
454 let e = MPI::parse("ecdh_e_len", "ecdh_e", php)?;
455 let key_len = php.parse_u8("ecdh_esk_len")? as usize;
456 let key = Vec::from(&php.parse_bytes("ecdh_esk", key_len)?
457 [..key_len]);
458
459 Ok(mpi::Ciphertext::ECDH {
460 e, key: key.into_boxed_slice()
461 })
462 }
463
464 X25519 => {
465 let mut e = [0; 32];
466 php.parse_bytes_into("x25519_e", &mut e)?;
467 let key_len = php.parse_u8("x25519_esk_len")? as usize;
468 let key = Vec::from(&php.parse_bytes("x25519_esk", key_len)?
469 [..key_len]);
470 Ok(mpi::Ciphertext::X25519 { e: Box::new(e), key: key.into() })
471 },
472
473 X448 => {
474 let mut e = [0; 56];
475 php.parse_bytes_into("x448_e", &mut e)?;
476 let key_len = php.parse_u8("x448_esk_len")? as usize;
477 let key = Vec::from(&php.parse_bytes("x448_esk", key_len)?
478 [..key_len]);
479 Ok(mpi::Ciphertext::X448 { e: Box::new(e), key: key.into() })
480 },
481
482 Unknown(_) | Private(_) => {
483 let mut mpis = Vec::new();
484 while let Ok(mpi) = MPI::parse("unknown_len",
485 "unknown", php) {
486 mpis.push(mpi);
487 }
488 let rest = php.parse_bytes_eof("rest")?;
489
490 Ok(mpi::Ciphertext::Unknown {
491 mpis: mpis.into_boxed_slice(),
492 rest: rest.into_boxed_slice(),
493 })
494 }
495
496 RSASign | DSA | EdDSA | ECDSA | Ed25519 | Ed448
497 => Err(Error::InvalidArgument(
498 format!("not an encryption algorithm: {:?}", algo)).into()),
499 }
500 }
501}
502
503impl mpi::Signature {
504 pub fn parse<R: Read + Send + Sync>(algo: PublicKeyAlgorithm, reader: R) -> Result<Self>
511 {
512 let bio = buffered_reader::Generic::with_cookie(
513 reader, None, Cookie::default());
514 let mut php = PacketHeaderParser::new_naked(bio.into_boxed());
515 Self::_parse(algo, &mut php)
516 }
517
518 pub(crate) fn _parse(
525 algo: PublicKeyAlgorithm,
526 php: &mut PacketHeaderParser<'_>)
527 -> Result<Self> {
528 use crate::PublicKeyAlgorithm::*;
529
530 #[allow(deprecated)]
531 match algo {
532 RSAEncryptSign | RSASign => {
533 let s = MPI::parse("rsa_signature_len", "rsa_signature", php)?;
534
535 Ok(mpi::Signature::RSA {
536 s,
537 })
538 }
539
540 DSA => {
541 let r = MPI::parse("dsa_sig_r_len", "dsa_sig_r",
542 php)?;
543 let s = MPI::parse("dsa_sig_s_len", "dsa_sig_s",
544 php)?;
545
546 Ok(mpi::Signature::DSA {
547 r,
548 s,
549 })
550 }
551
552 ElGamalEncryptSign => {
553 let r = MPI::parse("elgamal_sig_r_len",
554 "elgamal_sig_r", php)?;
555 let s = MPI::parse("elgamal_sig_s_len",
556 "elgamal_sig_s", php)?;
557
558 Ok(mpi::Signature::ElGamal {
559 r,
560 s,
561 })
562 }
563
564 EdDSA => {
565 let r = MPI::parse("eddsa_sig_r_len", "eddsa_sig_r",
566 php)?;
567 let s = MPI::parse("eddsa_sig_s_len", "eddsa_sig_s",
568 php)?;
569
570 Ok(mpi::Signature::EdDSA {
571 r,
572 s,
573 })
574 }
575
576 ECDSA => {
577 let r = MPI::parse("ecdsa_sig_r_len", "ecdsa_sig_r",
578 php)?;
579 let s = MPI::parse("ecdsa_sig_s_len", "ecdsa_sig_s",
580 php)?;
581
582 Ok(mpi::Signature::ECDSA {
583 r,
584 s,
585 })
586 }
587
588 Ed25519 => {
589 let mut s = [0; 64];
590 php.parse_bytes_into("ed25519_sig", &mut s)?;
591 Ok(mpi::Signature::Ed25519 { s: Box::new(s) })
592 },
593
594 Ed448 => {
595 let mut s = [0; 114];
596 php.parse_bytes_into("ed448_sig", &mut s)?;
597 Ok(mpi::Signature::Ed448 { s: Box::new(s) })
598 },
599
600 Unknown(_) | Private(_) => {
601 let mut mpis = Vec::new();
602 while let Ok(mpi) = MPI::parse("unknown_len",
603 "unknown", php) {
604 mpis.push(mpi);
605 }
606 let rest = php.parse_bytes_eof("rest")?;
607
608 Ok(mpi::Signature::Unknown {
609 mpis: mpis.into_boxed_slice(),
610 rest: rest.into_boxed_slice(),
611 })
612 }
613
614 RSAEncrypt | ElGamalEncrypt | ECDH | X25519 | X448
615 => Err(Error::InvalidArgument(
616 format!("not a signature algorithm: {:?}", algo)).into()),
617 }
618 }
619}
620
621#[test]
622fn mpis_parse_test() {
623 use std::io::Cursor;
624 use super::Parse;
625 use crate::PublicKeyAlgorithm::*;
626 use crate::serialize::MarshalInto;
627
628 {
630 let buf = Cursor::new("\x00\x01\x01\x00\x02\x02");
631 let mpis = mpi::PublicKey::parse(RSAEncryptSign, buf).unwrap();
632
633 match &mpis {
635 &mpi::PublicKey::RSA{ ref n, ref e } => {
636 assert_eq!(n.bits(), 1);
637 assert_eq!(n.value()[0], 1);
638 assert_eq!(n.value().len(), 1);
639 assert_eq!(e.bits(), 2);
640 assert_eq!(e.value()[0], 2);
641 assert_eq!(e.value().len(), 1);
642 }
643
644 _ => assert!(false),
645 }
646 }
647
648 {
650 let buf = Cursor::new("\x00\x02\x02");
651 let mpis = mpi::Ciphertext::parse(RSAEncryptSign, buf).unwrap();
652
653 assert_eq!(mpis.serialized_len(), 3);
654 }
655
656 let mpi = MPI::from_bytes(b"\x00\x09\x01\xff").unwrap();
658 assert_eq!(mpi.value().len(), 2);
659 assert_eq!(mpi.bits(), 9);
660 assert_eq!(mpi.value()[0], 1);
661 assert_eq!(mpi.value()[1], 0xff);
662
663 assert!(MPI::from_bytes(b"\x00\x02\x01").is_err());
666}