diff --git a/src/lib.rs b/src/lib.rs index 79765bdc..05f03da5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ use rcgen::generate_simple_self_signed; # fn main () { // Generate a certificate that's valid for "localhost" and "hello.world.example" let subject_alt_names = vec!["hello.world.example".to_string(), - "localhost".to_string()]; + "localhost".to_string()]; let cert = generate_simple_self_signed(subject_alt_names); println!("{}", cert.serialize_pem()); @@ -28,36 +28,35 @@ println!("{}", cert.serialize_private_key_pem()); #![forbid(unsafe_code)] #![deny(missing_docs)] -extern crate yasna; -extern crate ring; +extern crate bit_vec; +extern crate chrono; extern crate pem; +extern crate ring; extern crate untrusted; -extern crate chrono; -extern crate bit_vec; +extern crate yasna; -use yasna::Tag; -use yasna::models::ObjectIdentifier; +use bit_vec::BitVec; +use chrono::{DateTime, Timelike}; +use chrono::{NaiveDate, Utc}; use pem::Pem; -use ring::signature::EcdsaKeyPair; use ring::rand::SystemRandom; +use ring::signature::EcdsaKeyPair; use ring::signature::KeyPair; -use untrusted::Input; use ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING as KALG; -use yasna::DERWriter; -use yasna::models::GeneralizedTime; -use chrono::{DateTime, Timelike}; -use chrono::{NaiveDate, Utc}; use std::collections::HashMap; -use bit_vec::BitVec; +use untrusted::Input; +use yasna::models::GeneralizedTime; +use yasna::models::ObjectIdentifier; +use yasna::DERWriter; +use yasna::Tag; /// A self signed certificate together with signing keys pub struct Certificate { - params :CertificateParams, - key_pair :EcdsaKeyPair, - key_pair_serialized :Vec, + params: CertificateParams, + key_pair: EcdsaKeyPair, + key_pair_serialized: Vec, } - /** KISS function to generate a self signed certificate @@ -73,7 +72,7 @@ extern crate rcgen; use rcgen::generate_simple_self_signed; # fn main () { let subject_alt_names :&[_] = &["hello.world.example".to_string(), - "localhost".to_string()]; + "localhost".to_string()]; let cert = generate_simple_self_signed(subject_alt_names); // The certificate is now valid for localhost and the domain "hello.world.example" @@ -82,21 +81,21 @@ println!("{}", cert.serialize_private_key_pem()); # } ``` */ -pub fn generate_simple_self_signed(subject_alt_names :impl Into>) -> Certificate { - // not_before and not_after set to reasonably long dates - let not_before = date_time_ymd(1975, 01, 01); - let not_after = date_time_ymd(4096, 01, 01); - let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push(DnType::CommonName, "rcgen self signed cert"); - let params = CertificateParams { - alg : PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - not_before, - not_after, - serial_number : None, - subject_alt_names : subject_alt_names.into(), - distinguished_name, - }; - Certificate::from_params(params) +pub fn generate_simple_self_signed(subject_alt_names: impl Into>) -> Certificate { + // not_before and not_after set to reasonably long dates + let not_before = date_time_ymd(1975, 01, 01); + let not_after = date_time_ymd(4096, 01, 01); + let mut distinguished_name = DistinguishedName::new(); + distinguished_name.push(DnType::CommonName, "rcgen self signed cert"); + let params = CertificateParams { + alg: PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, + not_before, + not_after, + serial_number: None, + subject_alt_names: subject_alt_names.into(), + distinguished_name, + }; + Certificate::from_params(params) } // https://tools.ietf.org/html/rfc5280#section-4.1.1 @@ -105,41 +104,41 @@ pub fn generate_simple_self_signed(subject_alt_names :impl Into>) -> // Uses ECDSA: https://crt.sh/?asn1=607203242 /// id-at-countryName in RFC 5820 -const OID_COUNTRY_NAME :&[u64] = &[2, 5, 4, 6]; +const OID_COUNTRY_NAME: &[u64] = &[2, 5, 4, 6]; /// id-at-organizationName in RFC 5820 -const OID_ORG_NAME :&[u64] = &[2, 5, 4, 10]; +const OID_ORG_NAME: &[u64] = &[2, 5, 4, 10]; /// id-at-commonName in RFC 5820 -const OID_COMMON_NAME :&[u64] = &[2, 5, 4, 3]; +const OID_COMMON_NAME: &[u64] = &[2, 5, 4, 3]; // https://tools.ietf.org/html/rfc5480#section-2.1.1 -const OID_EC_PUBLIC_KEY :&[u64] = &[1, 2, 840, 10045, 2, 1]; -const OID_EC_SECP_256_R1 :&[u64] = &[1, 2, 840, 10045, 3, 1, 7]; +const OID_EC_PUBLIC_KEY: &[u64] = &[1, 2, 840, 10045, 2, 1]; +const OID_EC_SECP_256_R1: &[u64] = &[1, 2, 840, 10045, 3, 1, 7]; // https://tools.ietf.org/html/rfc5280#appendix-A.2 // https://tools.ietf.org/html/rfc5280#section-4.2.1.6 -const OID_SUBJECT_ALT_NAME :&[u64] = &[2, 5, 29, 17]; +const OID_SUBJECT_ALT_NAME: &[u64] = &[2, 5, 29, 17]; #[derive(Debug, PartialEq, Eq, Hash, Clone)] #[allow(missing_docs)] /// The attribute type of a distinguished name entry pub enum DnType { - CountryName, - OrganizationName, - CommonName, - #[doc(hidden)] - _Nonexhaustive, + CountryName, + OrganizationName, + CommonName, + #[doc(hidden)] + _Nonexhaustive, } impl DnType { - fn to_oid(&self) -> ObjectIdentifier { - let sl = match self { - DnType::CountryName => OID_COUNTRY_NAME, - DnType::OrganizationName => OID_ORG_NAME, - DnType::CommonName => OID_COMMON_NAME, - DnType::_Nonexhaustive => unimplemented!(), - }; - ObjectIdentifier::from_slice(sl) - } + fn to_oid(&self) -> ObjectIdentifier { + let sl = match self { + DnType::CountryName => OID_COUNTRY_NAME, + DnType::OrganizationName => OID_ORG_NAME, + DnType::CommonName => OID_COMMON_NAME, + DnType::_Nonexhaustive => unimplemented!(), + }; + ObjectIdentifier::from_slice(sl) + } } #[derive(Debug, PartialEq, Eq, Clone)] @@ -152,31 +151,31 @@ See also the RFC 5280 sections on the [issuer](https://tools.ietf.org/html/rfc52 and [subject](https://tools.ietf.org/html/rfc5280#section-4.1.2.6) fields. */ pub struct DistinguishedName { - entries :HashMap, + entries: HashMap, } impl DistinguishedName { - /// Creates a new, empty distinguished name - pub fn new() -> Self { - Self { - entries : HashMap::new(), - } - } - /// Inserts a new attribute that consists of type and name - pub fn push(&mut self, ty :DnType, s :impl Into) { - self.entries.insert(ty, s.into()); - } + /// Creates a new, empty distinguished name + pub fn new() -> Self { + Self { + entries: HashMap::new(), + } + } + /// Inserts a new attribute that consists of type and name + pub fn push(&mut self, ty: DnType, s: impl Into) { + self.entries.insert(ty, s.into()); + } } /// Parameters used for certificate generation #[allow(missing_docs)] pub struct CertificateParams { - pub alg :SignatureAlgorithm, - pub not_before :DateTime, - pub not_after :DateTime, - pub serial_number :Option, - pub subject_alt_names :Vec, - pub distinguished_name :DistinguishedName, + pub alg: SignatureAlgorithm, + pub not_before: DateTime, + pub not_after: DateTime, + pub serial_number: Option, + pub subject_alt_names: Vec, + pub distinguished_name: DistinguishedName, } /// Helper to obtain a DateTime from year, month, day values @@ -187,181 +186,184 @@ pub struct CertificateParams { /// have to import the chrono crate yourself in order to specify date /// information, second so that users don't have to type unproportionately /// long code just to generate an instance of `DateTime`. -pub fn date_time_ymd(year :i32, month :u32, day :u32) -> DateTime { - let naive_dt = NaiveDate::from_ymd(year, month, day).and_hms_milli(0, 0, 0, 0); - DateTime::::from_utc(naive_dt, Utc) +pub fn date_time_ymd(year: i32, month: u32, day: u32) -> DateTime { + let naive_dt = NaiveDate::from_ymd(year, month, day).and_hms_milli(0, 0, 0, 0); + DateTime::::from_utc(naive_dt, Utc) } -fn dt_to_generalized(dt :&DateTime) -> GeneralizedTime { - let mut date_time = *dt; - // Set nanoseconds to zero (or to one leap second if there is a leap second) - // This is needed because the GeneralizedTime serializer would otherwise - // output fractional values which RFC 5820 explicitly forbode [1]. - // [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 - let nanos = if date_time.nanosecond() >= 1_000_000 { - 1_000_000 - } else { - 0 - }; - date_time = date_time.with_nanosecond(nanos).unwrap(); - GeneralizedTime::from_datetime::(&date_time) +fn dt_to_generalized(dt: &DateTime) -> GeneralizedTime { + let mut date_time = *dt; + // Set nanoseconds to zero (or to one leap second if there is a leap second) + // This is needed because the GeneralizedTime serializer would otherwise + // output fractional values which RFC 5820 explicitly forbode [1]. + // [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2 + let nanos = if date_time.nanosecond() >= 1_000_000 { + 1_000_000 + } else { + 0 + }; + date_time = date_time.with_nanosecond(nanos).unwrap(); + GeneralizedTime::from_datetime::(&date_time) } impl Certificate { - /// Generates a new self-signed certificate from the given parameters - pub fn from_params(params :CertificateParams) -> Self { - let system_random = SystemRandom::new(); - let key_pair_doc = EcdsaKeyPair::generate_pkcs8(&KALG, &system_random).unwrap(); - let key_pair_serialized = key_pair_doc.as_ref().to_vec(); - - let key_pair = EcdsaKeyPair::from_pkcs8(&KALG, Input::from(&&key_pair_doc.as_ref())).unwrap(); - - Certificate { - params, - key_pair, - key_pair_serialized, - } - } - fn write_name(&self, writer :DERWriter) { - writer.write_sequence(|writer| { - writer.next().write_set(|writer| { - for (ty, content) in self.params.distinguished_name.entries.iter() { - writer.next().write_sequence(|writer| { - writer.next().write_oid(&ty.to_oid()); - writer.next().write_utf8_string(content); - }); - } - }); - }); - } - fn write_cert(&self, writer :DERWriter) { - writer.write_sequence(|writer| { - // Write version - writer.next().write_tagged(Tag::context(0), |writer| { - writer.write_u8(2); - }); - // Write serialNumber - let serial = self.params.serial_number.unwrap_or(42); - writer.next().write_u64(serial); - // Write signature - writer.next().write_sequence(|writer| { - writer.next().write_oid(&self.params.alg.oid()); - }); - // Write issuer - self.write_name(writer.next()); - // Write validity - writer.next().write_sequence(|writer| { - // Not before - let nb_gt = dt_to_generalized(&self.params.not_before); - writer.next().write_generalized_time(&nb_gt); - // Not after - let na_gt = dt_to_generalized(&self.params.not_after); - writer.next().write_generalized_time(&na_gt); - }); - // Write subject - self.write_name(writer.next()); - // Write subjectPublicKeyInfo - writer.next().write_sequence(|writer| { - writer.next().write_sequence(|writer| { - let oid = ObjectIdentifier::from_slice(OID_EC_PUBLIC_KEY); - writer.next().write_oid(&oid); - let oid = ObjectIdentifier::from_slice(OID_EC_SECP_256_R1); - writer.next().write_oid(&oid); - }); - let public_key = &self.key_pair.public_key().as_ref(); - let pkbs = BitVec::from_bytes(&public_key); - writer.next().write_bitvec(&pkbs); - }); - // write extensions - writer.next().write_tagged(Tag::context(3), |writer| { - writer.write_sequence(|writer| { - // Write subject_alt_names - writer.next().write_sequence(|writer| { - let oid = ObjectIdentifier::from_slice(OID_SUBJECT_ALT_NAME); - writer.next().write_oid(&oid); - let bytes = yasna::construct_der(|writer| { - writer.write_sequence(|writer|{ - for san in self.params.subject_alt_names.iter() { - writer.next().write_tagged_implicit(Tag::context(2), |writer| { - writer.write_utf8_string(san); - }); - } - }); - }); - writer.next().write_bytes(&bytes); - }); - }); - }); - }) - } - /// Serializes the certificate to the binary DER format - pub fn serialize_der(&self) -> Vec { - yasna::construct_der(|writer| { - writer.write_sequence(|writer| { - - let tbs_cert_list_serialized = yasna::construct_der(|writer| { - self.write_cert(writer); - }); - // Write tbsCertList - writer.next().write_der(&tbs_cert_list_serialized); - - // Write signatureAlgorithm - writer.next().write_sequence(|writer| { - writer.next().write_oid(&self.params.alg.oid()); - }); - - // Write signature - let cl_input = Input::from(&tbs_cert_list_serialized); - let system_random = SystemRandom::new(); - let signature = self.key_pair.sign(&system_random, cl_input).unwrap(); - let sig = BitVec::from_bytes(&signature.as_ref()); - writer.next().write_bitvec(&sig); - }) - }) - } - /// Serializes the certificate to the ASCII PEM format - pub fn serialize_pem(&self) -> String { - let p = Pem { - tag : "CERTIFICATE".to_string(), - contents : self.serialize_der(), - }; - pem::encode(&p) - } - /// Serializes the private key in PKCS#8 format - pub fn serialize_private_key_der(&self) -> Vec { - self.key_pair_serialized.clone() - } - /// Serializes the private key in PEM format - pub fn serialize_private_key_pem(&self) -> String { - let p = Pem { - tag : "PRIVATE KEY".to_string(), - contents : self.serialize_private_key_der(), - }; - pem::encode(&p) - } + /// Generates a new self-signed certificate from the given parameters + pub fn from_params(params: CertificateParams) -> Self { + let system_random = SystemRandom::new(); + let key_pair_doc = EcdsaKeyPair::generate_pkcs8(&KALG, &system_random).unwrap(); + let key_pair_serialized = key_pair_doc.as_ref().to_vec(); + + let key_pair = + EcdsaKeyPair::from_pkcs8(&KALG, Input::from(&&key_pair_doc.as_ref())).unwrap(); + + Certificate { + params, + key_pair, + key_pair_serialized, + } + } + fn write_name(&self, writer: DERWriter) { + writer.write_sequence(|writer| { + writer.next().write_set(|writer| { + for (ty, content) in self.params.distinguished_name.entries.iter() { + writer.next().write_sequence(|writer| { + writer.next().write_oid(&ty.to_oid()); + writer.next().write_utf8_string(content); + }); + } + }); + }); + } + fn write_cert(&self, writer: DERWriter) { + writer.write_sequence(|writer| { + // Write version + writer.next().write_tagged(Tag::context(0), |writer| { + writer.write_u8(2); + }); + // Write serialNumber + let serial = self.params.serial_number.unwrap_or(42); + writer.next().write_u64(serial); + // Write signature + writer.next().write_sequence(|writer| { + writer.next().write_oid(&self.params.alg.oid()); + }); + // Write issuer + self.write_name(writer.next()); + // Write validity + writer.next().write_sequence(|writer| { + // Not before + let nb_gt = dt_to_generalized(&self.params.not_before); + writer.next().write_generalized_time(&nb_gt); + // Not after + let na_gt = dt_to_generalized(&self.params.not_after); + writer.next().write_generalized_time(&na_gt); + }); + // Write subject + self.write_name(writer.next()); + // Write subjectPublicKeyInfo + writer.next().write_sequence(|writer| { + writer.next().write_sequence(|writer| { + let oid = ObjectIdentifier::from_slice(OID_EC_PUBLIC_KEY); + writer.next().write_oid(&oid); + let oid = ObjectIdentifier::from_slice(OID_EC_SECP_256_R1); + writer.next().write_oid(&oid); + }); + let public_key = &self.key_pair.public_key().as_ref(); + let pkbs = BitVec::from_bytes(&public_key); + writer.next().write_bitvec(&pkbs); + }); + // write extensions + writer.next().write_tagged(Tag::context(3), |writer| { + writer.write_sequence(|writer| { + // Write subject_alt_names + writer.next().write_sequence(|writer| { + let oid = ObjectIdentifier::from_slice(OID_SUBJECT_ALT_NAME); + writer.next().write_oid(&oid); + let bytes = yasna::construct_der(|writer| { + writer.write_sequence(|writer| { + for san in self.params.subject_alt_names.iter() { + writer.next().write_tagged_implicit( + Tag::context(2), + |writer| { + writer.write_utf8_string(san); + }, + ); + } + }); + }); + writer.next().write_bytes(&bytes); + }); + }); + }); + }) + } + /// Serializes the certificate to the binary DER format + pub fn serialize_der(&self) -> Vec { + yasna::construct_der(|writer| { + writer.write_sequence(|writer| { + let tbs_cert_list_serialized = yasna::construct_der(|writer| { + self.write_cert(writer); + }); + // Write tbsCertList + writer.next().write_der(&tbs_cert_list_serialized); + + // Write signatureAlgorithm + writer.next().write_sequence(|writer| { + writer.next().write_oid(&self.params.alg.oid()); + }); + + // Write signature + let cl_input = Input::from(&tbs_cert_list_serialized); + let system_random = SystemRandom::new(); + let signature = self.key_pair.sign(&system_random, cl_input).unwrap(); + let sig = BitVec::from_bytes(&signature.as_ref()); + writer.next().write_bitvec(&sig); + }) + }) + } + /// Serializes the certificate to the ASCII PEM format + pub fn serialize_pem(&self) -> String { + let p = Pem { + tag: "CERTIFICATE".to_string(), + contents: self.serialize_der(), + }; + pem::encode(&p) + } + /// Serializes the private key in PKCS#8 format + pub fn serialize_private_key_der(&self) -> Vec { + self.key_pair_serialized.clone() + } + /// Serializes the private key in PEM format + pub fn serialize_private_key_pem(&self) -> String { + let p = Pem { + tag: "PRIVATE KEY".to_string(), + contents: self.serialize_private_key_der(), + }; + pem::encode(&p) + } } /// Signature algorithm type pub struct SignatureAlgorithm { - oid_components : &'static [u64], + oid_components: &'static [u64], } /* pub const PKCS_WITH_SHA256_WITH_RSA_ENCRYPTION :SignatureAlgorithm = SignatureAlgorithm { - /// sha256WithRSAEncryption in RFC 4055 - oid_components : &[1, 2, 840, 113549, 1, 1, 11], + /// sha256WithRSAEncryption in RFC 4055 + oid_components : &[1, 2, 840, 113549, 1, 1, 11], }; */ /// Signature algorithm ID as per [RFC 5758](https://tools.ietf.org/html/rfc5758#section-3.2) -pub const PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION :SignatureAlgorithm = SignatureAlgorithm { - /// ecdsa-with-SHA256 in RFC 5758 - oid_components : &[1, 2, 840, 10045, 4, 3, 2], +pub const PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION: SignatureAlgorithm = SignatureAlgorithm { + /// ecdsa-with-SHA256 in RFC 5758 + oid_components: &[1, 2, 840, 10045, 4, 3, 2], }; // Signature algorithm IDs as per https://tools.ietf.org/html/rfc4055 impl SignatureAlgorithm { - fn oid(&self) -> ObjectIdentifier { - ObjectIdentifier::from_slice(self.oid_components) - } + fn oid(&self) -> ObjectIdentifier { + ObjectIdentifier::from_slice(self.oid_components) + } } diff --git a/src/main.rs b/src/main.rs index deaceae0..90e19439 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,33 +1,36 @@ extern crate rcgen; -use rcgen::{Certificate, CertificateParams, - DistinguishedName, DnType, - PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - date_time_ymd}; +use rcgen::{ + date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType, + PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, +}; use std::fs; use std::io::Result; fn main() -> Result<()> { - let not_before = date_time_ymd(1975, 01, 01); - let not_after = date_time_ymd(4096, 01, 01); - let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); - distinguished_name.push(DnType::CommonName, "Master CA"); - let params = CertificateParams { - alg : PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - not_before, - not_after, - serial_number : None, - subject_alt_names : vec!["crabs.crabs".to_string(), "localhost".to_string()], - distinguished_name, - }; - let cert = Certificate::from_params(params); - println!("{}", cert.serialize_pem()); - println!("{}", cert.serialize_private_key_pem()); - std::fs::create_dir_all("certs/")?; - fs::write("certs/cert.pem", &cert.serialize_pem().as_bytes())?; - fs::write("certs/cert.der", &cert.serialize_der())?; - fs::write("certs/key.pem", &cert.serialize_private_key_pem().as_bytes())?; - fs::write("certs/key.der", &cert.serialize_private_key_der())?; - Ok(()) + let not_before = date_time_ymd(1975, 01, 01); + let not_after = date_time_ymd(4096, 01, 01); + let mut distinguished_name = DistinguishedName::new(); + distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + distinguished_name.push(DnType::CommonName, "Master CA"); + let params = CertificateParams { + alg: PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, + not_before, + not_after, + serial_number: None, + subject_alt_names: vec!["crabs.crabs".to_string(), "localhost".to_string()], + distinguished_name, + }; + let cert = Certificate::from_params(params); + println!("{}", cert.serialize_pem()); + println!("{}", cert.serialize_private_key_pem()); + std::fs::create_dir_all("certs/")?; + fs::write("certs/cert.pem", &cert.serialize_pem().as_bytes())?; + fs::write("certs/cert.der", &cert.serialize_der())?; + fs::write( + "certs/key.pem", + &cert.serialize_private_key_pem().as_bytes(), + )?; + fs::write("certs/key.der", &cert.serialize_private_key_der())?; + Ok(()) } diff --git a/tests/openssl.rs b/tests/openssl.rs index 74031d50..17e48f1b 100644 --- a/tests/openssl.rs +++ b/tests/openssl.rs @@ -1,45 +1,46 @@ extern crate openssl; extern crate rcgen; -use rcgen::{Certificate, CertificateParams, - DistinguishedName, DnType, - PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - date_time_ymd}; +use rcgen::{ + date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType, + PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, +}; -use openssl::x509::{X509, X509StoreContext}; -use openssl::x509::store::{X509StoreBuilder, X509Store}; use openssl::stack::Stack; +use openssl::x509::store::{X509Store, X509StoreBuilder}; +use openssl::x509::{X509StoreContext, X509}; #[test] fn test_openssl() { - let not_before = date_time_ymd(1900, 01, 01); - let not_after = date_time_ymd(1901, 01, 01); - let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); - distinguished_name.push(DnType::CommonName, "Master CA"); - let params = CertificateParams { - alg : PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - not_before, - not_after, - serial_number : None, - subject_alt_names : vec!["crabs.crabs".to_string(), "localhost".to_string()], - distinguished_name, - }; - let cert = Certificate::from_params(params); + let not_before = date_time_ymd(1900, 01, 01); + let not_after = date_time_ymd(1901, 01, 01); + let mut distinguished_name = DistinguishedName::new(); + distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + distinguished_name.push(DnType::CommonName, "Master CA"); + let params = CertificateParams { + alg: PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, + not_before, + not_after, + serial_number: None, + subject_alt_names: vec!["crabs.crabs".to_string(), "localhost".to_string()], + distinguished_name, + }; + let cert = Certificate::from_params(params); - println!("{}", cert.serialize_pem()); + println!("{}", cert.serialize_pem()); - // Now verify the certificate. - let x509 = X509::from_pem(&cert.serialize_pem().as_bytes()).unwrap(); - let mut builder = X509StoreBuilder::new().unwrap(); - builder.add_cert(x509.clone()).unwrap(); + // Now verify the certificate. + let x509 = X509::from_pem(&cert.serialize_pem().as_bytes()).unwrap(); + let mut builder = X509StoreBuilder::new().unwrap(); + builder.add_cert(x509.clone()).unwrap(); - let store :X509Store = builder.build(); - let mut ctx = X509StoreContext::new().unwrap(); - let mut stack = Stack::new().unwrap(); - stack.push(x509.clone()).unwrap(); - ctx.init(&store, &x509, &stack.as_ref(), |ctx| { - ctx.verify_cert().unwrap(); - Ok(()) - }).unwrap(); + let store: X509Store = builder.build(); + let mut ctx = X509StoreContext::new().unwrap(); + let mut stack = Stack::new().unwrap(); + stack.push(x509.clone()).unwrap(); + ctx.init(&store, &x509, &stack.as_ref(), |ctx| { + ctx.verify_cert().unwrap(); + Ok(()) + }) + .unwrap(); } diff --git a/tests/webpki.rs b/tests/webpki.rs index 8f458999..925644d9 100644 --- a/tests/webpki.rs +++ b/tests/webpki.rs @@ -1,81 +1,80 @@ -extern crate webpki; -extern crate untrusted; extern crate rcgen; extern crate ring; +extern crate untrusted; +extern crate webpki; -use rcgen::{Certificate, CertificateParams, - DistinguishedName, DnType, - PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - date_time_ymd}; +use rcgen::{ + date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType, + PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, +}; use untrusted::Input; -use webpki::{EndEntityCert, TLSServerTrustAnchors}; use webpki::trust_anchor_util::cert_der_as_trust_anchor; use webpki::ECDSA_P256_SHA256; -use webpki::{Time, DNSNameRef}; +use webpki::{DNSNameRef, Time}; +use webpki::{EndEntityCert, TLSServerTrustAnchors}; use ring::rand::SystemRandom; use ring::signature::EcdsaKeyPair; use ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING as KALG; -fn sign_msg(cert :&Certificate, msg :&[u8]) -> Vec { - let pk_der = cert.serialize_private_key_der(); - let key_pair = EcdsaKeyPair::from_pkcs8(&KALG, Input::from(&pk_der)).unwrap(); - let system_random = SystemRandom::new(); - let msg_input = Input::from(&msg); - let signature = key_pair.sign(&system_random, msg_input).unwrap(); - signature.as_ref().to_vec() +fn sign_msg(cert: &Certificate, msg: &[u8]) -> Vec { + let pk_der = cert.serialize_private_key_der(); + let key_pair = EcdsaKeyPair::from_pkcs8(&KALG, Input::from(&pk_der)).unwrap(); + let system_random = SystemRandom::new(); + let msg_input = Input::from(&msg); + let signature = key_pair.sign(&system_random, msg_input).unwrap(); + signature.as_ref().to_vec() } #[test] fn test_webpki() { - let not_before = date_time_ymd(1975, 01, 01); - let not_after = date_time_ymd(4096, 01, 01); - let mut distinguished_name = DistinguishedName::new(); - distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); - distinguished_name.push(DnType::CommonName, "Master CA"); - let params = CertificateParams { - alg : PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, - not_before, - not_after, - serial_number : None, - subject_alt_names : vec!["crabs.crabs".to_string(), "localhost".to_string()], - distinguished_name, - }; - let cert = Certificate::from_params(params); + let not_before = date_time_ymd(1975, 01, 01); + let not_after = date_time_ymd(4096, 01, 01); + let mut distinguished_name = DistinguishedName::new(); + distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + distinguished_name.push(DnType::CommonName, "Master CA"); + let params = CertificateParams { + alg: PKCS_WITH_SHA256_WITH_ECDSA_ENCRYPTION, + not_before, + not_after, + serial_number: None, + subject_alt_names: vec!["crabs.crabs".to_string(), "localhost".to_string()], + distinguished_name, + }; + let cert = Certificate::from_params(params); - println!("{}", cert.serialize_pem()); + println!("{}", cert.serialize_pem()); - // Now verify the certificate. + // Now verify the certificate. - let cert_der = cert.serialize_der(); - let trust_anchor = cert_der_as_trust_anchor(Input::from(&cert_der)).unwrap(); - let trust_anchor_list = &[trust_anchor]; - let trust_anchors = TLSServerTrustAnchors(trust_anchor_list); - let end_entity_cert = EndEntityCert::from(Input::from(&cert_der)).unwrap(); + let cert_der = cert.serialize_der(); + let trust_anchor = cert_der_as_trust_anchor(Input::from(&cert_der)).unwrap(); + let trust_anchor_list = &[trust_anchor]; + let trust_anchors = TLSServerTrustAnchors(trust_anchor_list); + let end_entity_cert = EndEntityCert::from(Input::from(&cert_der)).unwrap(); - // Set time to Jan 10, 2004 - let time = Time::from_seconds_since_unix_epoch(0x40_00_00_00); + // Set time to Jan 10, 2004 + let time = Time::from_seconds_since_unix_epoch(0x40_00_00_00); - // (1/3) Check whether the cert is valid - end_entity_cert.verify_is_valid_tls_server_cert( - &[&ECDSA_P256_SHA256], - &trust_anchors, - &[], - time, - ).expect("valid TLS server cert"); + // (1/3) Check whether the cert is valid + end_entity_cert + .verify_is_valid_tls_server_cert(&[&ECDSA_P256_SHA256], &trust_anchors, &[], time) + .expect("valid TLS server cert"); - // (2/3) Check that the cert is valid for the given DNS name - let dns_name = DNSNameRef::try_from_ascii_str("crabs.crabs").unwrap(); - end_entity_cert.verify_is_valid_for_dns_name( - dns_name, - ).expect("valid for DNS name"); + // (2/3) Check that the cert is valid for the given DNS name + let dns_name = DNSNameRef::try_from_ascii_str("crabs.crabs").unwrap(); + end_entity_cert + .verify_is_valid_for_dns_name(dns_name) + .expect("valid for DNS name"); - // (3/3) Check that a message signed by the cert is valid. - let msg = b"Hello, World! This message is signed."; - let signature = sign_msg(&cert, msg); - end_entity_cert.verify_signature( - &ECDSA_P256_SHA256, - Input::from(msg), - Input::from(&signature), - ).expect("signature is valid"); + // (3/3) Check that a message signed by the cert is valid. + let msg = b"Hello, World! This message is signed."; + let signature = sign_msg(&cert, msg); + end_entity_cert + .verify_signature( + &ECDSA_P256_SHA256, + Input::from(msg), + Input::from(&signature), + ) + .expect("signature is valid"); }