diff options
Diffstat (limited to 'vendor/openssl/examples/mk_certs.rs')
-rw-r--r-- | vendor/openssl/examples/mk_certs.rs | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/vendor/openssl/examples/mk_certs.rs b/vendor/openssl/examples/mk_certs.rs new file mode 100644 index 000000000..48538c7a7 --- /dev/null +++ b/vendor/openssl/examples/mk_certs.rs @@ -0,0 +1,160 @@ +#![allow(clippy::uninlined_format_args)] + +//! A program that generates ca certs, certs verified by the ca, and public +//! and private keys. + +use openssl::asn1::Asn1Time; +use openssl::bn::{BigNum, MsbOption}; +use openssl::error::ErrorStack; +use openssl::hash::MessageDigest; +use openssl::pkey::{PKey, PKeyRef, Private}; +use openssl::rsa::Rsa; +use openssl::x509::extension::{ + AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName, + SubjectKeyIdentifier, +}; +use openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509}; + +/// Make a CA certificate and private key +fn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> { + let rsa = Rsa::generate(2048)?; + let key_pair = PKey::from_rsa(rsa)?; + + let mut x509_name = X509NameBuilder::new()?; + x509_name.append_entry_by_text("C", "US")?; + x509_name.append_entry_by_text("ST", "TX")?; + x509_name.append_entry_by_text("O", "Some CA organization")?; + x509_name.append_entry_by_text("CN", "ca test")?; + let x509_name = x509_name.build(); + + let mut cert_builder = X509::builder()?; + cert_builder.set_version(2)?; + let serial_number = { + let mut serial = BigNum::new()?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; + serial.to_asn1_integer()? + }; + cert_builder.set_serial_number(&serial_number)?; + cert_builder.set_subject_name(&x509_name)?; + cert_builder.set_issuer_name(&x509_name)?; + cert_builder.set_pubkey(&key_pair)?; + let not_before = Asn1Time::days_from_now(0)?; + cert_builder.set_not_before(¬_before)?; + let not_after = Asn1Time::days_from_now(365)?; + cert_builder.set_not_after(¬_after)?; + + cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?; + cert_builder.append_extension( + KeyUsage::new() + .critical() + .key_cert_sign() + .crl_sign() + .build()?, + )?; + + let subject_key_identifier = + SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?; + cert_builder.append_extension(subject_key_identifier)?; + + cert_builder.sign(&key_pair, MessageDigest::sha256())?; + let cert = cert_builder.build(); + + Ok((cert, key_pair)) +} + +/// Make a X509 request with the given private key +fn mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack> { + let mut req_builder = X509ReqBuilder::new()?; + req_builder.set_pubkey(key_pair)?; + + let mut x509_name = X509NameBuilder::new()?; + x509_name.append_entry_by_text("C", "US")?; + x509_name.append_entry_by_text("ST", "TX")?; + x509_name.append_entry_by_text("O", "Some organization")?; + x509_name.append_entry_by_text("CN", "www.example.com")?; + let x509_name = x509_name.build(); + req_builder.set_subject_name(&x509_name)?; + + req_builder.sign(key_pair, MessageDigest::sha256())?; + let req = req_builder.build(); + Ok(req) +} + +/// Make a certificate and private key signed by the given CA cert and private key +fn mk_ca_signed_cert( + ca_cert: &X509Ref, + ca_key_pair: &PKeyRef<Private>, +) -> Result<(X509, PKey<Private>), ErrorStack> { + let rsa = Rsa::generate(2048)?; + let key_pair = PKey::from_rsa(rsa)?; + + let req = mk_request(&key_pair)?; + + let mut cert_builder = X509::builder()?; + cert_builder.set_version(2)?; + let serial_number = { + let mut serial = BigNum::new()?; + serial.rand(159, MsbOption::MAYBE_ZERO, false)?; + serial.to_asn1_integer()? + }; + cert_builder.set_serial_number(&serial_number)?; + cert_builder.set_subject_name(req.subject_name())?; + cert_builder.set_issuer_name(ca_cert.subject_name())?; + cert_builder.set_pubkey(&key_pair)?; + let not_before = Asn1Time::days_from_now(0)?; + cert_builder.set_not_before(¬_before)?; + let not_after = Asn1Time::days_from_now(365)?; + cert_builder.set_not_after(¬_after)?; + + cert_builder.append_extension(BasicConstraints::new().build()?)?; + + cert_builder.append_extension( + KeyUsage::new() + .critical() + .non_repudiation() + .digital_signature() + .key_encipherment() + .build()?, + )?; + + let subject_key_identifier = + SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(subject_key_identifier)?; + + let auth_key_identifier = AuthorityKeyIdentifier::new() + .keyid(false) + .issuer(false) + .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(auth_key_identifier)?; + + let subject_alt_name = SubjectAlternativeName::new() + .dns("*.example.com") + .dns("hello.com") + .build(&cert_builder.x509v3_context(Some(ca_cert), None))?; + cert_builder.append_extension(subject_alt_name)?; + + cert_builder.sign(ca_key_pair, MessageDigest::sha256())?; + let cert = cert_builder.build(); + + Ok((cert, key_pair)) +} + +fn real_main() -> Result<(), ErrorStack> { + let (ca_cert, ca_key_pair) = mk_ca_cert()?; + let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?; + + // Verify that this cert was issued by this ca + match ca_cert.issued(&cert) { + X509VerifyResult::OK => println!("Certificate verified!"), + ver_err => println!("Failed to verify certificate: {}", ver_err), + }; + + Ok(()) +} + +fn main() { + match real_main() { + Ok(()) => println!("Finished."), + Err(e) => println!("Error: {}", e), + }; +} |