192f3ab15Sopenharmony_ci#![allow(clippy::uninlined_format_args)]
292f3ab15Sopenharmony_ci
392f3ab15Sopenharmony_ci//! A program that generates ca certs, certs verified by the ca, and public
492f3ab15Sopenharmony_ci//! and private keys.
592f3ab15Sopenharmony_ci
692f3ab15Sopenharmony_ciuse openssl::asn1::Asn1Time;
792f3ab15Sopenharmony_ciuse openssl::bn::{BigNum, MsbOption};
892f3ab15Sopenharmony_ciuse openssl::error::ErrorStack;
992f3ab15Sopenharmony_ciuse openssl::hash::MessageDigest;
1092f3ab15Sopenharmony_ciuse openssl::pkey::{PKey, PKeyRef, Private};
1192f3ab15Sopenharmony_ciuse openssl::rsa::Rsa;
1292f3ab15Sopenharmony_ciuse openssl::x509::extension::{
1392f3ab15Sopenharmony_ci    AuthorityKeyIdentifier, BasicConstraints, KeyUsage, SubjectAlternativeName,
1492f3ab15Sopenharmony_ci    SubjectKeyIdentifier,
1592f3ab15Sopenharmony_ci};
1692f3ab15Sopenharmony_ciuse openssl::x509::{X509NameBuilder, X509Ref, X509Req, X509ReqBuilder, X509VerifyResult, X509};
1792f3ab15Sopenharmony_ci
1892f3ab15Sopenharmony_ci/// Make a CA certificate and private key
1992f3ab15Sopenharmony_cifn mk_ca_cert() -> Result<(X509, PKey<Private>), ErrorStack> {
2092f3ab15Sopenharmony_ci    let rsa = Rsa::generate(2048)?;
2192f3ab15Sopenharmony_ci    let key_pair = PKey::from_rsa(rsa)?;
2292f3ab15Sopenharmony_ci
2392f3ab15Sopenharmony_ci    let mut x509_name = X509NameBuilder::new()?;
2492f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("C", "US")?;
2592f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("ST", "TX")?;
2692f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("O", "Some CA organization")?;
2792f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("CN", "ca test")?;
2892f3ab15Sopenharmony_ci    let x509_name = x509_name.build();
2992f3ab15Sopenharmony_ci
3092f3ab15Sopenharmony_ci    let mut cert_builder = X509::builder()?;
3192f3ab15Sopenharmony_ci    cert_builder.set_version(2)?;
3292f3ab15Sopenharmony_ci    let serial_number = {
3392f3ab15Sopenharmony_ci        let mut serial = BigNum::new()?;
3492f3ab15Sopenharmony_ci        serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
3592f3ab15Sopenharmony_ci        serial.to_asn1_integer()?
3692f3ab15Sopenharmony_ci    };
3792f3ab15Sopenharmony_ci    cert_builder.set_serial_number(&serial_number)?;
3892f3ab15Sopenharmony_ci    cert_builder.set_subject_name(&x509_name)?;
3992f3ab15Sopenharmony_ci    cert_builder.set_issuer_name(&x509_name)?;
4092f3ab15Sopenharmony_ci    cert_builder.set_pubkey(&key_pair)?;
4192f3ab15Sopenharmony_ci    let not_before = Asn1Time::days_from_now(0)?;
4292f3ab15Sopenharmony_ci    cert_builder.set_not_before(&not_before)?;
4392f3ab15Sopenharmony_ci    let not_after = Asn1Time::days_from_now(365)?;
4492f3ab15Sopenharmony_ci    cert_builder.set_not_after(&not_after)?;
4592f3ab15Sopenharmony_ci
4692f3ab15Sopenharmony_ci    cert_builder.append_extension(BasicConstraints::new().critical().ca().build()?)?;
4792f3ab15Sopenharmony_ci    cert_builder.append_extension(
4892f3ab15Sopenharmony_ci        KeyUsage::new()
4992f3ab15Sopenharmony_ci            .critical()
5092f3ab15Sopenharmony_ci            .key_cert_sign()
5192f3ab15Sopenharmony_ci            .crl_sign()
5292f3ab15Sopenharmony_ci            .build()?,
5392f3ab15Sopenharmony_ci    )?;
5492f3ab15Sopenharmony_ci
5592f3ab15Sopenharmony_ci    let subject_key_identifier =
5692f3ab15Sopenharmony_ci        SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(None, None))?;
5792f3ab15Sopenharmony_ci    cert_builder.append_extension(subject_key_identifier)?;
5892f3ab15Sopenharmony_ci
5992f3ab15Sopenharmony_ci    cert_builder.sign(&key_pair, MessageDigest::sha256())?;
6092f3ab15Sopenharmony_ci    let cert = cert_builder.build();
6192f3ab15Sopenharmony_ci
6292f3ab15Sopenharmony_ci    Ok((cert, key_pair))
6392f3ab15Sopenharmony_ci}
6492f3ab15Sopenharmony_ci
6592f3ab15Sopenharmony_ci/// Make a X509 request with the given private key
6692f3ab15Sopenharmony_cifn mk_request(key_pair: &PKey<Private>) -> Result<X509Req, ErrorStack> {
6792f3ab15Sopenharmony_ci    let mut req_builder = X509ReqBuilder::new()?;
6892f3ab15Sopenharmony_ci    req_builder.set_pubkey(key_pair)?;
6992f3ab15Sopenharmony_ci
7092f3ab15Sopenharmony_ci    let mut x509_name = X509NameBuilder::new()?;
7192f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("C", "US")?;
7292f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("ST", "TX")?;
7392f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("O", "Some organization")?;
7492f3ab15Sopenharmony_ci    x509_name.append_entry_by_text("CN", "www.example.com")?;
7592f3ab15Sopenharmony_ci    let x509_name = x509_name.build();
7692f3ab15Sopenharmony_ci    req_builder.set_subject_name(&x509_name)?;
7792f3ab15Sopenharmony_ci
7892f3ab15Sopenharmony_ci    req_builder.sign(key_pair, MessageDigest::sha256())?;
7992f3ab15Sopenharmony_ci    let req = req_builder.build();
8092f3ab15Sopenharmony_ci    Ok(req)
8192f3ab15Sopenharmony_ci}
8292f3ab15Sopenharmony_ci
8392f3ab15Sopenharmony_ci/// Make a certificate and private key signed by the given CA cert and private key
8492f3ab15Sopenharmony_cifn mk_ca_signed_cert(
8592f3ab15Sopenharmony_ci    ca_cert: &X509Ref,
8692f3ab15Sopenharmony_ci    ca_key_pair: &PKeyRef<Private>,
8792f3ab15Sopenharmony_ci) -> Result<(X509, PKey<Private>), ErrorStack> {
8892f3ab15Sopenharmony_ci    let rsa = Rsa::generate(2048)?;
8992f3ab15Sopenharmony_ci    let key_pair = PKey::from_rsa(rsa)?;
9092f3ab15Sopenharmony_ci
9192f3ab15Sopenharmony_ci    let req = mk_request(&key_pair)?;
9292f3ab15Sopenharmony_ci
9392f3ab15Sopenharmony_ci    let mut cert_builder = X509::builder()?;
9492f3ab15Sopenharmony_ci    cert_builder.set_version(2)?;
9592f3ab15Sopenharmony_ci    let serial_number = {
9692f3ab15Sopenharmony_ci        let mut serial = BigNum::new()?;
9792f3ab15Sopenharmony_ci        serial.rand(159, MsbOption::MAYBE_ZERO, false)?;
9892f3ab15Sopenharmony_ci        serial.to_asn1_integer()?
9992f3ab15Sopenharmony_ci    };
10092f3ab15Sopenharmony_ci    cert_builder.set_serial_number(&serial_number)?;
10192f3ab15Sopenharmony_ci    cert_builder.set_subject_name(req.subject_name())?;
10292f3ab15Sopenharmony_ci    cert_builder.set_issuer_name(ca_cert.subject_name())?;
10392f3ab15Sopenharmony_ci    cert_builder.set_pubkey(&key_pair)?;
10492f3ab15Sopenharmony_ci    let not_before = Asn1Time::days_from_now(0)?;
10592f3ab15Sopenharmony_ci    cert_builder.set_not_before(&not_before)?;
10692f3ab15Sopenharmony_ci    let not_after = Asn1Time::days_from_now(365)?;
10792f3ab15Sopenharmony_ci    cert_builder.set_not_after(&not_after)?;
10892f3ab15Sopenharmony_ci
10992f3ab15Sopenharmony_ci    cert_builder.append_extension(BasicConstraints::new().build()?)?;
11092f3ab15Sopenharmony_ci
11192f3ab15Sopenharmony_ci    cert_builder.append_extension(
11292f3ab15Sopenharmony_ci        KeyUsage::new()
11392f3ab15Sopenharmony_ci            .critical()
11492f3ab15Sopenharmony_ci            .non_repudiation()
11592f3ab15Sopenharmony_ci            .digital_signature()
11692f3ab15Sopenharmony_ci            .key_encipherment()
11792f3ab15Sopenharmony_ci            .build()?,
11892f3ab15Sopenharmony_ci    )?;
11992f3ab15Sopenharmony_ci
12092f3ab15Sopenharmony_ci    let subject_key_identifier =
12192f3ab15Sopenharmony_ci        SubjectKeyIdentifier::new().build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
12292f3ab15Sopenharmony_ci    cert_builder.append_extension(subject_key_identifier)?;
12392f3ab15Sopenharmony_ci
12492f3ab15Sopenharmony_ci    let auth_key_identifier = AuthorityKeyIdentifier::new()
12592f3ab15Sopenharmony_ci        .keyid(false)
12692f3ab15Sopenharmony_ci        .issuer(false)
12792f3ab15Sopenharmony_ci        .build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
12892f3ab15Sopenharmony_ci    cert_builder.append_extension(auth_key_identifier)?;
12992f3ab15Sopenharmony_ci
13092f3ab15Sopenharmony_ci    let subject_alt_name = SubjectAlternativeName::new()
13192f3ab15Sopenharmony_ci        .dns("*.example.com")
13292f3ab15Sopenharmony_ci        .dns("hello.com")
13392f3ab15Sopenharmony_ci        .build(&cert_builder.x509v3_context(Some(ca_cert), None))?;
13492f3ab15Sopenharmony_ci    cert_builder.append_extension(subject_alt_name)?;
13592f3ab15Sopenharmony_ci
13692f3ab15Sopenharmony_ci    cert_builder.sign(ca_key_pair, MessageDigest::sha256())?;
13792f3ab15Sopenharmony_ci    let cert = cert_builder.build();
13892f3ab15Sopenharmony_ci
13992f3ab15Sopenharmony_ci    Ok((cert, key_pair))
14092f3ab15Sopenharmony_ci}
14192f3ab15Sopenharmony_ci
14292f3ab15Sopenharmony_cifn real_main() -> Result<(), ErrorStack> {
14392f3ab15Sopenharmony_ci    let (ca_cert, ca_key_pair) = mk_ca_cert()?;
14492f3ab15Sopenharmony_ci    let (cert, _key_pair) = mk_ca_signed_cert(&ca_cert, &ca_key_pair)?;
14592f3ab15Sopenharmony_ci
14692f3ab15Sopenharmony_ci    // Verify that this cert was issued by this ca
14792f3ab15Sopenharmony_ci    match ca_cert.issued(&cert) {
14892f3ab15Sopenharmony_ci        X509VerifyResult::OK => println!("Certificate verified!"),
14992f3ab15Sopenharmony_ci        ver_err => println!("Failed to verify certificate: {}", ver_err),
15092f3ab15Sopenharmony_ci    };
15192f3ab15Sopenharmony_ci
15292f3ab15Sopenharmony_ci    Ok(())
15392f3ab15Sopenharmony_ci}
15492f3ab15Sopenharmony_ci
15592f3ab15Sopenharmony_cifn main() {
15692f3ab15Sopenharmony_ci    match real_main() {
15792f3ab15Sopenharmony_ci        Ok(()) => println!("Finished."),
15892f3ab15Sopenharmony_ci        Err(e) => println!("Error: {}", e),
15992f3ab15Sopenharmony_ci    };
16092f3ab15Sopenharmony_ci}
161