aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian Vincent <[email protected]>2017-10-16 18:28:36 -0500
committerBrian Vincent <[email protected]>2017-10-17 20:04:17 -0500
commitb23e5b59cea825859418c2e4fe00c88a1256bc7d (patch)
tree40d99702d54d5c0f4bda71588a7b41eb703740b3
parentRelease v0.9.20 (diff)
downloadrust-openssl-b23e5b59cea825859418c2e4fe00c88a1256bc7d.tar.xz
rust-openssl-b23e5b59cea825859418c2e4fe00c88a1256bc7d.zip
Add an example of making a CA and certs and verifying.
-rw-r--r--openssl/examples/mk_certs.rs153
1 files changed, 153 insertions, 0 deletions
diff --git a/openssl/examples/mk_certs.rs b/openssl/examples/mk_certs.rs
new file mode 100644
index 00000000..0e1dc2a0
--- /dev/null
+++ b/openssl/examples/mk_certs.rs
@@ -0,0 +1,153 @@
+//! A program that generates ca certs, certs verified by the ca, and public
+//! and private keys.
+
+extern crate openssl;
+
+use openssl::asn1::Asn1Time;
+use openssl::bn::BigNum;
+use openssl::error::ErrorStack;
+use openssl::hash::MessageDigest;
+use openssl::pkey::{PKey, PKeyRef};
+use openssl::rand::rand_bytes;
+use openssl::rsa::Rsa;
+use openssl::x509::{X509, X509Ref};
+use openssl::x509::{X509NameBuilder, X509Req, X509ReqBuilder};
+use openssl::x509::extension::{AuthorityKeyIdentifier, BasicConstraints, KeyUsage,
+ SubjectAlternativeName, SubjectKeyIdentifier};
+
+/// Make a CA certificate and private key
+fn mk_ca_cert() -> Result<(X509, PKey), ErrorStack> {
+ let rsa = Rsa::generate(2048)?;
+ let privkey = 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 buf = [0;20];
+ rand_bytes(&mut buf)?;
+ BigNum::from_slice(&buf)?.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(&privkey)?;
+ let not_before = Asn1Time::days_from_now(0)?;
+ cert_builder.set_not_before(&not_before)?;
+ let not_after = Asn1Time::days_from_now(365)?;
+ cert_builder.set_not_after(&not_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(&privkey, MessageDigest::sha256())?;
+ let cert = cert_builder.build();
+
+ Ok((cert, privkey))
+}
+
+/// Make a X509 request with the given private key
+fn mk_request(privkey: &PKey) -> Result<(X509Req), ErrorStack> {
+ let mut req_builder = X509ReqBuilder::new()?;
+ req_builder.set_pubkey(&privkey)?;
+
+ 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(&privkey, 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_privkey: &PKeyRef) -> Result<(X509, PKey), ErrorStack> {
+ let rsa = Rsa::generate(2048)?;
+ let privkey = PKey::from_rsa(rsa)?;
+
+ let req = mk_request(&privkey)?;
+
+ let mut cert_builder = X509::builder()?;
+ cert_builder.set_version(2)?;
+ let serial_number = {
+ let mut buf = [0;20];
+ rand_bytes(&mut buf)?;
+ BigNum::from_slice(&buf)?.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(&privkey)?;
+ let not_before = Asn1Time::days_from_now(0)?;
+ cert_builder.set_not_before(&not_before)?;
+ let not_after = Asn1Time::days_from_now(365)?;
+ cert_builder.set_not_after(&not_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_privkey, MessageDigest::sha256())?;
+ let cert = cert_builder.build();
+
+ Ok((cert, privkey))
+}
+
+fn real_main() -> Result<(), ErrorStack> {
+ let (ca_cert, ca_privkey) = mk_ca_cert()?;
+ let (cert, _privkey) = mk_ca_signed_cert(&ca_cert, &ca_privkey)?;
+
+ // Verify that this cert was issued by this ca
+ match ca_cert.issued(&cert) {
+ Err(ver_err) => println!("Failed to verify certificate: {}", ver_err),
+ Ok(()) => println!("Certificate verified!"),
+ };
+
+ Ok(())
+}
+
+fn main() {
+ match real_main() {
+ Ok(()) => println!("Finished."),
+ Err(e) => println!("Error: {}", e),
+ };
+}