chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

95
vendor/pkcs1/src/error.rs vendored Normal file
View File

@@ -0,0 +1,95 @@
//! Error types
use core::fmt;
#[cfg(feature = "pem")]
use der::pem;
/// Result type
pub type Result<T> = core::result::Result<T, Error>;
/// Error type
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum Error {
/// ASN.1 DER-related errors.
Asn1(der::Error),
/// Cryptographic errors.
///
/// These can be used by RSA implementations to signal that a key is
/// invalid for cryptographic reasons. This means the document parsed
/// correctly, but one of the values contained within was invalid, e.g.
/// a number expected to be a prime was not a prime.
Crypto,
/// PKCS#8 errors.
#[cfg(feature = "pkcs8")]
Pkcs8(pkcs8::Error),
/// Version errors
Version,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Asn1(err) => write!(f, "PKCS#1 ASN.1 error: {}", err),
Error::Crypto => f.write_str("PKCS#1 cryptographic error"),
#[cfg(feature = "pkcs8")]
Error::Pkcs8(err) => write!(f, "{}", err),
Error::Version => f.write_str("PKCS#1 version error"),
}
}
}
impl From<der::Error> for Error {
fn from(err: der::Error) -> Error {
Error::Asn1(err)
}
}
#[cfg(feature = "pem")]
impl From<pem::Error> for Error {
fn from(err: pem::Error) -> Error {
der::Error::from(err).into()
}
}
#[cfg(feature = "pkcs8")]
impl From<Error> for pkcs8::Error {
fn from(err: Error) -> pkcs8::Error {
match err {
Error::Asn1(e) => pkcs8::Error::Asn1(e),
Error::Crypto | Error::Version => pkcs8::Error::KeyMalformed,
Error::Pkcs8(e) => e,
}
}
}
#[cfg(feature = "pkcs8")]
impl From<pkcs8::Error> for Error {
fn from(err: pkcs8::Error) -> Error {
Error::Pkcs8(err)
}
}
#[cfg(feature = "pkcs8")]
impl From<Error> for pkcs8::spki::Error {
fn from(err: Error) -> pkcs8::spki::Error {
match err {
Error::Asn1(e) => pkcs8::spki::Error::Asn1(e),
_ => pkcs8::spki::Error::KeyMalformed,
}
}
}
#[cfg(feature = "pkcs8")]
impl From<pkcs8::spki::Error> for Error {
fn from(err: pkcs8::spki::Error) -> Error {
Error::Pkcs8(pkcs8::Error::PublicKey(err))
}
}
#[cfg(feature = "std")]
impl std::error::Error for Error {}

62
vendor/pkcs1/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,62 @@
#![no_std]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![doc = include_str!("../README.md")]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
)]
#![forbid(unsafe_code)]
#![warn(
clippy::mod_module_files,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod error;
mod params;
mod private_key;
mod public_key;
mod traits;
mod version;
pub use der::{
self,
asn1::{ObjectIdentifier, UintRef},
};
pub use crate::{
error::{Error, Result},
params::{RsaOaepParams, RsaPssParams, TrailerField},
private_key::RsaPrivateKey,
public_key::RsaPublicKey,
traits::{DecodeRsaPrivateKey, DecodeRsaPublicKey},
version::Version,
};
#[cfg(feature = "alloc")]
pub use crate::{
private_key::{other_prime_info::OtherPrimeInfo, OtherPrimeInfos},
traits::{EncodeRsaPrivateKey, EncodeRsaPublicKey},
};
#[cfg(feature = "pem")]
pub use der::pem::{self, LineEnding};
/// `rsaEncryption` Object Identifier (OID)
#[cfg(feature = "pkcs8")]
pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.1");
/// `AlgorithmIdentifier` for RSA.
#[cfg(feature = "pkcs8")]
pub const ALGORITHM_ID: pkcs8::AlgorithmIdentifierRef<'static> = pkcs8::AlgorithmIdentifierRef {
oid: ALGORITHM_OID,
parameters: Some(der::asn1::AnyRef::NULL),
};

399
vendor/pkcs1/src/params.rs vendored Normal file
View File

