Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ impl CertificateParams {
// Write signature algorithm
issuer
.signing_key
.algorithm()
.signature_algorithm()
.write_alg_ident(writer.next());
// Write issuer name
write_distinguished_name(writer.next(), issuer.distinguished_name.as_ref());
Expand Down
5 changes: 3 additions & 2 deletions rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,12 @@ use crate::{
/// #[cfg(not(feature = "crypto"))]
/// impl SigningKey for MyKeyPair {
/// fn sign(&self, _: &[u8]) -> Result<Vec<u8>, rcgen::Error> { Ok(vec![]) }
/// fn signature_algorithm(&self) -> &'static SignatureAlgorithm { &ED25519 }
/// }
/// #[cfg(not(feature = "crypto"))]
/// impl PublicKeyData for MyKeyPair {
/// fn der_bytes(&self) -> &[u8] { &self.public_key }
/// fn algorithm(&self) -> &'static SignatureAlgorithm { &ED25519 }
/// fn algorithm(&self) -> &'static PublicKeyAlgorithm { &key_alg::ED25519 }
/// }
/// # fn main () {
/// // Generate a CRL issuer.
Expand Down Expand Up @@ -203,7 +204,7 @@ impl CertificateRevocationListParams {
// signatureAlgorithm field in the sequence CertificateList
issuer
.signing_key
.algorithm()
.signature_algorithm()
.write_alg_ident(writer.next());

// Write issuer.
Expand Down
29 changes: 12 additions & 17 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use pki_types::CertificateSigningRequestDer;
#[cfg(feature = "pem")]
use crate::ENCODE_CONFIG;
use crate::{
Certificate, CertificateParams, Error, Issuer, PublicKeyData, SignatureAlgorithm, SigningKey,
Certificate, CertificateParams, Error, Issuer, PublicKeyAlgorithm, PublicKeyData, SigningKey,
};
#[cfg(feature = "x509-parser")]
use crate::{DistinguishedName, ExtendedKeyUsagePurpose, GeneralName, IsCa, KeyUsagePurpose};
Expand All @@ -16,12 +16,12 @@ use crate::{DistinguishedName, ExtendedKeyUsagePurpose, GeneralName, IsCa, KeyUs
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct PublicKey {
raw: Vec<u8>,
alg: &'static SignatureAlgorithm,
alg: &'static PublicKeyAlgorithm,
}

impl PublicKey {
/// The algorithm used to generate the public key and sign the CSR.
pub fn algorithm(&self) -> &SignatureAlgorithm {
/// The algorithm of the public key
pub fn algorithm(&self) -> &'static PublicKeyAlgorithm {
self.alg
}
}
Expand All @@ -31,7 +31,7 @@ impl PublicKeyData for PublicKey {
&self.raw
}

fn algorithm(&self) -> &'static SignatureAlgorithm {
fn algorithm(&self) -> &'static PublicKeyAlgorithm {
self.alg
}
}
Expand Down Expand Up @@ -116,20 +116,18 @@ impl CertificateSigningRequestParams {
.1;
csr.verify_signature()
.map_err(|_| Error::InvalidCertificationRequestSignature)?;
let alg_oid = csr
.signature_algorithm
.algorithm
.iter()
.ok_or(Error::CouldNotParseCertificationRequest)?
.collect::<Vec<_>>();
let alg = SignatureAlgorithm::from_oid(&alg_oid)?;

let info = &csr.certification_request_info;

let public_key = PublicKey {
raw: info.subject_pki.subject_public_key.data.to_vec(),
alg: PublicKeyAlgorithm::from_alg_id(&info.subject_pki.algorithm)?,
};

let mut params = CertificateParams {
distinguished_name: DistinguishedName::from_name(&info.subject)?,
..CertificateParams::default()
};
let raw = info.subject_pki.subject_public_key.data.to_vec();

if let Some(extensions) = csr.requested_extensions() {
for ext in extensions {
Expand Down Expand Up @@ -186,10 +184,7 @@ impl CertificateSigningRequestParams {
// * name_constraints
// and any other extensions.

Ok(Self {
params,
public_key: PublicKey { alg, raw },
})
Ok(Self { params, public_key })
}

/// Generate a new certificate based on the requested parameters, signed by the provided
Expand Down
7 changes: 7 additions & 0 deletions rcgen/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum Error {
UnsupportedExtension,
/// The requested signature algorithm is not supported
UnsupportedSignatureAlgorithm,
/// The public key algorithm is not supported
UnsupportedPublicKeyAlgorithm,
/// Unspecified `ring` error
RingUnspecified,
/// The `ring` library rejected the key upon loading
Expand Down Expand Up @@ -84,6 +86,11 @@ impl fmt::Display for Error {
"The requested signature algorithm \
is not supported"
)?,
UnsupportedPublicKeyAlgorithm => write!(
f,
"The public key algorithm \
is not supported"
)?,
#[cfg(feature = "x509-parser")]
UnsupportedExtension => write!(f, "Unsupported extension requested in CSR")?,
RingUnspecified => write!(f, "Unspecified ring error")?,
Expand Down
63 changes: 30 additions & 33 deletions rcgen/src/key_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ use crate::ring_like::{
},
{ecdsa_from_pkcs8, rsa_key_pair_public_modulus_len},
};
use crate::sign_algo::SignatureAlgorithm;
#[cfg(feature = "crypto")]
use crate::sign_algo::{algo::*, SignAlgo};
use crate::sign_algo::{PublicKeyAlgorithm, SignatureAlgorithm};
use crate::Error;
#[cfg(feature = "pem")]
use crate::ENCODE_CONFIG;
Expand Down Expand Up @@ -181,11 +181,6 @@ impl KeyPair {
))
}

/// Returns the key pair's signature algorithm
pub fn algorithm(&self) -> &'static SignatureAlgorithm {
self.alg
}

/// Parses the key pair from the ASCII PEM format
///
/// If `aws_lc_rs` feature is used, then the key must be a DER-encoded plaintext private key; as specified in PKCS #8/RFC 5958, SEC1/RFC 5915, or PKCS#1/RFC 3447;
Expand Down Expand Up @@ -448,6 +443,10 @@ impl SigningKey for KeyPair {
},
})
}

