| //! Generate a new certificate, and sign it with an existing root or | ||
| //! intermediate certificate. | ||
| //! | ||
| //! Requires four positional command line arguments: | ||
| //! * File path to PEM containing signer's key pair | ||
| //! * File path to PEM containing signer's certificate | ||
| //! * File path for generated PEM containing output key pair | ||
| //! * File path for generated PEM containing output certificate | ||
| use std::error::Error; | ||
| use std::fs; | ||
| use std::path::PathBuf; | ||
| use rcgen::{CertificateParams, DnType, ExtendedKeyUsagePurpose, Issuer, KeyPair, KeyUsagePurpose}; | ||
| use time::{Duration, OffsetDateTime}; | ||
| fn main() -> Result<(), Box<dyn Error>> { | ||
| let mut args = std::env::args().skip(1); | ||
| let signer_keys_file = PathBuf::from( | ||
| args.next() | ||
| .ok_or("provide signer's pem keys file as 1st argument")?, | ||
| ); | ||
| let signer_cert_file = PathBuf::from( | ||
| args.next() | ||
| .ok_or("provide signer's pem certificate file as 2nd argument")?, | ||
| ); | ||
| let output_keys_file = | ||
| PathBuf::from(args.next().ok_or("output pem keys file as 3rd argument")?); | ||
| let output_cert_file = PathBuf::from(args.next().ok_or("output pem cert file as 4th fourth")?); | ||
| // Read existing certificate authority | ||
| let keys_pem = fs::read_to_string(&signer_keys_file)?; | ||
| let cert_pem = fs::read_to_string(&signer_cert_file)?; | ||
| let key_pair = KeyPair::from_pem(&keys_pem)?; | ||
| let signer = Issuer::from_ca_cert_pem(&cert_pem, key_pair)?; | ||
| // Create a new signed server certificate | ||
| const DOMAIN: &str = "example.domain"; | ||
| let sans = vec![DOMAIN.into()]; | ||
| let mut params = CertificateParams::new(sans)?; | ||
| params.distinguished_name.push(DnType::CommonName, DOMAIN); | ||
| params.use_authority_key_identifier_extension = true; | ||
| params.key_usages.push(KeyUsagePurpose::DigitalSignature); | ||
| params | ||
| .extended_key_usages | ||
| .push(ExtendedKeyUsagePurpose::ServerAuth); | ||
| const DAY: Duration = Duration::days(1); | ||
| let yesterday = OffsetDateTime::now_utc() | ||
| .checked_sub(DAY) | ||
| .ok_or("invalid yesterday")?; | ||
| let tomorrow = OffsetDateTime::now_utc() | ||
| .checked_add(DAY) | ||
| .ok_or("invalid tomorrow")?; | ||
| params.not_before = yesterday; | ||
| params.not_after = tomorrow; | ||
| let output_keys = KeyPair::generate()?; | ||
| let output_cert = params.signed_by(&output_keys, &signer)?; | ||
| // Write new certificate | ||
| fs::write(&output_keys_file, output_keys.serialize_pem())?; | ||
| fs::write(&output_cert_file, output_cert.pem())?; | ||
| println!("Wrote signed leaf certificate:"); | ||
| println!(" keys: {}", output_keys_file.display()); | ||
| println!(" cert: {}", output_cert_file.display()); | ||
| println!(); | ||
| Ok(()) | ||
| } |
| { | ||
| "git": { | ||
| "sha1": "957a3d80d90bac59123b664808a31727b2a8e767" | ||
| "sha1": "5693362c2ecc8ac8315e48caa1facb18c76574db" | ||
| }, | ||
| "path_in_vcs": "rcgen" | ||
| } |
+10
-2
@@ -81,2 +81,3 @@ # This file is automatically @generated by Cargo. | ||
| "aws-lc-sys", | ||
| "untrusted 0.7.1", | ||
| "zeroize", | ||
@@ -532,3 +533,3 @@ ] | ||
| name = "rcgen" | ||
| version = "0.14.5" | ||
| version = "0.14.6" | ||
| dependencies = [ | ||
@@ -585,3 +586,3 @@ "aws-lc-rs", | ||
| "libc", | ||
| "untrusted", | ||
| "untrusted 0.9.0", | ||
| "windows-sys 0.52.0", | ||
@@ -734,2 +735,8 @@ ] | ||
| name = "untrusted" | ||
| version = "0.7.1" | ||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" | ||
| [[package]] | ||
| name = "untrusted" | ||
| version = "0.9.0" | ||
@@ -943,2 +950,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | ||
| "asn1-rs", | ||
| "aws-lc-rs", | ||
| "data-encoding", | ||
@@ -945,0 +953,0 @@ "der-parser", |
+28
-3
@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "rcgen" | ||
| version = "0.14.5" | ||
| version = "0.14.6" | ||
| build = false | ||
@@ -36,3 +36,13 @@ autolib = false | ||
| [package.metadata.docs.rs] | ||
| features = ["x509-parser"] | ||
| features = [ | ||
| "aws_lc_rs", | ||
| "aws_lc_rs_unstable", | ||
| "crypto", | ||
| "ring", | ||
| "x509-parser", | ||
| ] | ||
| rustdoc-args = [ | ||
| "--cfg", | ||
| "rcgen_docsrs", | ||
| ] | ||
@@ -51,2 +61,3 @@ [package.metadata.cargo_check_external_types] | ||
| "aws-lc-rs/aws-lc-sys", | ||
| "x509-parser?/verify-aws", | ||
| ] | ||
@@ -56,2 +67,3 @@ aws_lc_rs_unstable = [ | ||
| "aws-lc-rs/unstable", | ||
| "x509-parser?/verify-aws", | ||
| ] | ||
@@ -72,2 +84,3 @@ crypto = [] | ||
| "dep:ring", | ||
| "x509-parser?/verify", | ||
| ] | ||
@@ -93,2 +106,10 @@ | ||
| [[example]] | ||
| name = "sign-leaf-with-pem-files" | ||
| path = "examples/sign-leaf-with-pem-files.rs" | ||
| required-features = [ | ||
| "pem", | ||
| "x509-parser", | ||
| ] | ||
| [[example]] | ||
| name = "simple" | ||
@@ -124,3 +145,2 @@ path = "examples/simple.rs" | ||
| version = "0.18" | ||
| features = ["verify"] | ||
| optional = true | ||
@@ -141,1 +161,6 @@ | ||
| version = "0.10" | ||
| [lints.rust.unexpected_cfgs] | ||
| level = "warn" | ||
| priority = 0 | ||
| check-cfg = ["cfg(rcgen_docsrs)"] |
| #[cfg(unix)] | ||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
| use rcgen::{date_time_ymd, CertificateParams, DistinguishedName}; | ||
| use std::fmt::Write; | ||
| use std::fs; | ||
| use rcgen::{date_time_ymd, CertificateParams, DistinguishedName}; | ||
| let mut params: CertificateParams = Default::default(); | ||
@@ -8,0 +9,0 @@ params.not_before = date_time_ymd(2021, 5, 19); |
@@ -0,4 +1,5 @@ | ||
| use rcgen::DnValue::PrintableString; | ||
| use rcgen::{ | ||
| BasicConstraints, Certificate, CertificateParams, DnType, DnValue::PrintableString, | ||
| ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, KeyUsagePurpose, | ||
| BasicConstraints, Certificate, CertificateParams, DnType, ExtendedKeyUsagePurpose, IsCa, | ||
| Issuer, KeyPair, KeyUsagePurpose, | ||
| }; | ||
@@ -5,0 +6,0 @@ use time::{Duration, OffsetDateTime}; |
@@ -1,4 +0,5 @@ | ||
| use rcgen::{date_time_ymd, CertificateParams, DistinguishedName, DnType, KeyPair, SanType}; | ||
| use std::fs; | ||
| use rcgen::{date_time_ymd, CertificateParams, DistinguishedName, DnType, KeyPair, SanType}; | ||
| fn main() -> Result<(), Box<dyn std::error::Error>> { | ||
@@ -5,0 +6,0 @@ let mut params: CertificateParams = Default::default(); |
+1
-2
@@ -5,4 +5,3 @@ #[cfg(feature = "pem")] | ||
| use time::OffsetDateTime; | ||
| use yasna::DERWriter; | ||
| use yasna::Tag; | ||
| use yasna::{DERWriter, Tag}; | ||
@@ -9,0 +8,0 @@ use crate::key_pair::sign_der; |
+24
-28
@@ -13,3 +13,3 @@ use std::hash::Hash; | ||
| #[cfg(feature = "x509-parser")] | ||
| use crate::{DistinguishedName, SanType}; | ||
| use crate::{DistinguishedName, ExtendedKeyUsagePurpose, KeyUsagePurpose, SanType}; | ||
@@ -79,3 +79,3 @@ /// A public key, extracted from a CSR | ||
| impl CertificateSigningRequestParams { | ||
| /// Parse a certificate signing request from the ASCII PEM format | ||
| /// Parse and verify a certificate signing request from the ASCII PEM format | ||
| /// | ||
@@ -89,15 +89,20 @@ /// See [`from_der`](Self::from_der) for more details. | ||
| /// Parse a certificate signing request from DER-encoded bytes | ||
| /// Parse and verify a certificate signing request from DER-encoded bytes | ||
| /// | ||
| /// Currently, this only supports the `Subject Alternative Name` extension. | ||
| /// On encountering other extensions, this function will return an error. | ||
| /// Currently, this supports the following extensions: | ||
| /// - `Subject Alternative Name` (see [`SanType`]) | ||
| /// - `Key Usage` (see [`KeyUsagePurpose`]) | ||
| /// - `Extended Key Usage` (see [`ExtendedKeyUsagePurpose`]) | ||
| /// | ||
| /// [`rustls_pemfile::csr()`] is often used to obtain a [`CertificateSigningRequestDer`] from | ||
| /// On encountering other extensions, this function will return [`Error::UnsupportedExtension`]. | ||
| /// If the request's signature is invalid, it will return | ||
| /// [`Error::InvalidCertificationRequestSignature`]. | ||
| /// | ||
| /// The [`PemObject`] trait is often used to obtain a [`CertificateSigningRequestDer`] from | ||
| /// PEM input. If you already have a byte slice containing DER, it can trivially be converted | ||
| /// into [`CertificateSigningRequestDer`] using the [`Into`] trait. | ||
| /// | ||
| /// [`rustls_pemfile::csr()`]: https://docs.rs/rustls-pemfile/latest/rustls_pemfile/fn.csr.html | ||
| /// [`PemObject`]: pki_types::pem::PemObject | ||
| #[cfg(feature = "x509-parser")] | ||
| pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result<Self, Error> { | ||
| use crate::KeyUsagePurpose; | ||
| use x509_parser::prelude::FromDer; | ||
@@ -108,3 +113,4 @@ | ||
| .1; | ||
| csr.verify_signature().map_err(|_| Error::RingUnspecified)?; | ||
| csr.verify_signature() | ||
| .map_err(|_| Error::InvalidCertificationRequestSignature)?; | ||
| let alg_oid = csr | ||
@@ -142,33 +148,23 @@ .signature_algorithm | ||
| if eku.any { | ||
| params.insert_extended_key_usage(crate::ExtendedKeyUsagePurpose::Any); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::Any); | ||
| } | ||
| if eku.server_auth { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::ServerAuth, | ||
| ); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ServerAuth); | ||
| } | ||
| if eku.client_auth { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::ClientAuth, | ||
| ); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::ClientAuth); | ||
| } | ||
| if eku.code_signing { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::CodeSigning, | ||
| ); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::CodeSigning); | ||
| } | ||
| if eku.email_protection { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::EmailProtection, | ||
| ExtendedKeyUsagePurpose::EmailProtection, | ||
| ); | ||
| } | ||
| if eku.time_stamping { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::TimeStamping, | ||
| ); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::TimeStamping); | ||
| } | ||
| if eku.ocsp_signing { | ||
| params.insert_extended_key_usage( | ||
| crate::ExtendedKeyUsagePurpose::OcspSigning, | ||
| ); | ||
| params.insert_extended_key_usage(ExtendedKeyUsagePurpose::OcspSigning); | ||
| } | ||
@@ -186,3 +182,2 @@ if !eku.other.is_empty() { | ||
| // * is_ca | ||
| // * extended_key_usages | ||
| // * name_constraints | ||
@@ -220,6 +215,7 @@ // and any other extensions. | ||
| mod tests { | ||
| use crate::{CertificateParams, ExtendedKeyUsagePurpose, KeyPair, KeyUsagePurpose}; | ||
| use x509_parser::certification_request::X509CertificationRequest; | ||
| use x509_parser::prelude::{FromDer, ParsedExtension}; | ||
| use crate::{CertificateParams, ExtendedKeyUsagePurpose, KeyPair, KeyUsagePurpose}; | ||
| #[test] | ||
@@ -226,0 +222,0 @@ fn dont_write_sans_extension_if_no_sans_are_present() { |
+5
-0
@@ -13,3 +13,6 @@ use std::fmt; | ||
| CouldNotParseKeyPair, | ||
| /// The CSR signature is invalid | ||
| #[cfg(feature = "x509-parser")] | ||
| InvalidCertificationRequestSignature, | ||
| #[cfg(feature = "x509-parser")] | ||
| /// Invalid subject alternative name type | ||
@@ -66,2 +69,4 @@ InvalidNameType, | ||
| #[cfg(feature = "x509-parser")] | ||
| InvalidCertificationRequestSignature => write!(f, "Invalid CSR signature")?, | ||
| #[cfg(feature = "x509-parser")] | ||
| InvalidNameType => write!(f, "Invalid subject alternative name type")?, | ||
@@ -68,0 +73,0 @@ InvalidAsn1String(e) => write!(f, "{e}")?, |
+8
-12
| #[cfg(feature = "crypto")] | ||
| use std::fmt; | ||
| #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] | ||
| use aws_lc_rs::unstable::signature::PqdsaKeyPair; | ||
| #[cfg(feature = "pem")] | ||
@@ -25,9 +27,8 @@ use pem::Pem; | ||
| }; | ||
| use crate::sign_algo::SignatureAlgorithm; | ||
| #[cfg(feature = "crypto")] | ||
| use crate::sign_algo::{algo::*, SignAlgo}; | ||
| use crate::Error; | ||
| #[cfg(feature = "pem")] | ||
| use crate::ENCODE_CONFIG; | ||
| use crate::{sign_algo::SignatureAlgorithm, Error}; | ||
| #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] | ||
| use aws_lc_rs::unstable::signature::PqdsaKeyPair; | ||
@@ -683,6 +684,4 @@ /// A key pair variant | ||
| pub fn from_der(spki_der: &[u8]) -> Result<Self, Error> { | ||
| use x509_parser::{ | ||
| prelude::FromDer, | ||
| x509::{AlgorithmIdentifier, SubjectPublicKeyInfo}, | ||
| }; | ||
| use x509_parser::prelude::FromDer; | ||
| use x509_parser::x509::{AlgorithmIdentifier, SubjectPublicKeyInfo}; | ||
@@ -767,8 +766,5 @@ let (rem, spki) = | ||
| use super::*; | ||
| use crate::ring_like::rand::SystemRandom; | ||
| use crate::ring_like::signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING}; | ||
| use crate::ring_like::{ | ||
| rand::SystemRandom, | ||
| signature::{EcdsaKeyPair, ECDSA_P256_SHA256_FIXED_SIGNING}, | ||
| }; | ||
| #[cfg(all(feature = "x509-parser", feature = "pem"))] | ||
@@ -775,0 +771,0 @@ #[test] |
+16
-18
@@ -32,3 +32,3 @@ /*! | ||
| #![deny(missing_docs)] | ||
| #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] | ||
| #![cfg_attr(rcgen_docsrs, feature(doc_cfg))] | ||
| #![warn(unreachable_pub)] | ||
@@ -45,14 +45,2 @@ | ||
| #[cfg(feature = "pem")] | ||
| use pem::Pem; | ||
| use pki_types::CertificateDer; | ||
| use time::{OffsetDateTime, Time}; | ||
| use yasna::models::ObjectIdentifier; | ||
| use yasna::models::{GeneralizedTime, UTCTime}; | ||
| use yasna::tags::{TAG_BMPSTRING, TAG_TELETEXSTRING, TAG_UNIVERSALSTRING}; | ||
| use yasna::DERWriter; | ||
| use yasna::Tag; | ||
| use crate::string::{BmpString, Ia5String, PrintableString, TeletexString, UniversalString}; | ||
| pub use certificate::{ | ||
@@ -70,6 +58,8 @@ date_time_ymd, Attribute, BasicConstraints, Certificate, CertificateParams, CidrSubnet, | ||
| pub use key_pair::KeyPair; | ||
| pub use key_pair::PublicKeyData; | ||
| #[cfg(all(feature = "crypto", feature = "aws_lc_rs"))] | ||
| pub use key_pair::RsaKeySize; | ||
| pub use key_pair::{SigningKey, SubjectPublicKeyInfo}; | ||
| pub use key_pair::{PublicKeyData, SigningKey, SubjectPublicKeyInfo}; | ||
| #[cfg(feature = "pem")] | ||
| use pem::Pem; | ||
| use pki_types::CertificateDer; | ||
| #[cfg(feature = "crypto")] | ||
@@ -79,3 +69,9 @@ use ring_like::digest; | ||
| pub use sign_algo::SignatureAlgorithm; | ||
| use time::{OffsetDateTime, Time}; | ||
| use yasna::models::{GeneralizedTime, ObjectIdentifier, UTCTime}; | ||
| use yasna::tags::{TAG_BMPSTRING, TAG_TELETEXSTRING, TAG_UNIVERSALSTRING}; | ||
| use yasna::{DERWriter, Tag}; | ||
| use crate::string::{BmpString, Ia5String, PrintableString, TeletexString, UniversalString}; | ||
| mod certificate; | ||
@@ -994,6 +990,6 @@ mod crl; | ||
| mod test_ip_address_from_octets { | ||
| use super::super::ip_addr_from_octets; | ||
| use super::super::Error; | ||
| use std::net::IpAddr; | ||
| use super::super::{ip_addr_from_octets, Error}; | ||
| #[test] | ||
@@ -1043,6 +1039,8 @@ fn ipv4() { | ||
| mod test_san_type_from_general_name { | ||
| use crate::SanType; | ||
| use std::net::IpAddr; | ||
| use x509_parser::extensions::GeneralName; | ||
| use crate::SanType; | ||
| #[test] | ||
@@ -1049,0 +1047,0 @@ fn with_ipv4() { |
+6
-8
| use std::fmt; | ||
| use std::hash::{Hash, Hasher}; | ||
| #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] | ||
| use aws_lc_rs::unstable::signature::{ | ||
| PqdsaSigningAlgorithm, ML_DSA_44_SIGNING, ML_DSA_65_SIGNING, ML_DSA_87_SIGNING, | ||
| }; | ||
| use yasna::models::ObjectIdentifier; | ||
| use yasna::DERWriter; | ||
| use yasna::Tag; | ||
| use yasna::{DERWriter, Tag}; | ||
@@ -11,6 +14,2 @@ #[cfg(feature = "crypto")] | ||
| use crate::Error; | ||
| #[cfg(all(feature = "aws_lc_rs_unstable", not(feature = "fips")))] | ||
| use aws_lc_rs::unstable::signature::{ | ||
| PqdsaSigningAlgorithm, ML_DSA_44_SIGNING, ML_DSA_65_SIGNING, ML_DSA_87_SIGNING, | ||
| }; | ||
@@ -123,6 +122,5 @@ #[cfg(feature = "crypto")] | ||
| pub(crate) mod algo { | ||
| use super::*; | ||
| use crate::oid::*; | ||
| use super::*; | ||
| /// RSA signing with PKCS#1 1.5 padding and SHA-256 hashing as per [RFC 4055](https://tools.ietf.org/html/rfc4055) | ||
@@ -129,0 +127,0 @@ pub static PKCS_RSA_SHA256: SignatureAlgorithm = SignatureAlgorithm { |
+3
-2
| //! ASN.1 string types | ||
| use std::{fmt, str::FromStr}; | ||
| use std::fmt; | ||
| use std::str::FromStr; | ||
@@ -581,3 +582,3 @@ use crate::{Error, InvalidAsn1String}; | ||
| // (https://www.unicode.org/reports/tr19/tr19-9.html#Introduction) | ||
| // So any `char` is a valid UTF-32, we just cast it to perform the convertion. | ||
| // So any `char` is a valid UTF-32, we just cast it to perform the conversion. | ||
| for char in value.chars().map(|char| char as u32) { | ||
@@ -584,0 +585,0 @@ bytes.extend(char.to_be_bytes()) |
Sorry, the diff of this file is not supported yet