@@ -0,0 +1,399 @@
//! PKCS#1 RSA parameters.
use crate::{Error, Result};
use der::{
asn1::{AnyRef, ContextSpecificRef, ObjectIdentifier},
oid::AssociatedOid,
Decode, DecodeValue, Encode, EncodeValue, FixedTag, Length, Reader, Sequence, Tag, TagMode,
TagNumber, Writer,
};
use spki::{AlgorithmIdentifier, AlgorithmIdentifierRef};
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");
const OID_PSPECIFIED: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.9");
const SHA_1_AI: AlgorithmIdentifierRef<'_> = AlgorithmIdentifierRef {
oid: OID_SHA_1,
parameters: Some(AnyRef::NULL),
};
/// `TrailerField` as defined in [RFC 8017 Appendix 2.3].
/// ```text
/// TrailerField ::= INTEGER { trailerFieldBC(1) }
/// ```
/// [RFC 8017 Appendix 2.3]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3
#[derive(Clone, Debug, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum TrailerField {
/// the only supported value (0xbc, default)
BC = 1,
}
impl Default for TrailerField {
fn default() -> Self {
Self::BC
}
}
impl<'a> DecodeValue<'a> for TrailerField {
fn decode_value<R: Reader<'a>>(decoder: &mut R, header: der::Header) -> der::Result<Self> {
match u8::decode_value(decoder, header)? {
1 => Ok(TrailerField::BC),
_ => Err(Self::TAG.value_error()),
}
}
}
impl EncodeValue for TrailerField {
fn value_len(&self) -> der::Result<Length> {
Ok(Length::ONE)
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
(*self as u8).encode_value(writer)
}
}
impl FixedTag for TrailerField {
const TAG: Tag = Tag::Integer;
}
/// PKCS#1 RSASSA-PSS parameters as defined in [RFC 8017 Appendix 2.3]
///
/// ASN.1 structure containing a serialized RSASSA-PSS parameters:
/// ```text
/// RSASSA-PSS-params ::= SEQUENCE {
/// hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
/// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
/// saltLength [2] INTEGER DEFAULT 20,
/// trailerField [3] TrailerField DEFAULT trailerFieldBC
/// }
/// HashAlgorithm ::= AlgorithmIdentifier
/// MaskGenAlgorithm ::= AlgorithmIdentifier
/// ```
///
/// [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> {
/// Hash Algorithm
pub hash: AlgorithmIdentifierRef<'a>,
/// Mask Generation Function (MGF)
pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>,
/// Salt length
pub salt_len: u8,
/// Trailer field (i.e. [`TrailerField::BC`])
pub trailer_field: TrailerField,
}
impl<'a> RsaPssParams<'a> {
/// Default RSA PSS Salt length in RsaPssParams
pub const SALT_LEN_DEFAULT: u8 = 20;
/// Create new RsaPssParams for the provided digest and salt len
pub fn new<D>(salt_len: 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),
}),
},
salt_len,
trailer_field: Default::default(),
}
}
fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
if self.hash == SHA_1_AI {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N0,
tag_mode: TagMode::Explicit,
value: &self.hash,
})
}
}
fn context_specific_mask_gen(
&self,
) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>> {
if self.mask_gen == default_mgf1_sha1() {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N1,
tag_mode: TagMode::Explicit,
value: &self.mask_gen,
})
}
}
fn context_specific_salt_len(&self) -> Option<ContextSpecificRef<'_, u8>> {
if self.salt_len == RsaPssParams::SALT_LEN_DEFAULT {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N2,
tag_mode: TagMode::Explicit,
value: &self.salt_len,
})
}
}
fn context_specific_trailer_field(&self) -> Option<ContextSpecificRef<'_, TrailerField>> {
if self.trailer_field == TrailerField::default() {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N3,
tag_mode: TagMode::Explicit,
value: &self.trailer_field,
})
}
}
}
impl<'a> Default for RsaPssParams<'a> {
fn default() -> Self {
Self {
hash: SHA_1_AI,
mask_gen: default_mgf1_sha1(),
salt_len: RsaPssParams::SALT_LEN_DEFAULT,
trailer_field: Default::default(),
}
}
}
impl<'a> DecodeValue<'a> for RsaPssParams<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
hash: reader
.context_specific(TagNumber::N0, TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber::N1, TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
salt_len: reader
.context_specific(TagNumber::N2, TagMode::Explicit)?
.unwrap_or(RsaPssParams::SALT_LEN_DEFAULT),
trailer_field: reader
.context_specific(TagNumber::N3, TagMode::Explicit)?
.unwrap_or_default(),
})
})
}
}
impl EncodeValue for RsaPssParams<'_> {
fn value_len(&self) -> der::Result<Length> {
self.context_specific_hash().encoded_len()?
+ self.context_specific_mask_gen().encoded_len()?
+ self.context_specific_salt_len().encoded_len()?
+ self.context_specific_trailer_field().encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.context_specific_hash().encode(writer)?;
self.context_specific_mask_gen().encode(writer)?;
self.context_specific_salt_len().encode(writer)?;
self.context_specific_trailer_field().encode(writer)?;
Ok(())
}
}
impl<'a> Sequence<'a> for RsaPssParams<'a> {}
impl<'a> TryFrom<&'a [u8]> for RsaPssParams<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
}
/// Default Mask Generation Function (MGF): SHA-1.
fn default_mgf1_sha1<'a>() -> AlgorithmIdentifier<AlgorithmIdentifierRef<'a>> {
AlgorithmIdentifier::<AlgorithmIdentifierRef<'a>> {
oid: OID_MGF_1,
parameters: Some(SHA_1_AI),
}
}
/// PKCS#1 RSAES-OAEP parameters as defined in [RFC 8017 Appendix 2.1]
///
/// ASN.1 structure containing a serialized RSAES-OAEP parameters:
/// ```text
/// RSAES-OAEP-params ::= SEQUENCE {
/// hashAlgorithm [0] HashAlgorithm DEFAULT sha1,
/// maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1,
/// pSourceAlgorithm [2] PSourceAlgorithm DEFAULT pSpecifiedEmpty
/// }
/// HashAlgorithm ::= AlgorithmIdentifier
/// MaskGenAlgorithm ::= AlgorithmIdentifier
/// PSourceAlgorithm ::= 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> {
/// Hash Algorithm
pub hash: AlgorithmIdentifierRef<'a>,
/// Mask Generation Function (MGF)
pub mask_gen: AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>,
/// The source (and possibly the value) of the label L
pub p_source: AlgorithmIdentifierRef<'a>,
}
impl<'a> RsaOaepParams<'a> {
/// Create new RsaPssParams for the provided digest and default (empty) label
pub fn new<D>() -> Self
where
D: AssociatedOid,
{
Self::new_with_label::<D>(&[])
}
/// Create new RsaPssParams for the provided digest and specified label
pub fn new_with_label<D>(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: pspecicied_algorithm_identifier(label),
}
}
fn context_specific_hash(&self) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
if self.hash == SHA_1_AI {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N0,
tag_mode: TagMode::Explicit,
value: &self.hash,
})
}
}
fn context_specific_mask_gen(
&self,
) -> Option<ContextSpecificRef<'_, AlgorithmIdentifier<AlgorithmIdentifierRef<'a>>>> {
if self.mask_gen == default_mgf1_sha1() {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N1,
tag_mode: TagMode::Explicit,
value: &self.mask_gen,
})
}
}
fn context_specific_p_source(
&self,
) -> Option<ContextSpecificRef<'_, AlgorithmIdentifierRef<'a>>> {
if self.p_source == default_pempty_string() {
None
} else {
Some(ContextSpecificRef {
tag_number: TagNumber::N2,
tag_mode: TagMode::Explicit,
value: &self.p_source,
})
}
}
}
impl<'a> Default for RsaOaepParams<'a> {
fn default() -> Self {
Self {
hash: SHA_1_AI,
mask_gen: default_mgf1_sha1(),
p_source: default_pempty_string(),
}
}
}
impl<'a> DecodeValue<'a> for RsaOaepParams<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
hash: reader
.context_specific(TagNumber::N0, TagMode::Explicit)?
.unwrap_or(SHA_1_AI),
mask_gen: reader
.context_specific(TagNumber::N1, TagMode::Explicit)?
.unwrap_or_else(default_mgf1_sha1),
p_source: reader
.context_specific(TagNumber::N2, TagMode::Explicit)?
.unwrap_or_else(default_pempty_string),
})
})
}
}
impl EncodeValue for RsaOaepParams<'_> {
fn value_len(&self) -> der::Result<Length> {
self.context_specific_hash().encoded_len()?
+ self.context_specific_mask_gen().encoded_len()?
+ self.context_specific_p_source().encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.context_specific_hash().encode(writer)?;
self.context_specific_mask_gen().encode(writer)?;
self.context_specific_p_source().encode(writer)?;
Ok(())
}
}
impl<'a> Sequence<'a> for RsaOaepParams<'a> {}
impl<'a> TryFrom<&'a [u8]> for RsaOaepParams<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
}
fn pspecicied_algorithm_identifier(label: &impl AsRef<[u8]>) -> AlgorithmIdentifierRef<'_> {
AlgorithmIdentifierRef {
oid: OID_PSPECIFIED,
parameters: Some(
AnyRef::new(Tag::OctetString, label.as_ref()).expect("error creating OAEP params"),
),
}
}
/// Default Source Algorithm, empty string
fn default_pempty_string<'a>() -> AlgorithmIdentifierRef<'a> {
pspecicied_algorithm_identifier(&[])
}