fn signature_algorithm(&self) -> &'static SignatureAlgorithm {
self.alg
}
}

#[cfg(feature = "crypto")]
Expand All @@ -462,8 +461,8 @@ impl PublicKeyData for KeyPair {
}
}

fn algorithm(&self) -> &'static SignatureAlgorithm {
self.alg
fn algorithm(&self) -> &'static PublicKeyAlgorithm {
self.alg.public_key_algorithm()
}
}

Expand Down Expand Up @@ -595,7 +594,7 @@ pub(crate) fn sign_der(
writer.next().write_der(&data);

// Write signatureAlgorithm
key.algorithm().write_alg_ident(writer.next());
key.signature_algorithm().write_alg_ident(writer.next());

// Write signature
let sig = key.sign(&data)?;
Expand All @@ -611,12 +610,19 @@ impl<S: SigningKey + ?Sized> SigningKey for &S {
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error> {
(*self).sign(msg)
}

fn signature_algorithm(&self) -> &'static SignatureAlgorithm {
(*self).signature_algorithm()
}
}

/// A key that can be used to sign messages
pub trait SigningKey: PublicKeyData {
/// Signs `msg` using the selected algorithm
fn sign(&self, msg: &[u8]) -> Result<Vec<u8>, Error>;

/// The algorithm of the signatures this key produces
fn signature_algorithm(&self) -> &'static SignatureAlgorithm;
}

#[cfg(feature = "crypto")]
Expand All @@ -643,7 +649,7 @@ impl<T> ExternalError<T> for Result<T, pem::PemError> {
/// A public key
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SubjectPublicKeyInfo {
pub(crate) alg: &'static SignatureAlgorithm,
pub(crate) alg: &'static PublicKeyAlgorithm,
pub(crate) subject_public_key: Vec<u8>,
}

Expand All @@ -658,7 +664,7 @@ impl SubjectPublicKeyInfo {
#[cfg(feature = "x509-parser")]
pub fn from_der(spki_der: &[u8]) -> Result<Self, Error> {
use x509_parser::prelude::FromDer;
use x509_parser::x509::{AlgorithmIdentifier, SubjectPublicKeyInfo};
use x509_parser::x509::SubjectPublicKeyInfo;

let (rem, spki) =
SubjectPublicKeyInfo::from_der(spki_der).map_err(|e| Error::X509(e.to_string()))?;
Expand All @@ -668,23 +674,8 @@ impl SubjectPublicKeyInfo {
));
}

let alg = SignatureAlgorithm::iter()
.find(|alg| {
let bytes = yasna::construct_der(|writer| {
alg.write_oids_sign_alg(writer);
});
let Ok((rest, aid)) = AlgorithmIdentifier::from_der(&bytes) else {
return false;
};
if !rest.is_empty() {
return false;
}
aid == spki.algorithm
})
.ok_or(Error::UnsupportedSignatureAlgorithm)?;

Ok(Self {
alg,
alg: PublicKeyAlgorithm::from_alg_id(&spki.algorithm)?,
subject_public_key: Vec::from(spki.subject_public_key.as_ref()),
})
}
Expand All @@ -695,7 +686,7 @@ impl PublicKeyData for SubjectPublicKeyInfo {
&self.subject_public_key
}

