1use serde::{Deserialize, Serialize};
32use tsumiki::decoder::{DecodableFrom, Decoder};
33use tsumiki_asn1::{ASN1Object, Element};
34use tsumiki_der::Der;
35use tsumiki_pem::{Label, Pem, ToPem};
36use tsumiki_pkix_types::algorithm::AlgorithmIdentifier;
37
38use crate::error::{Error, Result};
39use crate::pkcs1::RSAPrivateKey;
40use crate::pkcs8::{OID_ED448, OID_ED25519, OneAsymmetricKey};
41use crate::sec1::ECPrivateKey;
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
47#[non_exhaustive]
48pub enum KeyAlgorithm {
49 Rsa,
51 Ec,
53 Ed25519,
55 Ed448,
57 Unknown,
59}
60
61impl KeyAlgorithm {
62 #[must_use]
64 pub fn oid(&self) -> Option<&'static str> {
65 match self {
66 KeyAlgorithm::Rsa => Some(AlgorithmIdentifier::OID_RSA_ENCRYPTION),
67 KeyAlgorithm::Ec => Some(AlgorithmIdentifier::OID_EC_PUBLIC_KEY),
68 KeyAlgorithm::Ed25519 => Some(OID_ED25519),
69 KeyAlgorithm::Ed448 => Some(OID_ED448),
70 KeyAlgorithm::Unknown => None,
71 }
72 }
73
74 #[must_use]
76 pub fn name(&self) -> &'static str {
77 match self {
78 KeyAlgorithm::Rsa => "RSA",
79 KeyAlgorithm::Ec => "EC",
80 KeyAlgorithm::Ed25519 => "Ed25519",
81 KeyAlgorithm::Ed448 => "Ed448",
82 KeyAlgorithm::Unknown => "Unknown",
83 }
84 }
85}
86
87impl std::fmt::Display for KeyAlgorithm {
88 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
89 write!(f, "{}", self.name())
90 }
91}
92
93pub trait PrivateKeyExt {
123 fn key_size(&self) -> u32;
148
149 fn algorithm(&self) -> KeyAlgorithm;
170
171 fn public_key_bytes(&self) -> Option<&[u8]>;
198
199 fn public_key(&self) -> Option<crate::PublicKey>;
238}
239
240#[derive(Debug, Clone)]
246pub enum PrivateKey {
247 Pkcs1(RSAPrivateKey),
249 Sec1(ECPrivateKey),
251 Pkcs8(OneAsymmetricKey),
253}
254
255impl PrivateKey {
256 pub fn from_der(bytes: &[u8]) -> Result<Self> {
267 let der: Der = bytes.to_vec().decode()?;
268 let asn1_obj: ASN1Object = der.decode()?;
269
270 let element = asn1_obj.elements().first().ok_or(Error::EmptyAsn1Object)?;
271
272 element.decode()
273 }
274
275 pub fn key_size(&self) -> u32 {
279 <Self as PrivateKeyExt>::key_size(self)
280 }
281
282 pub fn algorithm(&self) -> KeyAlgorithm {
286 <Self as PrivateKeyExt>::algorithm(self)
287 }
288
289 pub fn public_key_bytes(&self) -> Option<&[u8]> {
293 <Self as PrivateKeyExt>::public_key_bytes(self)
294 }
295
296 pub fn public_key(&self) -> Option<crate::PublicKey> {
300 <Self as PrivateKeyExt>::public_key(self)
301 }
302
303 pub fn is_pkcs1(&self) -> bool {
305 matches!(self, PrivateKey::Pkcs1(_))
306 }
307
308 pub fn is_sec1(&self) -> bool {
310 matches!(self, PrivateKey::Sec1(_))
311 }
312
313 pub fn is_pkcs8(&self) -> bool {
315 matches!(self, PrivateKey::Pkcs8(_))
316 }
317
318 pub fn as_pkcs1(&self) -> Option<&RSAPrivateKey> {
320 match self {
321 PrivateKey::Pkcs1(key) => Some(key),
322 _ => None,
323 }
324 }
325
326 pub fn as_sec1(&self) -> Option<&ECPrivateKey> {
328 match self {
329 PrivateKey::Sec1(key) => Some(key),
330 _ => None,
331 }
332 }
333
334 pub fn as_pkcs8(&self) -> Option<&OneAsymmetricKey> {
336 match self {
337 PrivateKey::Pkcs8(key) => Some(key),
338 _ => None,
339 }
340 }
341
342 pub fn into_pkcs1(self) -> Option<RSAPrivateKey> {
344 match self {
345 PrivateKey::Pkcs1(key) => Some(key),
346 _ => None,
347 }
348 }
349
350 pub fn into_sec1(self) -> Option<ECPrivateKey> {
352 match self {
353 PrivateKey::Sec1(key) => Some(key),
354 _ => None,
355 }
356 }
357
358 pub fn into_pkcs8(self) -> Option<OneAsymmetricKey> {
360 match self {
361 PrivateKey::Pkcs8(key) => Some(key),
362 _ => None,
363 }
364 }
365}
366
367impl DecodableFrom<Element> for PrivateKey {}
369
370impl Decoder<Element, PrivateKey> for Element {
371 type Error = Error;
372
373 fn decode(&self) -> Result<PrivateKey> {
380 let pkcs8_err = match self.decode() {
382 Ok(key) => return Ok(PrivateKey::Pkcs8(key)),
383 Err(e) => e,
384 };
385
386 let sec1_err = match self.decode() {
388 Ok(key) => return Ok(PrivateKey::Sec1(key)),
389 Err(e) => e,
390 };
391
392 let pkcs1_err = match self.decode() {
394 Ok(key) => return Ok(PrivateKey::Pkcs1(key)),
395 Err(e) => e,
396 };
397
398 Err(Error::UnrecognizedPrivateKeyFormat {
399 pkcs8: Box::new(pkcs8_err),
400 sec1: Box::new(sec1_err),
401 pkcs1: Box::new(pkcs1_err),
402 })
403 }
404}
405
406impl DecodableFrom<Pem> for PrivateKey {}
408
409impl Decoder<Pem, PrivateKey> for Pem {
410 type Error = Error;
411
412 fn decode(&self) -> Result<PrivateKey> {
413 match self.label() {
415 Label::RSAPrivateKey => Ok(PrivateKey::Pkcs1(self.decode()?)),
416 Label::ECPrivateKey => Ok(PrivateKey::Sec1(self.decode()?)),
417 Label::PrivateKey => Ok(PrivateKey::Pkcs8(self.decode()?)),
418 _ => {
419 let der: Der = self.decode()?;
421 let asn1_obj: ASN1Object = der.decode()?;
422
423 let element = asn1_obj.elements().first().ok_or(Error::EmptyAsn1Object)?;
424
425 element.decode()
426 }
427 }
428 }
429}
430
431impl From<RSAPrivateKey> for PrivateKey {
432 fn from(key: RSAPrivateKey) -> Self {
433 PrivateKey::Pkcs1(key)
434 }
435}
436
437impl From<ECPrivateKey> for PrivateKey {
438 fn from(key: ECPrivateKey) -> Self {
439 PrivateKey::Sec1(key)
440 }
441}
442
443impl From<OneAsymmetricKey> for PrivateKey {
444 fn from(key: OneAsymmetricKey) -> Self {
445 PrivateKey::Pkcs8(key)
446 }
447}
448
449impl ToPem for PrivateKey {
450 type Error = Error;
451
452 fn pem_label(&self) -> Label {
453 match self {
454 PrivateKey::Pkcs1(_) => Label::RSAPrivateKey,
455 PrivateKey::Sec1(_) => Label::ECPrivateKey,
456 PrivateKey::Pkcs8(_) => Label::PrivateKey,
457 }
458 }
459
460 fn to_pem(&self) -> Result<Pem> {
461 match self {
462 PrivateKey::Pkcs1(key) => key.to_pem().map_err(Error::from),
463 PrivateKey::Sec1(key) => key.to_pem().map_err(Error::from),
464 PrivateKey::Pkcs8(key) => key.to_pem().map_err(Error::from),
465 }
466 }
467}
468
469impl PrivateKeyExt for PrivateKey {
470 fn key_size(&self) -> u32 {
471 match self {
472 PrivateKey::Pkcs1(key) => key.key_size(),
473 PrivateKey::Sec1(key) => key.key_size(),
474 PrivateKey::Pkcs8(key) => key.key_size(),
475 }
476 }
477
478 fn algorithm(&self) -> KeyAlgorithm {
479 match self {
480 PrivateKey::Pkcs1(key) => key.algorithm(),
481 PrivateKey::Sec1(key) => key.algorithm(),
482 PrivateKey::Pkcs8(key) => key.algorithm(),
483 }
484 }
485
486 fn public_key_bytes(&self) -> Option<&[u8]> {
487 match self {
488 PrivateKey::Pkcs1(key) => key.public_key_bytes(),
489 PrivateKey::Sec1(key) => key.public_key_bytes(),
490 PrivateKey::Pkcs8(key) => key.public_key_bytes(),
491 }
492 }
493
494 fn public_key(&self) -> Option<crate::PublicKey> {
495 match self {
496 PrivateKey::Pkcs1(key) => PrivateKeyExt::public_key(key),
497 PrivateKey::Sec1(key) => PrivateKeyExt::public_key(key),
498 PrivateKey::Pkcs8(key) => PrivateKeyExt::public_key(key),
499 }
500 }
501}
502
503#[cfg(test)]
504mod tests {
505 use super::*;
506 use rstest::rstest;
507 use std::str::FromStr;
508
509 const RSA_2048_PKCS1: &str = r#"-----BEGIN RSA PRIVATE KEY-----
510MIIEpAIBAAKCAQEAvf4anqhlMYhVhpOv8XK/ygPFUxkNa8Rh9NNTVlqiWuPgD4Lj
5117YCsa31kQwYgOKADsG5ROApHSjKsWrKQ70DSpxZmPiO8j7jFQdUJLbe/hfiFskoM
512Ur+V5imxrkJB5cnBgIw49ykn0mVtyLRG9RS8Xv+XqNEHFnugS7z2cFQqKYI8oq2L
513yLxSbMzDlzkB1p64u5p6Gy0W3KQZt42/sompo+swMslw+XN2rSNFfUWfJWGdEFJc
514Sl+9oOz7y9ZGv56uC3VdGnU9u6MmC3iMZ/Vf9qQIHOr6KE6IaJNvHPSAET7qnBWJ
515q+x0UrsMJmGdkjGvE3MgIjgaLxjgn/sfO1++vwIDAQABAoIBAEp5BUQ1q9zbnPKw
516h2H0Yds02S82fb1FcERAZcVOp59K/XP3EZLyQiOsNhXTm+O2TVvmEi4OUV1zOX4f
517ypIN7cSTEia/aVVIzwF8GSnzgb5o6Tc2sVfqQz7CDyTIUf5ZtGDIFjhDyJk/KuZm
518S/4bT69JLtB8hvO4J+AoRM1JIHG+Lpe1p+Vsudk3+/AKiyx4tU1Z/zR3Rm9GxUd0
519XHZAUhnYumrczJeq9XS9ufvgJUZ0q+qdAuG4PL4+0KAblS+biad0mv32ibkGsiXt
520CvcZwIMlzQvt+Ai6Oa9GK6lfgrpYYKwZry6pnzI4/j6db4fnWXcNnkHDir7YjsZK
5218QTlfOkCgYEA8cilQsTcF2GRC4CMwGpz/7rZAgjLn7ucscqVhzQIFrZNpMtq2LEL
522/QNMa7dayDryr2b4RAcA2ns5WCRRCSslpVcXwrPDyxzhKdmnCTbu8nLTwtuRYzMU
523s/Oeex7o37aKwpiNQzfqqGTZy0xMulma//M6mX5D14bN4oVt43zx25UCgYEAySnk
524afMoZaLoW3rzDqiq8G3+M8tnFjhs7/r8Bz1BUuOfMjfK8ZFYWLseC8DaiOGLdJl8
5254P98R81xZp4KlYMqbLeIM1f/uo3um7a8AiD2ueuW8qe2xB+5vbiNpJU/fruOU+Bk
526FAZmaIGk8DdUom7SPktKTREYwiZ4o0BF/On2fAMCgYEAietymcvB4HR/UJhbsccH
527tHDZKRfrT4qtr51n/l/n3UzQrZh7snAL7p/bD/bfiihWF0gdhnCYRAjWhTjyINDE
528ALTVkPMKVOp8ZmsJpW/4jcSClzy4imWxAZWOaZ0QKczvCmIK8rUK3lPpCNbVTdef
529WzFb1AL6oA79kqGaNZIoRKECgYA2HVzi25S8cqyLH3IPOXRypURC7q7WnWtAy4XM
5309L+D6tPCkJu5jF310LBufPzM4c/AGCIt7MykDDI7Zrx2KAjboiuzlDKpHtFXdjrx
531X6i/rw62TEOwUtCGpwUDh1rDXvUUv0Js2KPn7ShPrrLH14QbWems/bJpWCwPzpSF
532SvMRvQKBgQDUNNVtpsS/4GwAmKwmLaHrbCn8oBlWBjpSS8NGbyQfA9ErllMLz3OO
533s2qerzz5oOlJm54dGAWRm1e7wTqUdeVOmCCceEvztVUsPfjPUgk7x4pfiFVUaltS
534t1uLx7BFNLk8mjqiaognIGpAlEtRJi+LPZQmIOzmPd0eZKAHNozgwQ==
535-----END RSA PRIVATE KEY-----"#;
536
537 const EC_P256_SEC1: &str = r#"-----BEGIN EC PRIVATE KEY-----
539MHcCAQEEIIfdTjEBvN2/AupnhPeL8585jLgieLQmi4SfX/FVrTxZoAoGCCqGSM49
540AwEHoUQDQgAEmvfw1VdwIlsJHfbHLhHXrO3Wq/0LBCduo6Nb96AiLGUxkn/OWt1I
5419STYYNw8e/Xuzsy9j5joSxQDwmCWSGPGWw==
542-----END EC PRIVATE KEY-----"#;
543
544 const RSA_2048_PKCS8: &str = r#"-----BEGIN PRIVATE KEY-----
545MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDmv7EEQO9B/tSS
546jlFB5L79XppctPwwSfjTb5QzvemWzHkG4PZG79WkNMj8UPcrixTIkZpf32y5WEGX
547QXArkFRUmboasfRQaleLEPeOPCBibIrZkGXokhidm4A8ZeqU92rkwMYC5C8+4Pdd
5484Kpzm/R7+IYXXXu9u1BVSg95z5RPSzcPTx0BDhgPZC7fIwkZwJmicv8zaIXKBddI
549Jm8YLrmjAwxft21NxcrSbCT8DWVHX+75xye6IGAsTt2fBn05BiYnjkK6ZwBwccdo
55030fmtmfcFsC8xOIXPNxOQPcLnFWZZcMkQLCHUybd2+mOFEWsghHYlQ6LyAo/66FV
551He+lH4mjAgMBAAECggEADLiSrLZbulqvI2k/J4/Ry6wUfHnp0UuysQ1csUGOCCc7
552oNp0GVMNhyD115srFTZ0rd4BEboCh3FLJGiSI4SwcX2MGf6nhmtmah9EVo4QBv0O
5535pGkXJ75Rm8VMb84oH/HX9cU04H67M+AM6e4HemCH/eChPU9ZidWdW1AzylXdsuG
5546gySsjkd47zDeNDVhK5fBfH7kzogNlh9RdzDmkrpYm5F4hkgus8xWKpPUBpdquSh
555/dBF5OW8gEuA6kYASzIcAYZK2TZuQHHGRpJkBkwbte61BwWZEGodYiXYESWNHfPA
5561UkwQdf0zzMO0BHynmkGsoBElvtWbmT6sqwLr/vH0QKBgQD9iXwBBdN0z+1T3Jy2
557UlYwET/yPZzmkFnHxkpZi5/jBxK5nCJO6wNXcEJfYtlDDO8mleJkAPfy06AEL1YQ
558T5Df/4PnSmLNUYz4QO6qLxj9pvuOfAyPqSxKmjrvqyJGHw79N50DPh80Pap5bJ1v
559XmB8iwS/jVbwphxKm3h4cNywqwKBgQDo/YkVaAFOzH2kjU72NJyHKYmrcs4kQg3e
560KsanJw6K1zKxQjM1fTGuswiK1IhBUL0aICMjS4AL/TVjemTspmaFmQiPMmxlFR0o
561sUfwNwDS/91Fi22QSSLvWvFAxTBsVVyZNkGlRuuhD3H8fGNx4MF+8jvXuhJWV75l
56215DAHLQ66QKBgQCPqSqhrbpu0y7IORZ3XNpHbE7OpUjVgG/O+jXA3ZPgYW6jy6vJ
563CfOfxRVm1S0EiDyuoXlhbwcQCgf+tw/OODeAJVmJYiXv70iwlqJlvkAr4kViLDo1
5644Qce0puYmGDYWNr2cl++qaGmyVZibUAcDd8gUumC3MSpoYYgZE3z+Qej9wKBgEuo
5652XVMGvCd00c2ZCfrmdECmiRE2dBIavx0Y6IwOra3f0y0tLBwAUw781AyCDU9pMrx
566GLgDcodyKH4vZsq6lpxXv8HQnAaPPrLSLwxAsFHUqORGjMPIHEIiBCoGXt0vMyzF
567w7eKOkZJH7jgI+L9G5i/zNMXJ5FGWRv1Tpo0OArRAoGBAOlRIE7hsCpEUtpbRMIl
568B26vMthQdq8njgnpL9bubV82MXcTqzxe6mwHezLMEB0BYmb+lX5ktZOonqOgQWsj
569rLdkb1HDq7D30YEoDvwfuTAoewGO/QBf+jXMHWx5TRUopcU/61bCI4D1zp/urrXo
570JAOJrxibNzk6iWT9+VFcxO3m
571-----END PRIVATE KEY-----"#;
572
573 #[rstest]
574 #[case(RSA_2048_PKCS1, true, false, false, Some(2048))]
575 #[case(EC_P256_SEC1, false, true, false, Some(256))]
576 #[case(RSA_2048_PKCS8, false, false, true, None)]
578 fn test_private_key_from_pem(
579 #[case] pem_str: &str,
580 #[case] is_pkcs1: bool,
581 #[case] is_sec1: bool,
582 #[case] is_pkcs8: bool,
583 #[case] expected_bits: Option<u32>,
584 ) {
585 let pem = Pem::from_str(pem_str).expect("Failed to parse PEM");
586 let key: PrivateKey = pem.decode().expect("Failed to decode PrivateKey");
587
588 assert_eq!(key.is_pkcs1(), is_pkcs1);
589 assert_eq!(key.is_sec1(), is_sec1);
590 assert_eq!(key.is_pkcs8(), is_pkcs8);
591 if let Some(expected) = expected_bits {
592 assert_eq!(key.key_size(), expected);
593 }
594 }
595
596 #[test]
597 fn test_private_key_accessors() {
598 let pem = Pem::from_str(RSA_2048_PKCS1).expect("Failed to parse PEM");
599 let key: PrivateKey = pem.decode().expect("Failed to decode PrivateKey");
600
601 assert!(key.as_pkcs1().is_some());
602 assert!(key.as_sec1().is_none());
603 assert!(key.as_pkcs8().is_none());
604
605 let inner = key.into_pkcs1();
606 assert!(inner.is_some());
607 }
608
609 #[derive(Debug, Clone, Copy)]
610 enum KeyFormat {
611 Pkcs1,
612 Sec1,
613 Pkcs8,
614 }
615
616 #[rstest]
617 #[case::pkcs1(RSA_2048_PKCS1, KeyFormat::Pkcs1)]
618 #[case::sec1(EC_P256_SEC1, KeyFormat::Sec1)]
619 #[case::pkcs8(RSA_2048_PKCS8, KeyFormat::Pkcs8)]
620 fn test_from_conversions(#[case] pem_str: &str, #[case] format: KeyFormat) {
621 let pem = Pem::from_str(pem_str).expect("Failed to parse PEM");
622
623 let key = match format {
624 KeyFormat::Pkcs1 => {
625 let rsa_key: RSAPrivateKey = pem.decode().expect("Failed to decode RSAPrivateKey");
626 PrivateKey::from(rsa_key)
627 }
628 KeyFormat::Sec1 => {
629 let ec_key: ECPrivateKey = pem.decode().expect("Failed to decode ECPrivateKey");
630 PrivateKey::from(ec_key)
631 }
632 KeyFormat::Pkcs8 => {
633 let pkcs8_key: OneAsymmetricKey =
634 pem.decode().expect("Failed to decode OneAsymmetricKey");
635 PrivateKey::from(pkcs8_key)
636 }
637 };
638
639 match format {
640 KeyFormat::Pkcs1 => assert!(key.is_pkcs1()),
641 KeyFormat::Sec1 => assert!(key.is_sec1()),
642 KeyFormat::Pkcs8 => assert!(key.is_pkcs8()),
643 }
644 }
645
646 #[rstest]
647 #[case::pkcs1_rsa(RSA_2048_PKCS1, true, KeyAlgorithm::Rsa, 2048, 2048)]
648 #[case::sec1_ec(EC_P256_SEC1, true, KeyAlgorithm::Ec, 256, 520)]
649 #[case::pkcs8_rsa_v1(RSA_2048_PKCS8, false, KeyAlgorithm::Rsa, 0, 0)]
650 fn test_public_key_extraction(
651 #[case] pem_str: &str,
652 #[case] has_public_key: bool,
653 #[case] expected_algorithm: KeyAlgorithm,
654 #[case] expected_private_key_size: u32,
655 #[case] expected_public_key_size: u32,
656 ) {
657 let pem = Pem::from_str(pem_str).expect("Failed to parse PEM");
658 let key: PrivateKey = pem.decode().expect("Failed to decode PrivateKey");
659
660 assert_eq!(key.algorithm(), expected_algorithm);
662
663 assert_eq!(key.key_size(), expected_private_key_size);
665
666 let pub_key = key.public_key();
668 assert_eq!(pub_key.is_some(), has_public_key);
669
670 if let Some(pub_key) = pub_key {
671 assert_eq!(pub_key.algorithm(), expected_algorithm);
673
674 assert_eq!(pub_key.key_size(), expected_public_key_size);
676 }
677 }
678
679 #[test]
680 fn test_public_key_extraction_pkcs1_returns_pkcs1_format() {
681 let pem = Pem::from_str(RSA_2048_PKCS1).expect("Failed to parse PEM");
682 let key: PrivateKey = pem.decode().expect("Failed to decode PrivateKey");
683
684 let pub_key = key.public_key().expect("Should have public key");
685 assert!(pub_key.is_pkcs1());
686 assert!(!pub_key.is_spki());
687 }
688
689 #[test]
690 fn test_public_key_extraction_sec1_returns_spki_format() {
691 let pem = Pem::from_str(EC_P256_SEC1).expect("Failed to parse PEM");
692 let key: PrivateKey = pem.decode().expect("Failed to decode PrivateKey");
693
694 let pub_key = key.public_key().expect("Should have public key");
695 assert!(!pub_key.is_pkcs1());
696 assert!(pub_key.is_spki());
697 }
698
699 #[rstest]
700 #[case::pkcs1_rsa(RSA_2048_PKCS1, Label::RSAPrivateKey)]
701 #[case::sec1_ec(EC_P256_SEC1, Label::ECPrivateKey)]
702 #[case::pkcs8_rsa(RSA_2048_PKCS8, Label::PrivateKey)]
703 fn test_to_pem_roundtrip(#[case] pem_str: &str, #[case] expected_label: Label) {
704 let original_pem = Pem::from_str(pem_str).expect("Failed to parse PEM");
705 let key: PrivateKey = original_pem.decode().expect("Failed to decode PrivateKey");
706
707 assert_eq!(key.pem_label(), expected_label);
709
710 let exported_pem = key.to_pem().expect("Failed to export to PEM");
712 assert_eq!(exported_pem.label(), expected_label);
713
714 let decoded_key: PrivateKey = exported_pem
716 .decode()
717 .expect("Failed to decode exported PEM");
718 assert_eq!(decoded_key.algorithm(), key.algorithm());
719 assert_eq!(decoded_key.key_size(), key.key_size());
720 }
721}