247
vendor/pkcs1/src/private_key.rs vendored Normal file
View File

@@ -0,0 +1,247 @@
//! PKCS#1 RSA Private Keys.
#[cfg(feature = "alloc")]
pub(crate) mod other_prime_info;
use crate::{Error, Result, RsaPublicKey, Version};
use core::fmt;
use der::{
asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag,
Writer,
};
#[cfg(feature = "alloc")]
use {self::other_prime_info::OtherPrimeInfo, alloc::vec::Vec, der::SecretDocument};
#[cfg(feature = "pem")]
use der::pem::PemLabel;
/// PKCS#1 RSA Private Keys as defined in [RFC 8017 Appendix 1.2].
///
/// ASN.1 structure containing a serialized RSA private key:
///
/// ```text
/// RSAPrivateKey ::= SEQUENCE {
/// version Version,
/// modulus INTEGER, -- n
/// publicExponent INTEGER, -- e
/// privateExponent INTEGER, -- d
/// prime1 INTEGER, -- p
/// prime2 INTEGER, -- q
/// exponent1 INTEGER, -- d mod (p-1)
/// exponent2 INTEGER, -- d mod (q-1)
/// coefficient INTEGER, -- (inverse of q) mod p
/// otherPrimeInfos OtherPrimeInfos OPTIONAL
/// }
/// ```
///
/// Note: the `version` field is selected automatically based on the absence or
/// presence of the `other_prime_infos` field.
///
/// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2
#[derive(Clone)]
pub struct RsaPrivateKey<'a> {
/// `n`: RSA modulus.
pub modulus: UintRef<'a>,
/// `e`: RSA public exponent.
pub public_exponent: UintRef<'a>,
/// `d`: RSA private exponent.
pub private_exponent: UintRef<'a>,
/// `p`: first prime factor of `n`.
pub prime1: UintRef<'a>,
/// `q`: Second prime factor of `n`.
pub prime2: UintRef<'a>,
/// First exponent: `d mod (p-1)`.
pub exponent1: UintRef<'a>,
/// Second exponent: `d mod (q-1)`.
pub exponent2: UintRef<'a>,
/// CRT coefficient: `(inverse of q) mod p`.
pub coefficient: UintRef<'a>,
/// 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<OtherPrimeInfos<'a>>,
}
impl<'a> RsaPrivateKey<'a> {
/// 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,
}
}
/// Get the [`Version`] for this key.
///
/// Determined by the presence or absence of the
/// [`RsaPrivateKey::other_prime_infos`] field.
pub fn version(&self) -> Version {
if self.other_prime_infos.is_some() {
Version::Multi
} else {
Version::TwoPrime
}
}
}
impl<'a> DecodeValue<'a> for RsaPrivateKey<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
let version = Version::decode(reader)?;
let result = Self {
modulus: reader.decode()?,
public_exponent: reader.decode()?,
private_exponent: reader.decode()?,
prime1: reader.decode()?,
prime2: reader.decode()?,
exponent1: reader.decode()?,
exponent2: reader.decode()?,
coefficient: reader.decode()?,
other_prime_infos: reader.decode()?,
};
// Ensure version is set correctly for two-prime vs multi-prime key.
if version.is_multi() != result.other_prime_infos.is_some() {
return Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }));
}
Ok(result)
})
}
}
impl EncodeValue for RsaPrivateKey<'_> {
fn value_len(&self) -> der::Result<Length> {
self.version().encoded_len()?
+ self.modulus.encoded_len()?
+ self.public_exponent.encoded_len()?
+ self.private_exponent.encoded_len()?
+ self.prime1.encoded_len()?
+ self.prime2.encoded_len()?
+ self.exponent1.encoded_len()?
+ self.exponent2.encoded_len()?
+ self.coefficient.encoded_len()?
+ self.other_prime_infos.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.version().encode(writer)?;
self.modulus.encode(writer)?;
self.public_exponent.encode(writer)?;
self.private_exponent.encode(writer)?;
self.prime1.encode(writer)?;
self.prime2.encode(writer)?;
self.exponent1.encode(writer)?;
self.exponent2.encode(writer)?;
self.coefficient.encode(writer)?;
self.other_prime_infos.encode(writer)?;
Ok(())
}
}
impl<'a> Sequence<'a> for RsaPrivateKey<'a> {}
impl<'a> From<RsaPrivateKey<'a>> for RsaPublicKey<'a> {
fn from(private_key: RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
private_key.public_key()
}
}
impl<'a> From<&RsaPrivateKey<'a>> for RsaPublicKey<'a> {
fn from(private_key: &RsaPrivateKey<'a>) -> RsaPublicKey<'a> {
private_key.public_key()
}
}
impl<'a> TryFrom<&'a [u8]> for RsaPrivateKey<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
}
impl fmt::Debug for RsaPrivateKey<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RsaPrivateKey")
.field("version", &self.version())
.field("modulus", &self.modulus)
.field("public_exponent", &self.public_exponent)
.finish_non_exhaustive()
}
}
#[cfg(feature = "alloc")]
impl TryFrom<RsaPrivateKey<'_>> for SecretDocument {
type Error = Error;
fn try_from(private_key: RsaPrivateKey<'_>) -> Result<SecretDocument> {
SecretDocument::try_from(&private_key)
}
}
#[cfg(feature = "alloc")]
impl TryFrom<&RsaPrivateKey<'_>> for SecretDocument {
type Error = Error;
fn try_from(private_key: &RsaPrivateKey<'_>) -> Result<SecretDocument> {
Ok(Self::encode_msg(private_key)?)
}
}
#[cfg(feature = "pem")]
impl PemLabel for RsaPrivateKey<'_> {
const PEM_LABEL: &'static str = "RSA PRIVATE KEY";
}
/// Placeholder struct for `OtherPrimeInfos` in the no-`alloc` case.
///
/// This type is unconstructable by design, but supports the same traits.
#[cfg(not(feature = "alloc"))]
#[derive(Clone)]
#[non_exhaustive]
pub struct OtherPrimeInfos<'a> {
_lifetime: core::marker::PhantomData<&'a ()>,
}
#[cfg(not(feature = "alloc"))]
impl<'a> DecodeValue<'a> for OtherPrimeInfos<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, _header: Header) -> der::Result<Self> {
// Placeholder decoder that always returns an error.
// Uses `Tag::Integer` to signal an unsupported version.
Err(reader.error(der::ErrorKind::Value { tag: Tag::Integer }))
}
}
#[cfg(not(feature = "alloc"))]
impl EncodeValue for OtherPrimeInfos<'_> {
fn value_len(&self) -> der::Result<Length> {
// Placeholder decoder that always returns an error.
// Uses `Tag::Integer` to signal an unsupported version.
Err(der::ErrorKind::Value { tag: Tag::Integer }.into())
}
fn encode_value(&self, _writer: &mut impl Writer) -> der::Result<()> {
// Placeholder decoder that always returns an error.
// Uses `Tag::Integer` to signal an unsupported version.
Err(der::ErrorKind::Value { tag: Tag::Integer }.into())
}
}
#[cfg(not(feature = "alloc"))]
impl<'a> der::FixedTag for OtherPrimeInfos<'a> {
const TAG: Tag = Tag::Sequence;
}
/// Additional RSA prime info in a multi-prime RSA key.
#[cfg(feature = "alloc")]
pub type OtherPrimeInfos<'a> = Vec<OtherPrimeInfo<'a>>;

