From 09eacfdedfb985e7216a415416524ebd49e7539f Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 17:25:11 +0200 Subject: [PATCH 01/14] der: add `AsIntRef` and `AsUintRef` traits This is needed for `pkcs1` generic `*Ref` and `*Owned` split --- der/src/asn1.rs | 2 +- der/src/asn1/integer.rs | 17 +++++++++++++++++ der/src/asn1/integer/int.rs | 18 ++++++++++++++++-- der/src/asn1/integer/uint.rs | 17 ++++++++++++++++- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/der/src/asn1.rs b/der/src/asn1.rs index 9717b395f..ff2dc5bf7 100644 --- a/der/src/asn1.rs +++ b/der/src/asn1.rs @@ -42,7 +42,7 @@ pub use self::{ general_string::GeneralStringRef, generalized_time::GeneralizedTime, ia5_string::Ia5StringRef, - integer::{int::IntRef, uint::UintRef}, + integer::{AsIntRef, AsUintRef, int::IntRef, uint::UintRef}, null::Null, octet_string::OctetStringRef, printable_string::PrintableStringRef, diff --git a/der/src/asn1/integer.rs b/der/src/asn1/integer.rs index e00e3fcd7..c7dbc5fc6 100644 --- a/der/src/asn1/integer.rs +++ b/der/src/asn1/integer.rs @@ -3,6 +3,9 @@ pub(super) mod int; pub(super) mod uint; +use int::IntRef; +use uint::UintRef; + use core::{cmp::Ordering, mem::size_of}; use crate::{EncodeValue, Result, encode::encode_value_to_slice}; @@ -30,6 +33,20 @@ where Ok(buf1.cmp(buf2)) } +/// Borrow the owned or ref `INTEGER` as [`IntRef`] +pub trait AsIntRef { + /// Borrows the owned or ref `INTEGER` as [`IntRef`] + #[must_use] + fn as_int_ref<'a>(&'a self) -> IntRef<'a>; +} + +/// Borrow the owned or ref `INTEGER` as [`UintRef`] +pub trait AsUintRef { + /// Borrows the owned or ref `INTEGER` as [`UintRef`] + #[must_use] + fn as_uint_ref<'a>(&'a self) -> UintRef<'a>; +} + #[cfg(test)] #[allow(clippy::unwrap_used)] pub(crate) mod tests { diff --git a/der/src/asn1/integer/int.rs b/der/src/asn1/integer/int.rs index 0da6c93de..540fced5f 100644 --- a/der/src/asn1/integer/int.rs +++ b/der/src/asn1/integer/int.rs @@ -3,7 +3,7 @@ use super::{is_highest_bit_set, uint, value_cmp}; use crate::{ AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, - Result, Tag, ValueOrd, Writer, ord::OrdIsValueOrd, + Result, Tag, ValueOrd, Writer, asn1::integer::AsIntRef, ord::OrdIsValueOrd, }; use core::cmp::Ordering; @@ -180,13 +180,19 @@ impl FixedTag for IntRef<'_> { impl OrdIsValueOrd for IntRef<'_> {} +impl AsIntRef for IntRef<'_> { + fn as_int_ref<'a>(&'a self) -> IntRef<'a> { + *self + } +} + #[cfg(feature = "alloc")] mod allocating { use super::{IntRef, strip_leading_ones, validate_canonical}; use crate::{ BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, - asn1::Uint, + asn1::{Uint, integer::AsIntRef}, ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, }; @@ -237,6 +243,14 @@ mod allocating { } } + impl AsIntRef for Int { + fn as_int_ref<'a>(&'a self) -> IntRef<'a> { + let inner = self.inner.as_ref(); + + IntRef { inner } + } + } + impl_any_conversions!(Int); impl<'a> DecodeValue<'a> for Int { diff --git a/der/src/asn1/integer/uint.rs b/der/src/asn1/integer/uint.rs index c0b6f87c9..9f6d552e6 100644 --- a/der/src/asn1/integer/uint.rs +++ b/der/src/asn1/integer/uint.rs @@ -3,7 +3,7 @@ use super::value_cmp; use crate::{ AnyRef, BytesRef, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, - Result, Tag, ValueOrd, Writer, ord::OrdIsValueOrd, + Result, Tag, ValueOrd, Writer, asn1::integer::AsUintRef, ord::OrdIsValueOrd, }; use core::cmp::Ordering; @@ -169,12 +169,19 @@ impl FixedTag for UintRef<'_> { impl OrdIsValueOrd for UintRef<'_> {} +impl AsUintRef for UintRef<'_> { + fn as_uint_ref<'a>(&'a self) -> UintRef<'a> { + *self + } +} + #[cfg(feature = "alloc")] mod allocating { use super::{UintRef, decode_to_slice, encoded_len, strip_leading_zeroes}; use crate::{ BytesOwned, DecodeValue, EncodeValue, Error, ErrorKind, FixedTag, Header, Length, Reader, Result, Tag, Writer, + asn1::integer::AsUintRef, ord::OrdIsValueOrd, referenced::{OwnedToRef, RefToOwned}, }; @@ -290,6 +297,14 @@ mod allocating { } } + impl AsUintRef for Uint { + fn as_uint_ref<'a>(&'a self) -> UintRef<'a> { + let inner = self.inner.as_ref(); + + UintRef { inner } + } + } + macro_rules! impl_from_traits { ($($uint:ty),+) => { $( From 9279a2e6ee2a6757d10d29513c833c665e2220e6 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:22:07 +0200 Subject: [PATCH 02/14] pkcs1: split RsaPublicKey into `RsaPublicKeyRef` and `RsaPublicKeyOwned` patch rsa crate with RustCrypto/RSA commit rev pkcs1: pub use RsaPublicKey use RsaPublicKey #[cfg(doc)] pkcs1: replace UintType with U pkcs1: split RsaPrivateKey info RsaPrivateKeyRef and Owned bump RSA patch git commit rev --- Cargo.toml | 4 + pkcs1/src/lib.rs | 7 +- pkcs1/src/private_key.rs | 118 ++++++++++++++-------- pkcs1/src/private_key/other_prime_info.rs | 24 +++-- pkcs1/src/public_key.rs | 51 +++++++--- pkcs1/src/traits.rs | 21 ++-- pkcs1/tests/private_key.rs | 12 +-- pkcs1/tests/public_key.rs | 6 +- 8 files changed, 157 insertions(+), 86 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 76339a17c..ba3e00078 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 *Ref (or *Owned) der types from RustCrypto/formats - #706 +rsa = { git = "https://github.com/dishmaker/RSA.git", rev = "bf83f5541c4260ec7295c92fe6d0f7fe9ae4972a" } + + [workspace.lints.clippy] borrow_as_ptr = "warn" cast_lossless = "warn" diff --git a/pkcs1/src/lib.rs b/pkcs1/src/lib.rs index c5f302813..e6c7fc27b 100644 --- a/pkcs1/src/lib.rs +++ b/pkcs1/src/lib.rs @@ -35,15 +35,16 @@ pub use der::{ pub use crate::{ error::{Error, Result}, params::{RsaOaepParams, RsaPssParams, TrailerField}, - private_key::RsaPrivateKey, - public_key::RsaPublicKey, + private_key::{RsaPrivateKey, RsaPrivateKeyRef}, + public_key::{RsaPublicKey, RsaPublicKeyRef}, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, version::Version, }; #[cfg(feature = "alloc")] pub use crate::{ - private_key::{OtherPrimeInfos, other_prime_info::OtherPrimeInfo}, + private_key::{OtherPrimeInfos, RsaPrivateKeyOwned, 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..e4686fed1 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -3,19 +3,30 @@ #[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, asn1::{OctetStringRef, UintRef}, + referenced::OwnedToRef, }; #[cfg(feature = "alloc")] use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument}; +#[cfg(feature = "alloc")] +use der::asn1::Uint; + #[cfg(feature = "pem")] use der::pem::PemLabel; +/// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2]. +pub type RsaPrivateKeyRef<'a> = RsaPrivateKey>; + +/// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2]. +#[cfg(feature = "alloc")] +pub type RsaPrivateKeyOwned = RsaPrivateKey; + /// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2]. /// /// ASN.1 structure containing a serialized RSA private key: @@ -40,45 +51,51 @@ use der::pem::PemLabel; /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Clone)] -pub struct RsaPrivateKey<'a> { +pub struct RsaPrivateKey { /// `n`: RSA modulus. - pub modulus: UintRef<'a>, + pub modulus: U, /// `e`: RSA public exponent. - pub public_exponent: UintRef<'a>, + pub public_exponent: U, /// `d`: RSA private exponent. - pub private_exponent: UintRef<'a>, + pub private_exponent: U, /// `p`: first prime factor of `n`. - pub prime1: UintRef<'a>, + pub prime1: U, /// `q`: Second prime factor of `n`. - pub prime2: UintRef<'a>, + pub prime2: U, /// First exponent: `d mod (p-1)`. - pub exponent1: UintRef<'a>, + pub exponent1: U, /// Second exponent: `d mod (q-1)`. - pub exponent2: UintRef<'a>, + pub exponent2: U, /// CRT coefficient: `(inverse of q) mod p`. - pub coefficient: UintRef<'a>, + pub coefficient: U, /// Additional primes `r_3`, ..., `r_u`, in order, if this is a multi-prime /// RSA key (i.e. `version` is `multi`). - pub other_prime_infos: Option>, + pub other_prime_infos: Option>, } -impl<'a> RsaPrivateKey<'a> { +impl<'u, U> RsaPrivateKey +where + U: OwnedToRef = UintRef<'u>>, + U: 'u, +{ /// Get the public key that corresponds to this [`RsaPrivateKey`]. - pub fn public_key(&self) -> RsaPublicKey<'a> { - RsaPublicKey { - modulus: self.modulus, - public_exponent: self.public_exponent, + pub fn public_key(&'u self) -> RsaPublicKeyRef<'u> { + RsaPublicKeyRef { + modulus: self.modulus.owned_to_ref(), + public_exponent: self.public_exponent.owned_to_ref(), } } +} +impl RsaPrivateKey { /// Get the [`Version`] for this key. /// /// Determined by the presence or absence of the @@ -92,7 +109,10 @@ impl<'a> RsaPrivateKey<'a> { } } -impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> { +impl<'a, U> DecodeValue<'a> for RsaPrivateKey +where + U: Decode<'a, Error = der::Error>, +{ type Error = der::Error; fn decode_value>(reader: &mut R, _header: Header) -> der::Result { @@ -119,7 +139,10 @@ impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> { } } -impl EncodeValue for RsaPrivateKey<'_> { +impl EncodeValue for RsaPrivateKey +where + U: Encode, +{ fn value_len(&self) -> der::Result { self.version().encoded_len()? + self.modulus.encoded_len()? @@ -148,21 +171,22 @@ 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> { - private_key.public_key() - } -} +impl Sequence<'_> for RsaPrivateKey {} -impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> { - fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> { +impl<'u, U> From<&'u RsaPrivateKey> for RsaPublicKeyRef<'u> +where + U: OwnedToRef = UintRef<'u>>, + U: 'u, +{ + fn from(private_key: &'u RsaPrivateKey) -> RsaPublicKeyRef<'u> { private_key.public_key() } } -impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> { +impl<'a, U> TryFrom<&'a [u8]> for RsaPrivateKey +where + U: Decode<'a, Error = der::Error>, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -170,7 +194,10 @@ impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> { } } -impl<'a> TryFrom<&'a OctetStringRef> for RsaPrivateKey<'a> { +impl<'a, U> TryFrom<&'a OctetStringRef> for RsaPrivateKey +where + U: Decode<'a, Error = der::Error>, +{ type Error = Error; fn try_from(bytes: &'a OctetStringRef) -> Result { @@ -178,7 +205,10 @@ impl<'a> TryFrom<&'a OctetStringRef> for RsaPrivateKey<'a> { } } -impl fmt::Debug for RsaPrivateKey<'_> { +impl fmt::Debug for RsaPrivateKey +where + U: fmt::Debug, +{ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RsaPrivateKey") .field("version", &self.version()) @@ -189,25 +219,31 @@ impl fmt::Debug for RsaPrivateKey<'_> { } #[cfg(feature = "alloc")] -impl TryFrom> for SecretDocument { +impl TryFrom> for SecretDocument +where + U: Encode, +{ type Error = Error; - fn try_from(private_key: RsaPrivateKey<'_>) -> Result { + fn try_from(private_key: RsaPrivateKey) -> Result { SecretDocument::try_from(&private_key) } } #[cfg(feature = "alloc")] -impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument { +impl TryFrom<&RsaPrivateKey> for SecretDocument +where + U: Encode, +{ type Error = Error; - fn try_from(private_key: &RsaPrivateKey<'_>) -> Result { + fn try_from(private_key: &RsaPrivateKey) -> Result { Ok(Self::encode_msg(private_key)?) } } #[cfg(feature = "pem")] -impl PemLabel for RsaPrivateKey<'_> { +impl PemLabel for RsaPrivateKey { const PEM_LABEL: &'static str = "RSA PRIVATE KEY"; } @@ -217,12 +253,12 @@ impl PemLabel for RsaPrivateKey<'_> { #[cfg(not(feature = "alloc"))] #[derive(Clone)] #[non_exhaustive] -pub struct OtherPrimeInfos<'a> { - _lifetime: core::marker::PhantomData<&'a ()>, +pub struct OtherPrimeInfos { + _marker: core::marker::PhantomData, } #[cfg(not(feature = "alloc"))] -impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> { +impl<'a, U> DecodeValue<'a> for OtherPrimeInfos { type Error = der::Error; fn decode_value>(reader: &mut R, _header: Header) -> der::Result { @@ -233,7 +269,7 @@ impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> { } #[cfg(not(feature = "alloc"))] -impl EncodeValue for OtherPrimeInfos<'_> { +impl EncodeValue for OtherPrimeInfos { fn value_len(&self) -> der::Result { // Placeholder decoder that always returns an error. // Uses `Tag::Integer` to signal an unsupported version. @@ -248,10 +284,10 @@ impl EncodeValue for OtherPrimeInfos<'_> { } #[cfg(not(feature = "alloc"))] -impl der::FixedTag for OtherPrimeInfos<'_> { +impl der::FixedTag for OtherPrimeInfos { const TAG: Tag = Tag::Sequence; } /// Additional RSA prime info in a multi-prime RSA key. #[cfg(feature = "alloc")] -pub type OtherPrimeInfos<'a> = Vec>; +pub type OtherPrimeInfos = Vec>; diff --git a/pkcs1/src/private_key/other_prime_info.rs b/pkcs1/src/private_key/other_prime_info.rs index bc6185bf2..d7a7dcc04 100644 --- a/pkcs1/src/private_key/other_prime_info.rs +++ b/pkcs1/src/private_key/other_prime_info.rs @@ -1,8 +1,6 @@ //! PKCS#1 OtherPrimeInfo support. -use der::{ - DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer, asn1::UintRef, -}; +use der::{Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer}; /// PKCS#1 OtherPrimeInfo as defined in [RFC 8017 Appendix 1.2]. /// @@ -18,18 +16,21 @@ use der::{ /// /// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2 #[derive(Clone)] -pub struct OtherPrimeInfo<'a> { +pub struct OtherPrimeInfo { /// Prime factor `r_i` of `n`, where `i` >= 3. - pub prime: UintRef<'a>, + pub prime: U, /// Exponent: `d_i = d mod (r_i - 1)`. - pub exponent: UintRef<'a>, + pub exponent: U, /// CRT coefficient: `t_i = (r_1 * r_2 * ... * r_(i-1))^(-1) mod r_i`. - pub coefficient: UintRef<'a>, + pub coefficient: U, } -impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { +impl<'a, U> DecodeValue<'a> for OtherPrimeInfo +where + U: Decode<'a, Error = der::Error>, +{ type Error = der::Error; fn decode_value>(reader: &mut R, _header: Header) -> der::Result { @@ -41,7 +42,10 @@ impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> { } } -impl EncodeValue for OtherPrimeInfo<'_> { +impl EncodeValue for OtherPrimeInfo +where + U: Encode, +{ fn value_len(&self) -> der::Result { self.prime.encoded_len()? + self.exponent.encoded_len()? + self.coefficient.encoded_len()? } @@ -54,4 +58,4 @@ impl EncodeValue for OtherPrimeInfo<'_> { } } -impl<'a> Sequence<'a> for OtherPrimeInfo<'a> {} +impl Sequence<'_> for OtherPrimeInfo {} diff --git a/pkcs1/src/public_key.rs b/pkcs1/src/public_key.rs index bf8e59c49..3b6e7ee0e 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: U, /// `e`: RSA public exponent - pub public_exponent: UintRef<'a>, + pub public_exponent: U, } -impl<'a> DecodeValue<'a> for RsaPublicKey<'a> { +impl<'a, U> DecodeValue<'a> for RsaPublicKey +where + U: 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 + U: 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, U> Sequence<'a> for RsaPublicKey {} -impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> { +impl<'a, U> 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..605864734 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::{RsaPrivateKeyRef, RsaPublicKeyRef}; + +#[cfg(doc)] +use crate::RsaPublicKey; /// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document. pub trait DecodeRsaPrivateKey: Sized { @@ -34,7 +37,7 @@ pub trait DecodeRsaPrivateKey: Sized { #[cfg(feature = "pem")] fn from_pkcs1_pem(s: &str) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; - RsaPrivateKey::validate_pem_label(label)?; + RsaPrivateKeyRef::validate_pem_label(label)?; Self::from_pkcs1_der(doc.as_bytes()) } @@ -49,7 +52,7 @@ pub trait DecodeRsaPrivateKey: Sized { #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs1_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; - RsaPrivateKey::validate_pem_label(&label)?; + RsaPrivateKeyRef::validate_pem_label(&label)?; Self::from_pkcs1_der(doc.as_bytes()) } } @@ -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()) } } @@ -101,7 +104,7 @@ pub trait EncodeRsaPrivateKey { #[cfg(feature = "pem")] fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs1_der()?; - Ok(doc.to_pem(RsaPrivateKey::PEM_LABEL, line_ending)?) + Ok(doc.to_pem(RsaPrivateKeyRef::PEM_LABEL, line_ending)?) } /// Write ASN.1 DER-encoded PKCS#1 private key to the given path. @@ -114,7 +117,7 @@ pub trait EncodeRsaPrivateKey { #[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, RsaPrivateKey::PEM_LABEL, line_ending)?) + Ok(doc.write_pem_file(path, RsaPrivateKeyRef::PEM_LABEL, line_ending)?) } } @@ -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/private_key.rs b/pkcs1/tests/private_key.rs index 9253bc07a..e412d52df 100644 --- a/pkcs1/tests/private_key.rs +++ b/pkcs1/tests/private_key.rs @@ -1,7 +1,7 @@ //! PKCS#1 private key tests use hex_literal::hex; -use pkcs1::{RsaPrivateKey, Version}; +use pkcs1::{RsaPrivateKeyRef, Version}; /// RSA-2048 PKCS#1 private key encoded as ASN.1 DER. /// @@ -17,7 +17,7 @@ const RSA_2048_MULTI_PRIME_DER_EXAMPLE: &[u8] = include_bytes!("examples/rsa2048 #[test] fn decode_rsa2048_der() { - let key = RsaPrivateKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let key = RsaPrivateKeyRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::TwoPrime); // Extracted using: @@ -70,7 +70,7 @@ fn decode_rsa2048_der() { #[test] fn decode_rsa4096_der() { - let key = RsaPrivateKey::try_from(RSA_4096_DER_EXAMPLE).unwrap(); + let key = RsaPrivateKeyRef::try_from(RSA_4096_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::TwoPrime); // Extracted using: @@ -125,13 +125,13 @@ fn decode_rsa4096_der() { #[test] fn decode_rsa2048_multi_prime_der() { // Multi-prime RSA keys are unsupported when the alloc feature is disabled - assert!(RsaPrivateKey::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).is_err()); + assert!(RsaPrivateKeyRef::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).is_err()); } #[cfg(feature = "alloc")] #[test] fn decode_rsa2048_multi_prime_der() { - let key = RsaPrivateKey::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).unwrap(); + let key = RsaPrivateKeyRef::try_from(RSA_2048_MULTI_PRIME_DER_EXAMPLE).unwrap(); assert_eq!(key.version(), Version::Multi); // Extracted using: @@ -204,7 +204,7 @@ fn decode_rsa2048_multi_prime_der() { #[test] fn private_key_to_public_key() { - let private_key = RsaPrivateKey::try_from(RSA_2048_DER_EXAMPLE).unwrap(); + let private_key = RsaPrivateKeyRef::try_from(RSA_2048_DER_EXAMPLE).unwrap(); let public_key = private_key.public_key(); // Extracted using: 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 From cceea30dd41f02fbf6197baab10df8c79964ea06 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 20:18:20 +0200 Subject: [PATCH 03/14] pkcs1: use `AsUintRef` instead of `OwnedToRef` --- Cargo.toml | 2 +- pkcs1/src/private_key.rs | 21 +++++++++------------ 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ba3e00078..2e4cbab5e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,7 +62,7 @@ x509-cert = { path = "./x509-cert" } x509-ocsp = { path = "./x509-ocsp" } # RSA: refactor: use *Ref (or *Owned) der types from RustCrypto/formats - #706 -rsa = { git = "https://github.com/dishmaker/RSA.git", rev = "bf83f5541c4260ec7295c92fe6d0f7fe9ae4972a" } +rsa = { git = "https://github.com/dishmaker/RSA.git", rev = "96c97ec3e8b2bedde44f5954334618bec87a19c3" } [workspace.lints.clippy] diff --git a/pkcs1/src/private_key.rs b/pkcs1/src/private_key.rs index e4686fed1..aa7259ac1 100644 --- a/pkcs1/src/private_key.rs +++ b/pkcs1/src/private_key.rs @@ -7,8 +7,7 @@ use crate::{Error, Result, RsaPublicKeyRef, Version}; use core::fmt; use der::{ Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer, - asn1::{OctetStringRef, UintRef}, - referenced::OwnedToRef, + asn1::{AsUintRef, OctetStringRef, UintRef}, }; #[cfg(feature = "alloc")] @@ -81,16 +80,15 @@ pub struct RsaPrivateKey { pub other_prime_infos: Option>, } -impl<'u, U> RsaPrivateKey +impl RsaPrivateKey where - U: OwnedToRef = UintRef<'u>>, - U: 'u, + U: AsUintRef, { /// Get the public key that corresponds to this [`RsaPrivateKey`]. - pub fn public_key(&'u self) -> RsaPublicKeyRef<'u> { + pub fn public_key<'a>(&'a self) -> RsaPublicKeyRef<'a> { RsaPublicKeyRef { - modulus: self.modulus.owned_to_ref(), - public_exponent: self.public_exponent.owned_to_ref(), + modulus: self.modulus.as_uint_ref(), + public_exponent: self.public_exponent.as_uint_ref(), } } } @@ -173,12 +171,11 @@ where impl Sequence<'_> for RsaPrivateKey {} -impl<'u, U> From<&'u RsaPrivateKey> for RsaPublicKeyRef<'u> +impl<'a, U> From<&'a RsaPrivateKey> for RsaPublicKeyRef<'a> where - U: OwnedToRef = UintRef<'u>>, - U: 'u, + U: AsUintRef, { - fn from(private_key: &'u RsaPrivateKey) -> RsaPublicKeyRef<'u> { + fn from(private_key: &'a RsaPrivateKey) -> RsaPublicKeyRef<'a> { private_key.public_key() } } From 47c81dd7813e754699de1a4ad12cc863c0be21f1 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 20:27:39 +0200 Subject: [PATCH 04/14] fix doc RsaPrivateKey --- pkcs1/src/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs1/src/traits.rs b/pkcs1/src/traits.rs index 605864734..6caad9d5d 100644 --- a/pkcs1/src/traits.rs +++ b/pkcs1/src/traits.rs @@ -19,7 +19,7 @@ use std::path::Path; use crate::{RsaPrivateKeyRef, RsaPublicKeyRef}; #[cfg(doc)] -use crate::RsaPublicKey; +use crate::{RsaPrivateKey, RsaPublicKey}; /// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document. pub trait DecodeRsaPrivateKey: Sized { From d93e59b9cffea8e865fd16481a9d59cebbfbe158 Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:30:35 +0200 Subject: [PATCH 05/14] pkcs1+spki: RsaOaepParams generic `Ref` and `Owned` --- pkcs1/src/lib.rs | 2 +- pkcs1/src/params.rs | 174 +++++++++++++++++++++++++++--------------- pkcs1/tests/params.rs | 16 ++-- spki/src/algorithm.rs | 21 +++++ spki/src/lib.rs | 5 +- 5 files changed, 147 insertions(+), 71 deletions(-) diff --git a/pkcs1/src/lib.rs b/pkcs1/src/lib.rs index e6c7fc27b..ae7045b3b 100644 --- a/pkcs1/src/lib.rs +++ b/pkcs1/src/lib.rs @@ -34,7 +34,7 @@ pub use der::{ pub use crate::{ error::{Error, Result}, - params::{RsaOaepParams, RsaPssParams, TrailerField}, + params::{RsaOaepParams, RsaOaepParamsOwned, RsaOaepParamsRef, RsaPssParams, TrailerField}, private_key::{RsaPrivateKey, RsaPrivateKeyRef}, public_key::{RsaPublicKey, RsaPublicKeyRef}, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs index 186e6379d..ea90aa0e7 100644 --- a/pkcs1/src/params.rs +++ b/pkcs1/src/params.rs @@ -1,13 +1,15 @@ //! PKCS#1 RSA parameters. use crate::{Error, Result}; +#[cfg(feature = "alloc")] +use der::Any; use der::{ Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode, TagNumber, Writer, asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier}, oid::AssociatedOid, }; -use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef}; +use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef, AsAlgorithmIdentifierRef}; const OID_SHA_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.3.14.3.2.26"); const OID_MGF_1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.8"); @@ -185,7 +187,7 @@ impl<'a> DecodeValue<'a> for RsaPssParams<'a> { .unwrap_or(SHA_1_AI), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? - .unwrap_or_else(default_mgf1_sha1), + .unwrap_or_else(|| default_mgf1_sha1::>()), salt_len: reader .context_specific(TagNumber(2), TagMode::Explicit)? .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT), @@ -224,13 +226,23 @@ impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> { } /// Default Mask Generation Function (MGF): SHA-1. -fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier> { - AlgorithmIdentifier::> { +fn default_mgf1_sha1() -> AlgorithmIdentifier> +where + AlgorithmIdentifier: From>>, +{ + AlgorithmIdentifier::> { oid: OID_MGF_1, - parameters: Some(SHA_1_AI), + parameters: Some(SHA_1_AI.into()), } } +/// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1] +pub type RsaOaepParamsRef<'a> = RsaOaepParams>; + +/// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1] +#[cfg(feature = "alloc")] +pub type RsaOaepParamsOwned = RsaOaepParams; + /// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1] /// /// ASN.1 structure containing a serialized RSAES-OAEP parameters: @@ -247,49 +259,23 @@ fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier> { /// /// [RFC 8017 Appendix 2.1]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.1 #[derive(Clone, Debug, Eq, PartialEq)] -pub struct RsaOaepParams<'a> { +pub struct RsaOaepParams { /// Hash Algorithm - pub hash: AlgorithmIdentifierRef<'a>, + pub hash: AlgorithmIdentifier, /// Mask Generation Function (MGF) - pub mask_gen: AlgorithmIdentifier>, + pub mask_gen: AlgorithmIdentifier>, /// The source (and possibly the value) of the label L - pub p_source: AlgorithmIdentifierRef<'a>, + pub p_source: AlgorithmIdentifier, } -impl<'a> RsaOaepParams<'a> { - /// Create new RsaPssParams for the provided digest and default (empty) label - pub fn new() -> Self - where - D: AssociatedOid, - { - Self::new_with_label::(&[]) - } - - /// Create new RsaPssParams for the provided digest and specified label - pub fn new_with_label(label: &'a impl AsRef<[u8]>) -> Self - where - D: AssociatedOid, - { - Self { - hash: AlgorithmIdentifierRef { - oid: D::OID, - parameters: Some(AnyRef::NULL), - }, - mask_gen: AlgorithmIdentifier { - oid: OID_MGF_1, - parameters: Some(AlgorithmIdentifierRef { - oid: D::OID, - parameters: Some(AnyRef::NULL), - }), - }, - p_source: pspecified_algorithm_identifier(label), - } - } - - fn context_specific_hash(&self) -> Option>> { - if self.hash == SHA_1_AI { +impl RsaOaepParams +where + AlgorithmIdentifier: AsAlgorithmIdentifierRef, +{ + fn context_specific_hash(&self) -> Option>> { + if self.hash.as_algo_ref() == SHA_1_AI { None } else { Some(ContextSpecificRef { @@ -300,64 +286,121 @@ impl<'a> RsaOaepParams<'a> { } } - fn context_specific_mask_gen( + fn context_specific_p_source( &self, - ) -> Option>>> { - if self.mask_gen == default_mgf1_sha1() { + ) -> Option>> { + if self.p_source.as_algo_ref() == default_pempty_string() { None } else { Some(ContextSpecificRef { - tag_number: TagNumber(1), + tag_number: TagNumber(2), tag_mode: TagMode::Explicit, - value: &self.mask_gen, + value: &self.p_source, }) } } +} - fn context_specific_p_source( +impl RsaOaepParams +where + AlgorithmIdentifier: AsAlgorithmIdentifierRef, + AlgorithmIdentifier: From>>, + Params: PartialEq, +{ + fn context_specific_mask_gen( &self, - ) -> Option>> { - if self.p_source == default_pempty_string() { + ) -> Option>>> { + if self.mask_gen == default_mgf1_sha1::() { None } else { Some(ContextSpecificRef { - tag_number: TagNumber(2), + tag_number: TagNumber(1), tag_mode: TagMode::Explicit, - value: &self.p_source, + value: &self.mask_gen, }) } } } -impl Default for RsaOaepParams<'_> { +impl<'a> RsaOaepParamsRef<'a> { + /// Create new RsaPssParams for the provided digest and default (empty) label + pub fn new() -> Self + where + D: AssociatedOid, + { + Self::new_with_label::(&[]) + } + + /// Create new RsaPssParams for the provided digest and specified label + pub fn new_with_label(label: &'a impl AsRef<[u8]>) -> RsaOaepParamsRef<'a> + where + D: AssociatedOid, + { + Self { + hash: AlgorithmIdentifier { + oid: D::OID, + parameters: Some(AnyRef::NULL), + }, + mask_gen: AlgorithmIdentifier { + oid: OID_MGF_1, + parameters: Some(AlgorithmIdentifier { + oid: D::OID, + parameters: Some(AnyRef::NULL), + }), + }, + p_source: pspecified_algorithm_identifier(label), + } + } +} + +impl Default for RsaOaepParams +where + AlgorithmIdentifier: From>, +{ fn default() -> Self { Self { - hash: SHA_1_AI, - mask_gen: default_mgf1_sha1(), - p_source: default_pempty_string(), + hash: SHA_1_AI.into(), + mask_gen: default_mgf1_sha1().into(), + p_source: default_pempty_string().into(), } } } -impl<'a> DecodeValue<'a> for RsaOaepParams<'a> { +impl<'a, Params> DecodeValue<'a> for RsaOaepParams +where + AlgorithmIdentifier: DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier>: + DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier: From>, + Params: 'a, +{ type Error = der::Error; fn decode_value>(reader: &mut R, _header: der::Header) -> der::Result { Ok(Self { hash: reader .context_specific(TagNumber(0), TagMode::Explicit)? - .unwrap_or(SHA_1_AI), + .unwrap_or(SHA_1_AI.into()), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? - .unwrap_or_else(default_mgf1_sha1), + .unwrap_or_else(|| default_mgf1_sha1().into()), p_source: reader .context_specific(TagNumber(2), TagMode::Explicit)? - .unwrap_or_else(default_pempty_string), + .unwrap_or_else(|| default_pempty_string().into()), }) } } -impl EncodeValue for RsaOaepParams<'_> { +impl EncodeValue for RsaOaepParams +where + AlgorithmIdentifier: AsAlgorithmIdentifierRef, + for<'b> Option>>: Encode, + for<'b> Option>>>: + Encode, + AlgorithmIdentifier: From>, + AlgorithmIdentifier: From>>, + Params: PartialEq, +{ fn value_len(&self) -> der::Result { self.context_specific_hash().encoded_len()? + self.context_specific_mask_gen().encoded_len()? @@ -372,9 +415,16 @@ impl EncodeValue for RsaOaepParams<'_> { } } -impl<'a> Sequence<'a> for RsaOaepParams<'a> {} +impl<'a, Params> Sequence<'a> for RsaOaepParams {} -impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> { +impl<'a, Params> TryFrom<&'a [u8]> for RsaOaepParams +where + AlgorithmIdentifier: DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier>: + DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier: From>, + Params: 'a, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { diff --git a/pkcs1/tests/params.rs b/pkcs1/tests/params.rs index c48d9dbf8..a6598b873 100644 --- a/pkcs1/tests/params.rs +++ b/pkcs1/tests/params.rs @@ -7,7 +7,7 @@ use der::{ oid::AssociatedOid, }; use hex_literal::hex; -use pkcs1::{RsaOaepParams, RsaPssParams, TrailerField}; +use pkcs1::{RsaOaepParamsRef, RsaPssParams, TrailerField}; /// Default PSS parameters using all default values (SHA1, MGF1) const RSA_PSS_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000"); @@ -134,7 +134,7 @@ fn new_pss_param() { #[test] fn decode_oaep_param() { - let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); + let param = RsaOaepParamsRef::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); assert!( param @@ -177,7 +177,7 @@ fn decode_oaep_param() { #[test] fn encode_oaep_param() { let mut buf = [0_u8; 256]; - let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); + let param = RsaOaepParamsRef::try_from(RSA_OAEP_PARAMETERS_SHA2_256).unwrap(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_SHA2_256 @@ -186,7 +186,7 @@ fn encode_oaep_param() { #[test] fn decode_oaep_param_default() { - let param = RsaOaepParams::try_from(RSA_OAEP_PARAMETERS_DEFAULTS).unwrap(); + let param = RsaOaepParamsRef::try_from(RSA_OAEP_PARAMETERS_DEFAULTS).unwrap(); assert!( param @@ -235,7 +235,9 @@ fn decode_oaep_param_default() { fn encode_oaep_param_default() { let mut buf = [0_u8; 256]; assert_eq!( - RsaOaepParams::default().encode_to_slice(&mut buf).unwrap(), + RsaOaepParamsRef::default() + .encode_to_slice(&mut buf) + .unwrap(), RSA_OAEP_PARAMETERS_DEFAULTS ); } @@ -244,13 +246,13 @@ fn encode_oaep_param_default() { fn new_oaep_param() { let mut buf = [0_u8; 256]; - let param = RsaOaepParams::new::(); + let param = RsaOaepParamsRef::new::(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_OAEP_PARAMETERS_DEFAULTS ); - let param = RsaOaepParams::new::(); + let param = RsaOaepParamsRef::new::(); println!("{:02x?}", param.encode_to_slice(&mut buf).unwrap()); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index 717d9f7ce..0a76322d7 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -186,6 +186,18 @@ impl<'a> AlgorithmIdentifierRef<'a> { } } +/// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. +pub trait AsAlgorithmIdentifierRef { + /// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. + fn as_algo_ref<'a>(&'a self) -> AlgorithmIdentifierRef<'a>; +} + +impl<'a> AsAlgorithmIdentifierRef for AlgorithmIdentifierRef<'a> { + fn as_algo_ref(&self) -> AlgorithmIdentifierRef<'a> { + *self + } +} + #[cfg(feature = "alloc")] mod allocating { use super::*; @@ -210,4 +222,13 @@ mod allocating { } } } + + impl AsAlgorithmIdentifierRef for AlgorithmIdentifierOwned { + fn as_algo_ref<'a>(&'a self) -> AlgorithmIdentifierRef<'a> { + AlgorithmIdentifier { + oid: self.oid, + parameters: self.parameters.owned_to_ref(), + } + } + } } diff --git a/spki/src/lib.rs b/spki/src/lib.rs index e9acaee2d..c6f376cc8 100644 --- a/spki/src/lib.rs +++ b/spki/src/lib.rs @@ -40,7 +40,10 @@ mod traits; mod digest; pub use crate::{ - algorithm::{AlgorithmIdentifier, AlgorithmIdentifierRef, AlgorithmIdentifierWithOid}, + algorithm::{ + AlgorithmIdentifier, AlgorithmIdentifierRef, AlgorithmIdentifierWithOid, + AsAlgorithmIdentifierRef, + }, error::{Error, Result}, spki::{SubjectPublicKeyInfo, SubjectPublicKeyInfoRef}, traits::{AssociatedAlgorithmIdentifier, DecodePublicKey, SignatureAlgorithmIdentifier}, From e5b92d268aee471ee14fb9c3300e3b216a7b9ffd Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:35:40 +0200 Subject: [PATCH 06/14] pkcs1: simplify trait bounds on RsaOaepParams --- pkcs1/src/params.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs index ea90aa0e7..71eba0b81 100644 --- a/pkcs1/src/params.rs +++ b/pkcs1/src/params.rs @@ -228,7 +228,7 @@ impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> { /// Default Mask Generation Function (MGF): SHA-1. fn default_mgf1_sha1() -> AlgorithmIdentifier> where - AlgorithmIdentifier: From>>, + AlgorithmIdentifier: From>, { AlgorithmIdentifier::> { oid: OID_MGF_1, @@ -304,7 +304,7 @@ where impl RsaOaepParams where AlgorithmIdentifier: AsAlgorithmIdentifierRef, - AlgorithmIdentifier: From>>, + AlgorithmIdentifier: From>, Params: PartialEq, { fn context_specific_mask_gen( @@ -398,7 +398,6 @@ where for<'b> Option>>>: Encode, AlgorithmIdentifier: From>, - AlgorithmIdentifier: From>>, Params: PartialEq, { fn value_len(&self) -> der::Result { From d3d39b93d450aa18594c43c9ddf26ae3fd9194ac Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:44:49 +0200 Subject: [PATCH 07/14] pkcs1: workaround clippy redundant closure --- pkcs1/src/lib.rs | 3 ++- pkcs1/src/params.rs | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/pkcs1/src/lib.rs b/pkcs1/src/lib.rs index ae7045b3b..e3085d0c7 100644 --- a/pkcs1/src/lib.rs +++ b/pkcs1/src/lib.rs @@ -34,7 +34,7 @@ pub use der::{ pub use crate::{ error::{Error, Result}, - params::{RsaOaepParams, RsaOaepParamsOwned, RsaOaepParamsRef, RsaPssParams, TrailerField}, + params::{RsaOaepParams, RsaOaepParamsRef, RsaPssParams, TrailerField}, private_key::{RsaPrivateKey, RsaPrivateKeyRef}, public_key::{RsaPublicKey, RsaPublicKeyRef}, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, @@ -43,6 +43,7 @@ pub use crate::{ #[cfg(feature = "alloc")] pub use crate::{ + params::RsaOaepParamsOwned, private_key::{OtherPrimeInfos, RsaPrivateKeyOwned, other_prime_info::OtherPrimeInfo}, public_key::RsaPublicKeyOwned, traits::{EncodeRsaPrivateKey, EncodeRsaPublicKey}, diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs index 71eba0b81..cbc1dd79d 100644 --- a/pkcs1/src/params.rs +++ b/pkcs1/src/params.rs @@ -187,7 +187,12 @@ impl<'a> DecodeValue<'a> for RsaPssParams<'a> { .unwrap_or(SHA_1_AI), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? - .unwrap_or_else(|| default_mgf1_sha1::>()), + .unwrap_or_else(|| { + // workaround for clippy: warning: redundant closure: default_mgf1_sha1::>() + let algo_id: AlgorithmIdentifier> = + default_mgf1_sha1(); + algo_id + }), salt_len: reader .context_specific(TagNumber(2), TagMode::Explicit)? .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT), @@ -360,7 +365,7 @@ where fn default() -> Self { Self { hash: SHA_1_AI.into(), - mask_gen: default_mgf1_sha1().into(), + mask_gen: default_mgf1_sha1(), p_source: default_pempty_string().into(), } } @@ -383,7 +388,7 @@ where .unwrap_or(SHA_1_AI.into()), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? - .unwrap_or_else(|| default_mgf1_sha1().into()), + .unwrap_or_else(default_mgf1_sha1), p_source: reader .context_specific(TagNumber(2), TagMode::Explicit)? .unwrap_or_else(|| default_pempty_string().into()), From 4e76ca6484610763fb85a3f773305c9b101e013e Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:06:13 +0200 Subject: [PATCH 08/14] pkcs1: RsaPssParams generic Ref and Owned --- pkcs1/src/params.rs | 134 +++++++++++++++++++++++++++----------------- 1 file changed, 83 insertions(+), 51 deletions(-) diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs index cbc1dd79d..f955169dc 100644 --- a/pkcs1/src/params.rs +++ b/pkcs1/src/params.rs @@ -59,6 +59,9 @@ impl FixedTag for TrailerField { const TAG: Tag = Tag::Integer; } +/// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] +pub type RsaPssParamsRef<'a> = RsaPssParams>; + /// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] /// /// ASN.1 structure containing a serialized RSASSA-PSS parameters: @@ -75,12 +78,12 @@ impl FixedTag for TrailerField { /// /// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3 #[derive(Clone, Debug, Eq, PartialEq)] -pub struct RsaPssParams<'a> { +pub struct RsaPssParams { /// Hash Algorithm - pub hash: AlgorithmIdentifierRef<'a>, + pub hash: AlgorithmIdentifier, /// Mask Generation Function (MGF) - pub mask_gen: AlgorithmIdentifier>, + pub mask_gen: AlgorithmIdentifier>, /// Salt length pub salt_len: u8, @@ -89,11 +92,37 @@ pub struct RsaPssParams<'a> { pub trailer_field: TrailerField, } -impl<'a> RsaPssParams<'a> { +impl RsaPssParams { /// Default RSA PSS Salt length in RsaPssParams pub const SALT_LEN_DEFAULT: u8 = 20; - /// Create new RsaPssParams for the provided digest and salt len + fn context_specific_salt_len(&self) -> Option> { + if self.salt_len == Self::SALT_LEN_DEFAULT { + None + } else { + Some(ContextSpecificRef { + tag_number: TagNumber(2), + tag_mode: TagMode::Explicit, + value: &self.salt_len, + }) + } + } + + fn context_specific_trailer_field(&self) -> Option> { + if self.trailer_field == TrailerField::default() { + None + } else { + Some(ContextSpecificRef { + tag_number: TagNumber(3), + tag_mode: TagMode::Explicit, + value: &self.trailer_field, + }) + } + } +} + +impl<'a> RsaPssParamsRef<'a> { + /// Create new [`RsaPssParams`] for the provided digest and salt len pub fn new(salt_len: u8) -> Self where D: AssociatedOid, @@ -114,9 +143,16 @@ impl<'a> RsaPssParams<'a> { trailer_field: Default::default(), } } +} - fn context_specific_hash(&self) -> Option>> { - if self.hash == SHA_1_AI { +impl RsaPssParams +where + AlgorithmIdentifier: AsAlgorithmIdentifierRef, + AlgorithmIdentifier: From>>, + Params: PartialEq, +{ + fn context_specific_hash(&self) -> Option>> { + if self.hash.as_algo_ref() == SHA_1_AI { None } else { Some(ContextSpecificRef { @@ -129,8 +165,8 @@ impl<'a> RsaPssParams<'a> { fn context_specific_mask_gen( &self, - ) -> Option>>> { - if self.mask_gen == default_mgf1_sha1() { + ) -> Option>>> { + if self.mask_gen == default_mgf1_sha1::() { None } else { Some(ContextSpecificRef { @@ -140,62 +176,43 @@ impl<'a> RsaPssParams<'a> { }) } } - - fn context_specific_salt_len(&self) -> Option> { - if self.salt_len == RsaPssParams::SALT_LEN_DEFAULT { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber(2), - tag_mode: TagMode::Explicit, - value: &self.salt_len, - }) - } - } - - fn context_specific_trailer_field(&self) -> Option> { - if self.trailer_field == TrailerField::default() { - None - } else { - Some(ContextSpecificRef { - tag_number: TagNumber(3), - tag_mode: TagMode::Explicit, - value: &self.trailer_field, - }) - } - } } -impl Default for RsaPssParams<'_> { +impl Default for RsaPssParams +where + AlgorithmIdentifier: From>, +{ fn default() -> Self { Self { - hash: SHA_1_AI, + hash: SHA_1_AI.into(), mask_gen: default_mgf1_sha1(), - salt_len: RsaPssParams::SALT_LEN_DEFAULT, + salt_len: RsaPssParams::::SALT_LEN_DEFAULT, trailer_field: Default::default(), } } } -impl<'a> DecodeValue<'a> for RsaPssParams<'a> { +impl<'a, Params> DecodeValue<'a> for RsaPssParams +where + AlgorithmIdentifier: DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier>: + DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier: From>, + Params: 'a, +{ type Error = der::Error; fn decode_value>(reader: &mut R, _header: der::Header) -> der::Result { Ok(Self { hash: reader .context_specific(TagNumber(0), TagMode::Explicit)? - .unwrap_or(SHA_1_AI), + .unwrap_or_else(|| SHA_1_AI.into()), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? - .unwrap_or_else(|| { - // workaround for clippy: warning: redundant closure: default_mgf1_sha1::>() - let algo_id: AlgorithmIdentifier> = - default_mgf1_sha1(); - algo_id - }), + .unwrap_or_else(default_mgf1_sha1), salt_len: reader .context_specific(TagNumber(2), TagMode::Explicit)? - .unwrap_or(RsaPssParams::SALT_LEN_DEFAULT), + .unwrap_or(RsaPssParams::::SALT_LEN_DEFAULT), trailer_field: reader .context_specific(TagNumber(3), TagMode::Explicit)? .unwrap_or_default(), @@ -203,7 +220,15 @@ impl<'a> DecodeValue<'a> for RsaPssParams<'a> { } } -impl EncodeValue for RsaPssParams<'_> { +impl EncodeValue for RsaPssParams +where + AlgorithmIdentifier: AsAlgorithmIdentifierRef, + for<'b> Option>>: Encode, + for<'b> Option>>>: + Encode, + AlgorithmIdentifier: From>, + Params: PartialEq, +{ fn value_len(&self) -> der::Result { self.context_specific_hash().encoded_len()? + self.context_specific_mask_gen().encoded_len()? @@ -220,9 +245,16 @@ impl EncodeValue for RsaPssParams<'_> { } } -impl<'a> Sequence<'a> for RsaPssParams<'a> {} +impl<'a, Params> Sequence<'a> for RsaPssParams {} -impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> { +impl<'a, Params> TryFrom<&'a [u8]> for RsaPssParams +where + AlgorithmIdentifier: DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier>: + DecodeValue<'a, Error = der::Error> + FixedTag, + AlgorithmIdentifier: From>, + Params: 'a, +{ type Error = Error; fn try_from(bytes: &'a [u8]) -> Result { @@ -328,7 +360,7 @@ where } impl<'a> RsaOaepParamsRef<'a> { - /// Create new RsaPssParams for the provided digest and default (empty) label + /// Create new [`RsaOaepParams`] for the provided digest and default (empty) label pub fn new() -> Self where D: AssociatedOid, @@ -336,7 +368,7 @@ impl<'a> RsaOaepParamsRef<'a> { Self::new_with_label::(&[]) } - /// Create new RsaPssParams for the provided digest and specified label + /// Create new [`RsaOaepParams`] for the provided digest and specified label pub fn new_with_label(label: &'a impl AsRef<[u8]>) -> RsaOaepParamsRef<'a> where D: AssociatedOid, @@ -385,7 +417,7 @@ where Ok(Self { hash: reader .context_specific(TagNumber(0), TagMode::Explicit)? - .unwrap_or(SHA_1_AI.into()), + .unwrap_or_else(|| SHA_1_AI.into()), mask_gen: reader .context_specific(TagNumber(1), TagMode::Explicit)? .unwrap_or_else(default_mgf1_sha1), From fead111c91c645b45e3526414700165d836a940b Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:11:34 +0200 Subject: [PATCH 09/14] pkcs1: pub use RsaPssParamsRef, RsaPssParamsOwned --- pkcs1/src/lib.rs | 4 ++-- pkcs1/src/params.rs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pkcs1/src/lib.rs b/pkcs1/src/lib.rs index e3085d0c7..e2e20b289 100644 --- a/pkcs1/src/lib.rs +++ b/pkcs1/src/lib.rs @@ -34,7 +34,7 @@ pub use der::{ pub use crate::{ error::{Error, Result}, - params::{RsaOaepParams, RsaOaepParamsRef, RsaPssParams, TrailerField}, + params::{RsaOaepParams, RsaOaepParamsRef, RsaPssParams, RsaPssParamsRef, TrailerField}, private_key::{RsaPrivateKey, RsaPrivateKeyRef}, public_key::{RsaPublicKey, RsaPublicKeyRef}, traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, @@ -43,7 +43,7 @@ pub use crate::{ #[cfg(feature = "alloc")] pub use crate::{ - params::RsaOaepParamsOwned, + params::{RsaOaepParamsOwned, RsaPssParamsOwned}, private_key::{OtherPrimeInfos, RsaPrivateKeyOwned, other_prime_info::OtherPrimeInfo}, public_key::RsaPublicKeyOwned, traits::{EncodeRsaPrivateKey, EncodeRsaPublicKey}, diff --git a/pkcs1/src/params.rs b/pkcs1/src/params.rs index f955169dc..d3188e6a4 100644 --- a/pkcs1/src/params.rs +++ b/pkcs1/src/params.rs @@ -62,6 +62,10 @@ impl FixedTag for TrailerField { /// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] pub type RsaPssParamsRef<'a> = RsaPssParams>; +/// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] +#[cfg(feature = "alloc")] +pub type RsaPssParamsOwned = RsaPssParams; + /// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3] /// /// ASN.1 structure containing a serialized RSASSA-PSS parameters: From cd21a298a7bf8059a7da6cbe29bef4defeef007e Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:37:27 +0200 Subject: [PATCH 10/14] fix *Owned type trait bounds --- pkcs1/tests/params.rs | 40 +++++++++++++++++++++++++++++++++------- spki/src/algorithm.rs | 18 ++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/pkcs1/tests/params.rs b/pkcs1/tests/params.rs index a6598b873..32694f9ae 100644 --- a/pkcs1/tests/params.rs +++ b/pkcs1/tests/params.rs @@ -7,7 +7,7 @@ use der::{ oid::AssociatedOid, }; use hex_literal::hex; -use pkcs1::{RsaOaepParamsRef, RsaPssParams, TrailerField}; +use pkcs1::{RsaOaepParamsRef, RsaPssParamsRef, TrailerField}; /// Default PSS parameters using all default values (SHA1, MGF1) const RSA_PSS_PARAMETERS_DEFAULTS: &[u8] = &hex!("3000"); @@ -35,7 +35,7 @@ impl AssociatedOid for Sha256Mock { #[test] fn decode_pss_param() { - let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); + let param = RsaPssParamsRef::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); assert!( param @@ -65,7 +65,7 @@ fn decode_pss_param() { #[test] fn encode_pss_param() { let mut buf = [0_u8; 256]; - let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); + let param = RsaPssParamsRef::try_from(RSA_PSS_PARAMETERS_SHA2_256).unwrap(); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_SHA2_256 @@ -74,7 +74,7 @@ fn encode_pss_param() { #[test] fn decode_pss_param_default() { - let param = RsaPssParams::try_from(RSA_PSS_PARAMETERS_DEFAULTS).unwrap(); + let param = RsaPssParamsRef::try_from(RSA_PSS_PARAMETERS_DEFAULTS).unwrap(); assert!( param @@ -110,7 +110,9 @@ fn decode_pss_param_default() { fn encode_pss_param_default() { let mut buf = [0_u8; 256]; assert_eq!( - RsaPssParams::default().encode_to_slice(&mut buf).unwrap(), + RsaPssParamsRef::default() + .encode_to_slice(&mut buf) + .unwrap(), RSA_PSS_PARAMETERS_DEFAULTS ); } @@ -119,13 +121,13 @@ fn encode_pss_param_default() { fn new_pss_param() { let mut buf = [0_u8; 256]; - let param = RsaPssParams::new::(20); + let param = RsaPssParamsRef::new::(20); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_DEFAULTS ); - let param = RsaPssParams::new::(32); + let param = RsaPssParamsRef::new::(32); assert_eq!( param.encode_to_slice(&mut buf).unwrap(), RSA_PSS_PARAMETERS_SHA2_256 @@ -259,3 +261,27 @@ fn new_oaep_param() { RSA_OAEP_PARAMETERS_SHA2_256 ); } + +#[cfg(feature = "alloc")] +mod test_alloc_trait_bounds { + use der::{Decode, Encode}; + use pkcs1::{RsaOaepParamsOwned, RsaPssParamsOwned}; + + #[test] + fn rsapssparamsowned_trait_bounds_from_der() { + let _ = RsaPssParamsOwned::from_der(&[]); + } + #[test] + fn rsapssparamsowned_trait_bounds_to_der() { + let _ = RsaPssParamsOwned::default().encode_to_slice(&mut []); + } + + #[test] + fn rsaoaepparamsowned_trait_bounds_from_der() { + let _ = RsaOaepParamsOwned::from_der(&[]); + } + #[test] + fn rsaoaepparamsowned_trait_bounds_to_der() { + let _ = RsaOaepParamsOwned::default().encode_to_slice(&mut []); + } +} diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index 0a76322d7..85c7916d2 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -98,6 +98,24 @@ pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier; #[cfg(feature = "alloc")] pub type AlgorithmIdentifierOwned = AlgorithmIdentifier; +impl<'a> From> for AlgorithmIdentifierOwned { + fn from(value: AlgorithmIdentifierRef) -> Self { + Self { + oid: value.oid, + parameters: value.parameters.map(|p| p.into()), + } + } +} + +// impl<'a> From<&'a AlgorithmIdentifierOwned> for AlgorithmIdentifierRef { +// fn from(value: AlgorithmIdentifierRef) -> Self { +// Self { +// oid: value.oid, +// parameters: value.parameters.map(|p| p.into()), +// } +// } +// } + impl AlgorithmIdentifier { /// Assert the `algorithm` OID is an expected value. /// From 00038c3afc1259ec5e771181486c9ad3faa0cf0c Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:39:45 +0200 Subject: [PATCH 11/14] spki: AlgorithmIdentifier conversion between Ref and Owned --- spki/src/algorithm.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index 85c7916d2..f7feb7348 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -98,24 +98,6 @@ pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier; #[cfg(feature = "alloc")] pub type AlgorithmIdentifierOwned = AlgorithmIdentifier; -impl<'a> From> for AlgorithmIdentifierOwned { - fn from(value: AlgorithmIdentifierRef) -> Self { - Self { - oid: value.oid, - parameters: value.parameters.map(|p| p.into()), - } - } -} - -// impl<'a> From<&'a AlgorithmIdentifierOwned> for AlgorithmIdentifierRef { -// fn from(value: AlgorithmIdentifierRef) -> Self { -// Self { -// oid: value.oid, -// parameters: value.parameters.map(|p| p.into()), -// } -// } -// } - impl AlgorithmIdentifier { /// Assert the `algorithm` OID is an expected value. /// @@ -204,6 +186,24 @@ impl<'a> AlgorithmIdentifierRef<'a> { } } +impl<'a> From> for AlgorithmIdentifierOwned { + fn from(value: AlgorithmIdentifierRef) -> Self { + Self { + oid: value.oid, + parameters: value.parameters.map(|p| p.into()), + } + } +} + +impl<'a> From<&'a AlgorithmIdentifierOwned> for AlgorithmIdentifierRef<'a> { + fn from(value: &'a AlgorithmIdentifierOwned) -> Self { + Self { + oid: value.oid, + parameters: value.parameters.as_ref().map(|p| p.to_ref()), + } + } +} + /// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. pub trait AsAlgorithmIdentifierRef { /// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. From f2ba01d8be2398acd430d24a715bbfc3b96bc93f Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:46:48 +0200 Subject: [PATCH 12/14] spki: cfg(feature = alloc) AlgorithmIdentifierOwned --- spki/src/algorithm.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index f7feb7348..9691e0e02 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -186,24 +186,6 @@ impl<'a> AlgorithmIdentifierRef<'a> { } } -impl<'a> From> for AlgorithmIdentifierOwned { - fn from(value: AlgorithmIdentifierRef) -> Self { - Self { - oid: value.oid, - parameters: value.parameters.map(|p| p.into()), - } - } -} - -impl<'a> From<&'a AlgorithmIdentifierOwned> for AlgorithmIdentifierRef<'a> { - fn from(value: &'a AlgorithmIdentifierOwned) -> Self { - Self { - oid: value.oid, - parameters: value.parameters.as_ref().map(|p| p.to_ref()), - } - } -} - /// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. pub trait AsAlgorithmIdentifierRef { /// Borrow the owned or ref `AlgorithmIdentifier` as [`AlgorithmIdentifierRef`]. @@ -249,4 +231,22 @@ mod allocating { } } } + + impl<'a> From> for AlgorithmIdentifierOwned { + fn from(value: AlgorithmIdentifierRef) -> Self { + Self { + oid: value.oid, + parameters: value.parameters.map(|p| p.into()), + } + } + } + + impl<'a> From<&'a AlgorithmIdentifierOwned> for AlgorithmIdentifierRef<'a> { + fn from(value: &'a AlgorithmIdentifierOwned) -> Self { + Self { + oid: value.oid, + parameters: value.parameters.as_ref().map(|p| p.to_ref()), + } + } + } } From 86568c18ac668865277ddd9bdb15c814e77136dd Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 00:57:20 +0200 Subject: [PATCH 13/14] pkcs1: alloc feature forward to spki/alloc --- pkcs1/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkcs1/Cargo.toml b/pkcs1/Cargo.toml index d551fa3e0..0708eb4b9 100644 --- a/pkcs1/Cargo.toml +++ b/pkcs1/Cargo.toml @@ -25,7 +25,7 @@ hex-literal = "1" tempfile = "3" [features] -alloc = ["der/alloc", "zeroize"] +alloc = ["der/alloc", "spki/alloc", "zeroize"] std = ["der/std", "alloc"] pem = ["alloc", "der/pem"] From d49ab23f618228a38164032e33e7e50510ffbc2b Mon Sep 17 00:00:00 2001 From: dishmaker <141624503+dishmaker@users.noreply.github.com> Date: Sun, 30 Aug 2026 01:02:14 +0200 Subject: [PATCH 14/14] spki: fix clippy --- spki/src/algorithm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spki/src/algorithm.rs b/spki/src/algorithm.rs index 9691e0e02..d74a501a6 100644 --- a/spki/src/algorithm.rs +++ b/spki/src/algorithm.rs @@ -236,7 +236,7 @@ mod allocating { fn from(value: AlgorithmIdentifierRef) -> Self { Self { oid: value.oid, - parameters: value.parameters.map(|p| p.into()), + parameters: value.parameters.map(Into::into), } } }