diff --git a/src/encoding.rs b/src/encoding.rs index bc0fac2c..b6ce17be 100644 --- a/src/encoding.rs +++ b/src/encoding.rs @@ -8,16 +8,29 @@ use crate::{ BigUint, RsaPrivateKey, RsaPublicKey, }; use core::convert::{TryFrom, TryInto}; -use pkcs8::{der::Encode, Document, EncodePrivateKey, EncodePublicKey, SecretDocument}; +use pkcs8::{ + der::Encode, Document, EncodePrivateKey, EncodePublicKey, ObjectIdentifier, SecretDocument, +}; use zeroize::Zeroizing; +/// ObjectID for the RSA PSS keys +pub const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); + /// Verify that the `AlgorithmIdentifier` for a key is correct. fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> pkcs8::spki::Result<()> { - algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?; - - if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() { - return Err(pkcs8::spki::Error::KeyMalformed); - } + match algorithm.oid { + pkcs1::ALGORITHM_OID => { + if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() { + return Err(pkcs8::spki::Error::KeyMalformed); + } + } + ID_RSASSA_PSS => { + if !algorithm.parameters.is_none() { + return Err(pkcs8::spki::Error::KeyMalformed); + } + } + _ => return Err(pkcs8::spki::Error::OidUnknown { oid: algorithm.oid }), + }; Ok(()) } diff --git a/src/pkcs1v15/signing_key.rs b/src/pkcs1v15/signing_key.rs index c5179803..ac6fa3e7 100644 --- a/src/pkcs1v15/signing_key.rs +++ b/src/pkcs1v15/signing_key.rs @@ -253,6 +253,9 @@ where type Error = pkcs8::Error; fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + private_key_info + .algorithm + .assert_algorithm_oid(pkcs1::ALGORITHM_OID)?; RsaPrivateKey::try_from(private_key_info).map(Self::new) } } diff --git a/src/pkcs1v15/verifying_key.rs b/src/pkcs1v15/verifying_key.rs index a0a217ad..baa77c98 100644 --- a/src/pkcs1v15/verifying_key.rs +++ b/src/pkcs1v15/verifying_key.rs @@ -206,6 +206,8 @@ where type Error = pkcs8::spki::Error; fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + spki.algorithm.assert_algorithm_oid(pkcs1::ALGORITHM_OID)?; + RsaPublicKey::try_from(spki).map(Self::new) } } diff --git a/src/pss.rs b/src/pss.rs index e0b94137..6d4fae8c 100644 --- a/src/pss.rs +++ b/src/pss.rs @@ -22,7 +22,7 @@ pub use self::{ use alloc::{boxed::Box, vec::Vec}; use core::fmt::{self, Debug}; -use const_oid::{AssociatedOid, ObjectIdentifier}; +use const_oid::AssociatedOid; use digest::{Digest, DynDigest, FixedOutputReset}; use num_bigint::BigUint; use pkcs1::RsaPssParams; @@ -32,6 +32,7 @@ use rand_core::CryptoRngCore; use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad}; use crate::algorithms::pss::*; use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt}; +use crate::encoding::ID_RSASSA_PSS; use crate::errors::{Error, Result}; use crate::traits::PublicKeyParts; use crate::traits::SignatureScheme; @@ -240,8 +241,6 @@ fn get_pss_signature_algo_id(salt_len: u8) -> pkcs8::spki::Result(salt_len); Ok(AlgorithmIdentifierOwned { diff --git a/src/pss/signing_key.rs b/src/pss/signing_key.rs index e3a38c2e..22a6cac1 100644 --- a/src/pss/signing_key.rs +++ b/src/pss/signing_key.rs @@ -1,4 +1,5 @@ use super::{get_pss_signature_algo_id, sign_digest, Signature, VerifyingKey}; +use crate::encoding::ID_RSASSA_PSS; use crate::{Result, RsaPrivateKey}; use const_oid::AssociatedOid; use core::marker::PhantomData; @@ -231,6 +232,9 @@ where type Error = pkcs8::Error; fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + private_key_info + .algorithm + .assert_algorithm_oid(ID_RSASSA_PSS)?; RsaPrivateKey::try_from(private_key_info).map(Self::new) } } diff --git a/src/pss/verifying_key.rs b/src/pss/verifying_key.rs index a4a7612b..b1ea02e6 100644 --- a/src/pss/verifying_key.rs +++ b/src/pss/verifying_key.rs @@ -1,10 +1,11 @@ use super::{verify_digest, Signature}; +use crate::encoding::ID_RSASSA_PSS; use crate::RsaPublicKey; use core::marker::PhantomData; use digest::{Digest, FixedOutputReset}; use pkcs8::{ spki::{der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier}, - Document, EncodePublicKey, AssociatedOid, + AssociatedOid, Document, EncodePublicKey, }; use signature::{hazmat::PrehashVerifier, DigestVerifier, Verifier}; #[cfg(feature = "serde")] @@ -169,6 +170,15 @@ where type Error = pkcs8::spki::Error; fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + match spki.algorithm.oid { + ID_RSASSA_PSS | pkcs1::ALGORITHM_OID => (), + _ => { + return Err(spki::Error::OidUnknown { + oid: spki.algorithm.oid, + }); + } + } + RsaPublicKey::try_from(spki).map(Self::new) } } diff --git a/tests/examples/pkcs8/rsa2048-rfc9421-priv.der b/tests/examples/pkcs8/rsa2048-rfc9421-priv.der new file mode 100644 index 00000000..4585234d Binary files /dev/null and b/tests/examples/pkcs8/rsa2048-rfc9421-priv.der differ diff --git a/tests/examples/pkcs8/rsa2048-rfc9421-pub.der b/tests/examples/pkcs8/rsa2048-rfc9421-pub.der new file mode 100644 index 00000000..923fa695 Binary files /dev/null and b/tests/examples/pkcs8/rsa2048-rfc9421-pub.der differ diff --git a/tests/pkcs8.rs b/tests/pkcs8.rs index ee597e18..17a0f00c 100644 --- a/tests/pkcs8.rs +++ b/tests/pkcs8.rs @@ -14,10 +14,17 @@ const RSA_2048_PRIV_PEM: &str = include_str!("examples/pkcs8/rsa2048-priv.pem"); #[cfg(feature = "pem")] const RSA_2048_PUB_PEM: &str = include_str!("examples/pkcs8/rsa2048-pub.pem"); +/// RSA-2048 PSS PKCS#8 private key encoded as DER +const RSA_2048_PSS_PRIV_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9421-priv.der"); + +/// RSA-2048 PSS PKCS#8 public key encoded as DER +const RSA_2048_PSS_PUB_DER: &[u8] = include_bytes!("examples/pkcs8/rsa2048-rfc9421-pub.der"); + use hex_literal::hex; use rsa::{ pkcs1v15, pkcs8::{DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey}, + pss, traits::{PrivateKeyParts, PublicKeyParts}, RsaPrivateKey, RsaPublicKey, }; @@ -51,6 +58,29 @@ fn decode_rsa2048_pub_der() { let _ = pkcs1v15::VerifyingKey::::from_public_key_der(RSA_2048_PUB_DER).unwrap(); } +#[test] +fn decode_rsa2048_pss_priv_der() { + let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap(); + + assert_eq!(&key.n().to_bytes_be(), &hex!("AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB6463C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA005E3C90F3A3A70E467937C9586E0803E0EDF0E8CEA902F2E4864F79027753AE27DB2053CD53C3CF30EECECAB1401EA803B339E33C59933AD08470DD99D45A5681C870B982CF2FE5A892A96D775D67AAACE2F9B27D72F48A00361D50000DE5652DCDDA62CBA2DB4E04B13FBA1C894E139F483923A683649EC0F0BCE8D0A4B2658A00E3CE66A9C3B419501D570F65AB868E4FDBFA77E9DBE1B9CD91056494B4377D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB")); + assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + assert_eq!(&key.d().to_bytes_be(), &hex!("9407C8A9FA426289954A17C02A7C1FDA50FD234C0A8E41EC0AD64289FE24025C10AAA5BA37EB482F76DD391F9559FD10D590480EDA4EF7552B1BBA5A9ECCAB3C445B36B44994F8981323D31E4093D670FE9768ACBA2C862CD04D9C5A0A7C1800E0A01B3C96506AD14857D0A7DF82521E7A4DE7ED9E86B7860581ED9301C5B659B3785DF2BB96EA45CA8E871F25918981CC3004505CB25E3927539F968C04FD0F3B86D0CA4E4E4714D449E39C88F254164B501E4BC66F29BB2ABC847F01FC4E4B342FB5A1CF23FAD0F2F7C52F4534E262F66FB3CEDC1821718342E28CD860EC213783DA6236A07A0F332003D30748EC1C12556D7CA7587E8E07DCE1D95EC4A611")); + assert_eq!(&key.primes()[0].to_bytes_be(), &hex!("E55FBA212239C846821579BE7E4D44336C700167A478F542032BEBF506D3945382670B7D5B08D48E1B4A46EB22E54ABE21867FB6AD96444E00B386FF14710CB69D80111E3721CBE65CFA8A141A1492D5434BB7538481EBB27462D54EDD1EA55DC2230431EE63C4A3609EC28BA67ABEE0DCA1A12E8E796BB5485A331BD27DC509")); + assert_eq!(&key.primes()[1].to_bytes_be(), &hex!("C3EC0875ED7B5B96340A9869DD9674B8CF0E52AD4092B57620A6AEA981DA0F1013DF610CE1C8B630C111DA7214128E20FF8DA55B4CD8A2E145A8E370BF4F87C8EB203E9752A8A442E562E09F455769B8DA35CCBA2A134F5DE274020B6A7620F03DE276FCBFDE2B0356438DD17DD40152AB80C1277B4849A643CB158AA07ADBC3")); + + let _ = pss::SigningKey::::from_pkcs8_der(RSA_2048_PSS_PRIV_DER).unwrap(); +} + +#[test] +fn decode_rsa2048_pss_pub_der() { + let key = RsaPublicKey::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap(); + + assert_eq!(&key.n().to_bytes_be(), &hex!("AF8B669B7AF6D1677F3DBAAF3F5B36F9012DBE9B91695F18AB8D208D447CCB6463C5AE9DA46D865C76CF7EF32CF1CB7E2E1D461F8E71DBC470DD1CB9DE69BEA005E3C90F3A3A70E467937C9586E0803E0EDF0E8CEA902F2E4864F79027753AE27DB2053CD53C3CF30EECECAB1401EA803B339E33C59933AD08470DD99D45A5681C870B982CF2FE5A892A96D775D67AAACE2F9B27D72F48A00361D50000DE5652DCDDA62CBA2DB4E04B13FBA1C894E139F483923A683649EC0F0BCE8D0A4B2658A00E3CE66A9C3B419501D570F65AB868E4FDBFA77E9DBE1B9CD91056494B4377D502F266FB17433A9F4B08D08DE3C576A670CE90557AF94F67579A3273A5C8DB")); + assert_eq!(&key.e().to_bytes_be(), &hex!("010001")); + + let _ = pss::VerifyingKey::::from_public_key_der(RSA_2048_PSS_PUB_DER).unwrap(); +} + #[test] fn encode_rsa2048_priv_der() { let key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();