View File

@@ -0,0 +1,57 @@
//! PKCS#1 OtherPrimeInfo support.
use der::{
asn1::UintRef, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Writer,
};
/// PKCS#1 OtherPrimeInfo as defined in [RFC 8017 Appendix 1.2].
///
/// ASN.1 structure containing an additional prime in a multi-prime RSA key.
///
/// ```text
/// OtherPrimeInfo ::= SEQUENCE {
/// prime INTEGER, -- ri
/// exponent INTEGER, -- di
/// coefficient INTEGER -- ti
/// }
/// ```
///
/// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2
#[derive(Clone)]
pub struct OtherPrimeInfo<'a> {
/// Prime factor `r_i` of `n`, where `i` >= 3.
pub prime: UintRef<'a>,
/// Exponent: `d_i = d mod (r_i - 1)`.
pub exponent: UintRef<'a>,
/// CRT coefficient: `t_i = (r_1 * r_2 * ... * r_(i-1))^(-1) mod r_i`.
pub coefficient: UintRef<'a>,
}
impl<'a> DecodeValue<'a> for OtherPrimeInfo<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
prime: reader.decode()?,
exponent: reader.decode()?,
coefficient: reader.decode()?,
})
})
}
}
impl EncodeValue for OtherPrimeInfo<'_> {
fn value_len(&self) -> der::Result<Length> {
self.prime.encoded_len()? + self.exponent.encoded_len()? + self.coefficient.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.prime.encode(writer)?;
self.exponent.encode(writer)?;
self.coefficient.encode(writer)?;
Ok(())
}
}
impl<'a> Sequence<'a> for OtherPrimeInfo<'a> {}

