| use crate::cri_attributes::*; |
| use crate::error::{X509Error, X509Result}; |
| use crate::extensions::*; |
| use crate::traits::FromDer; |
| use crate::x509::{ |
| parse_signature_value, AlgorithmIdentifier, SubjectPublicKeyInfo, X509Name, X509Version, |
| }; |
| |
| use der_parser::ber::BitStringObject; |
| use der_parser::der::*; |
| use der_parser::oid::Oid; |
| use der_parser::*; |
| use nom::Offset; |
| #[cfg(feature = "verify")] |
| use oid_registry::*; |
| use std::collections::HashMap; |
| |
| /// Certification Signing Request (CSR) |
| #[derive(Debug, PartialEq)] |
| pub struct X509CertificationRequest<'a> { |
| pub certification_request_info: X509CertificationRequestInfo<'a>, |
| pub signature_algorithm: AlgorithmIdentifier<'a>, |
| pub signature_value: BitStringObject<'a>, |
| } |
| |
| impl<'a> X509CertificationRequest<'a> { |
| pub fn requested_extensions(&self) -> Option<impl Iterator<Item = &ParsedExtension>> { |
| self.certification_request_info |
| .iter_attributes() |
| .find_map(|attr| { |
| if let ParsedCriAttribute::ExtensionRequest(requested) = &attr.parsed_attribute { |
| Some(requested.extensions.iter().map(|ext| &ext.parsed_extension)) |
| } else { |
| None |
| } |
| }) |
| } |
| |
| /// Verify the cryptographic signature of this certification request |
| /// |
| /// Uses the public key contained in the CSR, which must be the one of the entity |
| /// requesting the certification for this verification to succeed. |
| #[cfg(feature = "verify")] |
| pub fn verify_signature(&self) -> Result<(), X509Error> { |
| use ring::signature; |
| let spki = &self.certification_request_info.subject_pki; |
| let signature_alg = &self.signature_algorithm.algorithm; |
| // identify verification algorithm |
| let verification_alg: &dyn signature::VerificationAlgorithm = |
| if *signature_alg == OID_PKCS1_SHA1WITHRSA { |
| &signature::RSA_PKCS1_1024_8192_SHA1_FOR_LEGACY_USE_ONLY |
| } else if *signature_alg == OID_PKCS1_SHA256WITHRSA { |
| &signature::RSA_PKCS1_2048_8192_SHA256 |
| } else if *signature_alg == OID_PKCS1_SHA384WITHRSA { |
| &signature::RSA_PKCS1_2048_8192_SHA384 |
| } else if *signature_alg == OID_PKCS1_SHA512WITHRSA { |
| &signature::RSA_PKCS1_2048_8192_SHA512 |
| } else if *signature_alg == OID_SIG_ECDSA_WITH_SHA256 { |
| &signature::ECDSA_P256_SHA256_ASN1 |
| } else if *signature_alg == OID_SIG_ECDSA_WITH_SHA384 { |
| &signature::ECDSA_P384_SHA384_ASN1 |
| } else if *signature_alg == OID_SIG_ED25519 { |
| &signature::ED25519 |
| } else { |
| return Err(X509Error::SignatureUnsupportedAlgorithm); |
| }; |
| // get public key |
| let key = signature::UnparsedPublicKey::new(verification_alg, spki.subject_public_key.data); |
| // verify signature |
| let sig = self.signature_value.data; |
| key.verify(self.certification_request_info.raw, sig) |
| .or(Err(X509Error::SignatureVerificationError)) |
| } |
| } |
| |
| /// <pre> |
| /// CertificationRequest ::= SEQUENCE { |
| /// certificationRequestInfo CertificationRequestInfo, |
| /// signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }}, |
| /// signature BIT STRING |
| /// } |
| /// </pre> |
| impl<'a> FromDer<'a> for X509CertificationRequest<'a> { |
| fn from_der(i: &'a [u8]) -> X509Result<'a, Self> { |
| parse_der_sequence_defined_g(|i, _| { |
| let (i, certification_request_info) = X509CertificationRequestInfo::from_der(i)?; |
| let (i, signature_algorithm) = AlgorithmIdentifier::from_der(i)?; |
| let (i, signature_value) = parse_signature_value(i)?; |
| let cert = X509CertificationRequest { |
| certification_request_info, |
| signature_algorithm, |
| signature_value, |
| }; |
| Ok((i, cert)) |
| })(i) |
| } |
| } |
| |
| /// Certification Request Info structure |
| /// |
| /// Certification request information is defined by the following ASN.1 structure: |
| /// |
| /// <pre> |
| /// CertificationRequestInfo ::= SEQUENCE { |
| /// version INTEGER { v1(0) } (v1,...), |
| /// subject Name, |
| /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, |
| /// attributes [0] Attributes{{ CRIAttributes }} |
| /// } |
| /// </pre> |
| /// |
| /// version is the version number; subject is the distinguished name of the certificate |
| /// subject; subject_pki contains information about the public key being certified, and |
| /// attributes is a collection of attributes providing additional information about the |
| /// subject of the certificate. |
| #[derive(Debug, PartialEq)] |
| pub struct X509CertificationRequestInfo<'a> { |
| pub version: X509Version, |
| pub subject: X509Name<'a>, |
| pub subject_pki: SubjectPublicKeyInfo<'a>, |
| attributes: Vec<X509CriAttribute<'a>>, |
| pub raw: &'a [u8], |
| } |
| |
| impl<'a> X509CertificationRequestInfo<'a> { |
| /// Get the CRL entry extensions. |
| #[inline] |
| pub fn attributes(&self) -> &[X509CriAttribute] { |
| &self.attributes |
| } |
| |
| /// Returns an iterator over the CRL entry extensions |
| #[inline] |
| pub fn iter_attributes(&self) -> impl Iterator<Item = &X509CriAttribute> { |
| self.attributes.iter() |
| } |
| |
| /// Searches for a CRL entry extension with the given `Oid`. |
| /// |
| /// Note: if there are several extensions with the same `Oid`, the first one is returned. |
| pub fn find_attribute(&self, oid: &Oid) -> Option<&X509CriAttribute> { |
| self.attributes.iter().find(|&ext| ext.oid == *oid) |
| } |
| |
| /// Builds and returns a map of CRL entry extensions. |
| /// |
| /// If an extension is present twice, this will fail and return `DuplicateExtensions`. |
| pub fn attributes_map(&self) -> Result<HashMap<Oid, &X509CriAttribute>, X509Error> { |
| self.attributes |
| .iter() |
| .try_fold(HashMap::new(), |mut m, ext| { |
| if m.contains_key(&ext.oid) { |
| return Err(X509Error::DuplicateAttributes); |
| } |
| m.insert(ext.oid.clone(), ext); |
| Ok(m) |
| }) |
| } |
| } |
| |
| /// <pre> |
| /// CertificationRequestInfo ::= SEQUENCE { |
| /// version INTEGER { v1(0) } (v1,...), |
| /// subject Name, |
| /// subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }}, |
| /// attributes [0] Attributes{{ CRIAttributes }} |
| /// } |
| /// </pre> |
| impl<'a> FromDer<'a> for X509CertificationRequestInfo<'a> { |
| fn from_der(i: &'a [u8]) -> X509Result<Self> { |
| let start_i = i; |
| parse_der_sequence_defined_g(move |i, _| { |
| let (i, version) = X509Version::from_der_required(i)?; |
| let (i, subject) = X509Name::from_der(i)?; |
| let (i, subject_pki) = SubjectPublicKeyInfo::from_der(i)?; |
| let (i, attributes) = parse_cri_attributes(i)?; |
| let len = start_i.offset(i); |
| let tbs = X509CertificationRequestInfo { |
| version, |
| subject, |
| subject_pki, |
| attributes, |
| raw: &start_i[..len], |
| }; |
| Ok((i, tbs)) |
| })(i) |
| } |
| } |