diff --git a/Cargo.toml b/Cargo.toml index 76339a17c..add67e2b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,6 +61,10 @@ x509-tsp = { path = "./x509-tsp" } x509-cert = { path = "./x509-cert" } x509-ocsp = { path = "./x509-ocsp" } +# RSA: refactor: use RsaPublicKeyRef instead of RsaPublicKey from RustCrypto/formats - #706 +rsa = { git = "https://github.com/RustCrypto/RSA.git", rev = "dc89967d5acf570f35375a9eb9151380fabd2f28" } + + [workspace.lints.clippy] borrow_as_ptr = "warn" cast_lossless = "warn" diff --git a/pkcs1/src/lib.rs b/pkcs1/src/lib.rs index c5f302813..847405669 100644 --- a/pkcs1/src/lib.rs +++ b/pkcs1/src/lib.rs @@ -36,7 +36,7 @@ pub use crate::{ error::{Error, Result}, params::{RsaOaepParams, RsaPssParams, TrailerField}, private_key::RsaPrivateKey, - public_key::RsaPublicKey, + public_key::{RsaPublicKey, RsaPublicKeyRef}, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, version::Version, }; @@ -44,6 +44,7 @@ pub use crate::{ #[cfg(feature = "alloc")] pub use crate::{ private_key::{OtherPrimeInfos, other_prime_info::OtherPrimeInfo}, + public_key::RsaPublicKeyOwned, traits::{EncodeRsaPrivateKey, EncodeRsaPublicKey}, }; diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs index 0c1886efd..c89d56b5b 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -3,7 +3,7 @@ #[cfg(feature = "alloc")] pub(crate) mod other_prime_info; -use crate::{Error, Result, RsaPublicKey, Version}; +use crate::{Error, Result, RsaPublicKeyRef, Version}; use core::fmt; use der::{ Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, @@ -72,8 +72,8 @@ pub struct RsaPrivateKey<'a> { impl<'a> RsaPrivateKey<'a> { /// Get the public key that corresponds to this [`RsaPrivateKey`]. - pub fn public_key(&self) -> RsaPublicKey<'a> { - RsaPublicKey { + pub fn public_key(&self) -> RsaPublicKeyRef<'a> { + RsaPublicKeyRef { modulus: self.modulus, public_exponent: self.public_exponent, } @@ -150,14 +150,14 @@ impl EncodeValue for RsaPrivateKey<'_> { impl<'a> Sequence<'a> for RsaPrivateKey<'a> {} -impl<'a> From> for RsaPublicKey<'a> { - fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> { +impl<'a> From> for RsaPublicKeyRef<'a> { + fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKeyRef<'a> { private_key.public_key() } } -impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> { - fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> { +impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKeyRef<'a> { + fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKeyRef<'a> { private_key.public_key() } } diff --git a/pkcs1/src/public_key.rs b/pkcs1/src/public_key.rs index bf8e59c49..b7f3b6ee3 100644 --- a/pkcs1/src/public_key.rs +++ b/pkcs1/src/public_key.rs @@ -2,16 +2,23 @@ use crate::{Error, Result}; use der::{ - Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, + Decode, DecodeValue, Encode, EncodeValue, FixedTag, Header, Length, Reader, Sequence, Writer, asn1::UintRef, }; #[cfg(feature = "alloc")] -use der::Document; +use der::{Document, asn1::Uint}; #[cfg(feature = "pem")] use der::pem::PemLabel; +/// [`RsaPublicKey`] with [`UintRef`] INTEGERs. +pub type RsaPublicKeyRef<'a> = RsaPublicKey>; + +/// [`RsaPublicKey`] with allocating [`Uint`] INTEGERs. +#[cfg(feature = "alloc")] +pub type RsaPublicKeyOwned = RsaPublicKey; + /// PKCS#1 RSA Public Keys as defined in [RFC 8017 Appendix 1.1]. /// /// ASN.1 structure containing a serialized RSA public key: @@ -25,15 +32,18 @@ use der::pem::PemLabel; /// /// [RFC 8017 Appendix 1.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.1 #[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct RsaPublicKey<'a> { +pub struct RsaPublicKey { /// `n`: RSA modulus - pub modulus: UintRef<'a>, + pub modulus: UintType, /// `e`: RSA public exponent - pub public_exponent: UintRef<'a>, + pub public_exponent: UintType, } -impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { +impl<'a, UintType> DecodeValue<'a> for RsaPublicKey +where + UintType: DecodeValue<'a, Error = der::Error> + FixedTag + 'a, +{ type Error = der::Error; fn decode_value>(reader: &mut R, _header: Header) -> der::Result { Ok(Self { @@ -43,7 +53,10 @@ impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { } } -impl EncodeValue for RsaPublicKey<'_> { +impl EncodeValue for RsaPublicKey +where + UintType: EncodeValue + FixedTag, +{ fn value_len(&self) -> der::Result { self.modulus.encoded_len()? + self.public_exponent.encoded_len()? } @@ -55,9 +68,13 @@ impl EncodeValue for RsaPublicKey<'_> { } } -impl<'a> Sequence<'a> for RsaPublicKey<'a> {} +impl<'a, UintType> Sequence<'a> for RsaPublicKey {} -impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> { +impl<'a, UintType> TryFrom<&'a [u8]> for RsaPublicKey +where + RsaPublicKey: Decode<'a>, + Error: From< as Decode<'a>>::Error>, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -66,24 +83,30 @@ impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> { } #[cfg(feature = "alloc")] -impl TryFrom> for Document { +impl TryFrom> for Document +where + RsaPublicKey: EncodeValue, +{ type Error = Error; - fn try_from(spki: RsaPublicKey<'_>) -> Result { + fn try_from(spki: RsaPublicKey) -> Result { Self::try_from(&spki) } } #[cfg(feature = "alloc")] -impl TryFrom<&RsaPublicKey<'_>> for Document { +impl TryFrom<&RsaPublicKey> for Document +where + RsaPublicKey: EncodeValue, +{ type Error = Error; - fn try_from(spki: &RsaPublicKey<'_>) -> Result { + fn try_from(spki: &RsaPublicKey) -> Result { Ok(Self::encode_msg(spki)?) } } #[cfg(feature = "pem")] -impl PemLabel for RsaPublicKey<'_> { +impl PemLabel for RsaPublicKey { const PEM_LABEL: &'static str = "RSA PUBLIC KEY"; } diff --git a/pkcs1/src/traits.rs b/pkcs1/src/traits.rs index 9424775f8..d337fafae 100644 --- a/pkcs1/src/traits.rs +++ b/pkcs1/src/traits.rs @@ -16,7 +16,10 @@ use { use std::path::Path; #[cfg(all(feature = "alloc", feature = "pem"))] -use crate::{RsaPrivateKey, RsaPublicKey}; +use crate::{RsaPrivateKey, RsaPublicKeyRef}; + +#[cfg(doc)] +use crate::RsaPublicKey; /// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document. pub trait DecodeRsaPrivateKey: Sized { @@ -70,7 +73,7 @@ pub trait DecodeRsaPublicKey: Sized { #[cfg(feature = "pem")] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = Document::from_pem(s)?; - RsaPublicKey::validate_pem_label(label)?; + RsaPublicKeyRef::validate_pem_label(label)?; Self::from_pkcs1_der(doc.as_bytes()) } @@ -86,7 +89,7 @@ pub trait DecodeRsaPublicKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = Document::read_pem_file(path)?; - RsaPublicKey::validate_pem_label(&label)?; + RsaPublicKeyRef::validate_pem_label(&label)?; Self::from_pkcs1_der(doc.as_bytes()) } } @@ -128,7 +131,7 @@ pub trait EncodeRsaPublicKey { #[cfg(feature = "pem")] fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result { let doc = self.to_pkcs1_der()?; - Ok(doc.to_pem(RsaPublicKey::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(RsaPublicKeyRef::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded public key to the given path. @@ -141,6 +144,6 @@ pub trait EncodeRsaPublicKey { #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs1_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs1_der()?; - Ok(doc.write_pem_file(path, RsaPublicKey::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, RsaPublicKeyRef::PEM_LABEL, line_ending)?) } } diff --git a/pkcs1/tests/public_key.rs b/pkcs1/tests/public_key.rs index f3e480e82..ea2ba88e2 100644 --- a/pkcs1/tests/public_key.rs +++ b/pkcs1/tests/public_key.rs @@ -1,7 +1,7 @@ //! PKCS#1 public key tests use hex_literal::hex; -use pkcs1::RsaPublicKey; +use pkcs1::RsaPublicKeyRef; /// RSA-2048 PKCS#1 public key encoded as ASN.1 DER. /// @@ -22,7 +22,7 @@ const RSA_4096_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa4096-pub.der"); #[test] fn decode_rsa2048_der() { - let key = RsaPublicKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let key = RsaPublicKeyRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa2048-pub.pem @@ -37,7 +37,7 @@ fn decode_rsa2048_der() { #[test] fn decode_rsa4096_der() { - let key = RsaPublicKey::try_from(RSA_4096_DER_EXAMPLE).unwrap(); + let key = RsaPublicKeyRef::try_from(RSA_4096_DER_EXAMPLE).unwrap(); // Extracted using: // $ openssl asn1parse -in tests/examples/rsa4096-pub.pem