90
vendor/pkcs1/src/public_key.rs vendored Normal file
View File

@@ -0,0 +1,90 @@
//! PKCS#1 RSA Public Keys.
use crate::{Error, Result};
use der::{
asn1::UintRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence,
Writer,
};
#[cfg(feature = "alloc")]
use der::Document;
#[cfg(feature = "pem")]
use der::pem::PemLabel;
/// PKCS#1 RSA Public Keys as defined in [RFC 8017 Appendix 1.1].
///
/// ASN.1 structure containing a serialized RSA public key:
///
/// ```text
/// RSAPublicKey ::= SEQUENCE {
/// modulus INTEGER, -- n
/// publicExponent INTEGER -- e
/// }
/// ```
///
/// [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> {
/// `n`: RSA modulus
pub modulus: UintRef<'a>,
/// `e`: RSA public exponent
pub public_exponent: UintRef<'a>,
}
impl<'a> DecodeValue<'a> for RsaPublicKey<'a> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
modulus: reader.decode()?,
public_exponent: reader.decode()?,
})
})
}
}
impl EncodeValue for RsaPublicKey<'_> {
fn value_len(&self) -> der::Result<Length> {
self.modulus.encoded_len()? + self.public_exponent.encoded_len()?
}
fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
self.modulus.encode(writer)?;
self.public_exponent.encode(writer)?;
Ok(())
}
}
impl<'a> Sequence<'a> for RsaPublicKey<'a> {}
impl<'a> TryFrom<&'a [u8]> for RsaPublicKey<'a> {
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
}
#[cfg(feature = "alloc")]
impl TryFrom<RsaPublicKey<'_>> for Document {
type Error = Error;
fn try_from(spki: RsaPublicKey<'_>) -> Result<Document> {
Self::try_from(&spki)
}
}
#[cfg(feature = "alloc")]
impl TryFrom<&RsaPublicKey<'_>> for Document {
type Error = Error;
fn try_from(spki: &RsaPublicKey<'_>) -> Result<Document> {
Ok(Self::encode_msg(spki)?)
}
}
#[cfg(feature = "pem")]
impl PemLabel for RsaPublicKey<'_> {
const PEM_LABEL: &'static str = "RSA PUBLIC KEY";
}