fn algorithm(&self) -> &'static SignatureAlgorithm {
fn algorithm(&self) -> &'static PublicKeyAlgorithm {
self.alg
}
}
Expand All @@ -705,7 +696,7 @@ impl<K: PublicKeyData + ?Sized> PublicKeyData for &K {
(*self).der_bytes()
}

fn algorithm(&self) -> &'static SignatureAlgorithm {
fn algorithm(&self) -> &'static PublicKeyAlgorithm {
(*self).algorithm()
}
}
Expand All @@ -723,8 +714,8 @@ pub trait PublicKeyData {
/// The public key in DER format
fn der_bytes(&self) -> &[u8];

/// The algorithm used by the key pair
fn algorithm(&self) -> &'static SignatureAlgorithm;
/// The algorithm of the public key
fn algorithm(&self) -> &'static PublicKeyAlgorithm;
}

/// Serialize private key to PEM format
Expand All @@ -743,7 +734,7 @@ pub fn serialize_private_key_pem(key: &PrivateKeyDer<'_>) -> Result<String, Erro

pub(crate) fn serialize_public_key_der(key: &(impl PublicKeyData + ?Sized), writer: DERWriter) {
writer.write_sequence(|writer| {
key.algorithm().write_oids_sign_alg(writer.next());
key.algorithm().write_alg_id(writer.next());
let pk = key.der_bytes();
writer.next().write_bitvec_bytes(pk, pk.len() * 8);
})
Expand Down Expand Up @@ -776,6 +767,11 @@ mod test {

let pkd_der = SubjectPublicKeyInfo::from_der(&der).expect("from der");
assert_eq!(kp.der_bytes(), pkd_der.der_bytes());

// Several signature algorithms can share an SPKI encoding, so this recovery is
// only unambiguous because it resolves to a key algorithm.
assert_eq!(pkd_der.algorithm(), alg.public_key_algorithm());
assert_eq!(pkd_der.subject_public_key_info(), der);
}
}

Expand All @@ -786,6 +782,7 @@ mod test {
let der = pkcs8.as_ref().to_vec();

let key_pair = KeyPair::try_from(der).unwrap();
assert_eq!(key_pair.algorithm(), &ECDSA_P256_SHA256);
assert_eq!(key_pair.signature_algorithm(), &ECDSA_P256_SHA256);
assert_eq!(key_pair.algorithm(), &crate::key_alg::ECDSA_P256);
}
}
25 changes: 24 additions & 1 deletion rcgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub use key_pair::{PublicKeyData, SigningKey, SubjectPublicKeyInfo};

mod sign_algo;
pub use sign_algo::algo::*;
pub use sign_algo::SignatureAlgorithm;
pub use sign_algo::{key_alg, PublicKeyAlgorithm, SignatureAlgorithm};

mod oid;

Expand Down Expand Up @@ -679,4 +679,27 @@ mod tests {
}
}
}

#[test]
fn algo_hash_agrees_with_eq() {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};

fn hash(value: &impl Hash) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}

for alg_i in SignatureAlgorithm::iter() {
for alg_j in SignatureAlgorithm::iter() {
assert!(alg_i != alg_j || hash(alg_i) == hash(alg_j));
}
}
for alg_i in PublicKeyAlgorithm::iter() {
for alg_j in PublicKeyAlgorithm::iter() {
assert!(alg_i != alg_j || hash(alg_i) == hash(alg_j));
}
}
}
}
Loading
Loading