202
vendor/pkcs1/src/traits.rs vendored Normal file
View File

@@ -0,0 +1,202 @@
//! Traits for parsing objects from PKCS#1 encoded documents
use crate::Result;
#[cfg(feature = "alloc")]
use der::{Document, SecretDocument};
#[cfg(feature = "pem")]
use {
crate::LineEnding,
alloc::string::String,
der::{pem::PemLabel, zeroize::Zeroizing},
};
#[cfg(feature = "pkcs8")]
use {
crate::{ALGORITHM_ID, ALGORITHM_OID},
der::asn1::BitStringRef,
};
#[cfg(feature = "std")]
use std::path::Path;
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
use der::Decode;
#[cfg(all(feature = "alloc", any(feature = "pem", feature = "pkcs8")))]
use crate::{RsaPrivateKey, RsaPublicKey};
/// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document.
pub trait DecodeRsaPrivateKey: Sized {
/// Deserialize PKCS#1 private key from ASN.1 DER-encoded data
/// (binary format).
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;
/// Deserialize PKCS#1-encoded private key from PEM.
///
/// Keys in this format begin with the following:
///
/// ```text
/// -----BEGIN RSA PRIVATE KEY-----
/// ```
#[cfg(feature = "pem")]
fn from_pkcs1_pem(s: &str) -> Result<Self> {
let (label, doc) = SecretDocument::from_pem(s)?;
RsaPrivateKey::validate_pem_label(label)?;
Self::from_pkcs1_der(doc.as_bytes())
}
/// Load PKCS#1 private key from an ASN.1 DER-encoded file on the local
/// filesystem (binary format).
#[cfg(feature = "std")]
fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
Self::from_pkcs1_der(SecretDocument::read_der_file(path)?.as_bytes())
}
/// Load PKCS#1 private key from a PEM-encoded file on the local filesystem.
#[cfg(all(feature = "pem", feature = "std"))]
fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
let (label, doc) = SecretDocument::read_pem_file(path)?;
RsaPrivateKey::validate_pem_label(&label)?;
Self::from_pkcs1_der(doc.as_bytes())
}
}
/// Parse a [`RsaPublicKey`] from a PKCS#1-encoded document.
pub trait DecodeRsaPublicKey: Sized {
/// Deserialize object from ASN.1 DER-encoded [`RsaPublicKey`]
/// (binary format).
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;
/// Deserialize PEM-encoded [`RsaPublicKey`].
///
/// Keys in this format begin with the following:
///
/// ```text
/// -----BEGIN RSA PUBLIC KEY-----
/// ```
#[cfg(feature = "pem")]
fn from_pkcs1_pem(s: &str) -> Result<Self> {
let (label, doc) = Document::from_pem(s)?;
RsaPublicKey::validate_pem_label(label)?;
Self::from_pkcs1_der(doc.as_bytes())
}
/// Load [`RsaPublicKey`] from an ASN.1 DER-encoded file on the local
/// filesystem (binary format).
#[cfg(feature = "std")]
fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
let doc = Document::read_der_file(path)?;
Self::from_pkcs1_der(doc.as_bytes())
}
/// Load [`RsaPublicKey`] from a PEM-encoded file on the local filesystem.
#[cfg(all(feature = "pem", feature = "std"))]
fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
let (label, doc) = Document::read_pem_file(path)?;
RsaPublicKey::validate_pem_label(&label)?;
Self::from_pkcs1_der(doc.as_bytes())
}
}
/// Serialize a [`RsaPrivateKey`] to a PKCS#1 encoded document.
#[cfg(feature = "alloc")]
pub trait EncodeRsaPrivateKey {
/// Serialize a [`SecretDocument`] containing a PKCS#1-encoded private key.
fn to_pkcs1_der(&self) -> Result<SecretDocument>;
/// Serialize this private key as PEM-encoded PKCS#1 with the given [`LineEnding`].
#[cfg(feature = "pem")]
fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> {
let doc = self.to_pkcs1_der()?;
Ok(doc.to_pem(RsaPrivateKey::PEM_LABEL, line_ending)?)
}
/// Write ASN.1 DER-encoded PKCS#1 private key to the given path.
#[cfg(feature = "std")]
fn write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
Ok(self.to_pkcs1_der()?.write_der_file(path)?)
}
/// Write ASN.1 DER-encoded PKCS#1 private key to the given path.
#[cfg(all(feature = "pem", feature = "std"))]
fn write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
let doc = self.to_pkcs1_der()?;
Ok(doc.write_pem_file(path, RsaPrivateKey::PEM_LABEL, line_ending)?)
}
}
/// Serialize a [`RsaPublicKey`] to a PKCS#1-encoded document.
#[cfg(feature = "alloc")]
pub trait EncodeRsaPublicKey {
/// Serialize a [`Document`] containing a PKCS#1-encoded public key.
fn to_pkcs1_der(&self) -> Result<Document>;
/// Serialize this public key as PEM-encoded PKCS#1 with the given line ending.
#[cfg(feature = "pem")]
fn to_pkcs1_pem(&self, line_ending: LineEnding) -> Result<String> {
let doc = self.to_pkcs1_der()?;
Ok(doc.to_pem(RsaPublicKey::PEM_LABEL, line_ending)?)
}
/// Write ASN.1 DER-encoded public key to the given path.
#[cfg(feature = "std")]
fn write_pkcs1_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
Ok(self.to_pkcs1_der()?.write_der_file(path)?)
}
/// Write ASN.1 DER-encoded public key to the given path.
#[cfg(all(feature = "pem", feature = "std"))]
fn write_pkcs1_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> {
let doc = self.to_pkcs1_der()?;
Ok(doc.write_pem_file(path, RsaPublicKey::PEM_LABEL, line_ending)?)
}
}
#[cfg(feature = "pkcs8")]
impl<T> DecodeRsaPrivateKey for T
where
T: for<'a> TryFrom<pkcs8::PrivateKeyInfo<'a>, Error = pkcs8::Error>,
{
fn from_pkcs1_der(private_key: &[u8]) -> Result<Self> {
Ok(Self::try_from(pkcs8::PrivateKeyInfo {
algorithm: ALGORITHM_ID,
private_key,
public_key: None,
})?)
}
}
#[cfg(feature = "pkcs8")]
impl<T> DecodeRsaPublicKey for T
where
T: for<'a> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'a>, Error = pkcs8::spki::Error>,
{
fn from_pkcs1_der(public_key: &[u8]) -> Result<Self> {
Ok(Self::try_from(pkcs8::SubjectPublicKeyInfoRef {
algorithm: ALGORITHM_ID,
subject_public_key: BitStringRef::from_bytes(public_key)?,
})?)
}
}
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
fn to_pkcs1_der(&self) -> Result<SecretDocument> {
let pkcs8_doc = self.to_pkcs8_der()?;
let pkcs8_key = pkcs8::PrivateKeyInfo::from_der(pkcs8_doc.as_bytes())?;
pkcs8_key.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
RsaPrivateKey::from_der(pkcs8_key.private_key)?.try_into()
}
}
#[cfg(all(feature = "alloc", feature = "pkcs8"))]
impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
fn to_pkcs1_der(&self) -> Result<Document> {
let doc = self.to_public_key_der()?;
let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(doc.as_bytes())?;
spki.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())?.try_into()
}
}

72
vendor/pkcs1/src/version.rs vendored Normal file
View File

@@ -0,0 +1,72 @@
//! PKCS#1 version identifier.
use crate::Error;
use der::{Decode, Encode, FixedTag, Reader, Tag, Writer};
/// Version identifier for PKCS#1 documents as defined in
/// [RFC 8017 Appendix 1.2].
///
/// > version is the version number, for compatibility with future
/// > revisions of this document. It SHALL be 0 for this version of the
/// > document, unless multi-prime is used; in which case, it SHALL be 1.
///
/// ```text
/// Version ::= INTEGER { two-prime(0), multi(1) }
/// (CONSTRAINED BY
/// {-- version must be multi if otherPrimeInfos present --})
/// ```
///
/// [RFC 8017 Appendix 1.2]: https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.1.2
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[repr(u8)]
pub enum Version {
/// Denotes a `two-prime` key
TwoPrime = 0,
/// Denotes a `multi` (i.e. multi-prime) key
Multi = 1,
}
impl Version {
/// Is this a multi-prime RSA key?
pub fn is_multi(self) -> bool {
self == Self::Multi
}
}
impl From<Version> for u8 {
fn from(version: Version) -> Self {
version as u8
}
}
impl TryFrom<u8> for Version {
type Error = Error;
fn try_from(byte: u8) -> Result<Version, Error> {
match byte {
0 => Ok(Version::TwoPrime),
1 => Ok(Version::Multi),
_ => Err(Error::Version),
}
}
}
impl<'a> Decode<'a> for Version {
fn decode<R: Reader<'a>>(decoder: &mut R) -> der::Result<Self> {
Version::try_from(u8::decode(decoder)?).map_err(|_| Self::TAG.value_error())
}
}
impl Encode for Version {
fn encoded_len(&self) -> der::Result<der::Length> {
der::Length::ONE.for_tlv()
}
fn encode(&self, writer: &mut impl Writer) -> der::Result<()> {
u8::from(*self).encode(writer)
}
}
impl FixedTag for Version {
const TAG: Tag = Tag::Integer;
}