README.rdoc in certificate_authority-0.1.6 vs README.rdoc in certificate_authority-1.0.0
- old
+ new
@@ -1,7 +1,11 @@
= CertificateAuthority - Because it shouldn't be this damned complicated
+{<img src="https://travis-ci.org/cchandler/certificate_authority.png?branch=master" alt="Build Status" />}[https://travis-ci.org/cchandler/certificate_authority]
+{<img src="https://codeclimate.com/github/cchandler/certificate_authority.png" alt="Code Climate" />}[https://codeclimate.com/github/cchandler/certificate_authority]
+{<img src="https://coveralls.io/repos/cchandler/certificate_authority/badge.png?branch=master" alt="Code Coverage" />}[https://coveralls.io/r/cchandler/certificate_authority]
+
This is meant to provide a (more) programmer-friendly implementation of all the basic functionality contained in RFC-3280 to implement your own certificate authority.
You can generate root certificates, intermediate certificates, and terminal certificates. You can also generate/manage Certificate Revocation Lists (CRLs) and Online Certificate Status Protocol (OCSP) messages.
Because this library is built using the native Ruby bindings for OpenSSL it also supports PKCS#11 cryptographic hardware for secure maintenance of private key materials.
@@ -58,11 +62,11 @@
intermediate.signing_entity = true
intermediate.parent = root
signing_profile = {"extensions" => {"keyUsage" => {"usage" => ["critical", "keyCertSign"] }} }
intermediate.sign!(signing_profile)
-All we have to do is create another certificate like we did with the root. In this example we gave it the next available serial number which for us, was 2. We then generate (and save!) key material for this new entity. Even the +signing_entity+ is set to true so this certificate can sign other certificates. The difference here is that the +parent+ field is set to the root. Going forward, whatever entity you want to sign a certificate, you set that entity to be the parent. In this case, our root will be responsible for signing this intermediate when we call +sign!+.
+All we have to do is create another certificate like we did with the root. In this example we gave it the next available serial number, which for us, was 2. We then generate (and save!) key material for this new entity. Even the +signing_entity+ is set to true so this certificate can sign other certificates. The difference here is that the +parent+ field is set to the root. Going forward, whatever entity you want to sign a certificate, you set that entity to be the parent. In this case, our root will be responsible for signing this intermediate when we call +sign!+.
= Creating new certificates (in general)
Now that we have a root certificate (and possibly an intermediate) we can sign end-user certificates. It is, perhaps unsurprisingly, similar to all the others:
@@ -191,10 +195,82 @@
[cps_uris] This is an array of URIs where a client or human can go to get information related to your certification practice.
[user_notice] This is a nested field containing explicit human readable text if you want to embed a notice in the certificate body related to certification practices. It contains nested attributes of +explicit_text+ for the notice, +organization+ and +notice_numbers+. Refer to the RFC for specific implications of how these are set, but whether or not browsers implement the correct specified behavior for their presence is another issue.
+= Certificate Signing Requests (CSRs)
+
+If you want certificate requestors to be able to request certificates without moving the private key you'll need to generate a CSR and submit it to the certificate authority.
+
+Here's an example of using +certificate_authority+ to generate a CSR.
+
+ csr = CertificateAuthority::SigningRequest.new
+ dn = CertificateAuthority::DistinguishedName.new
+ dn.common_name = "localhost"
+ csr.distinguished_name = dn
+ k = CertificateAuthority::MemoryKeyMaterial.new
+ k.generate_key(2048)
+ csr.key_material = k
+ csr.digest = "SHA256"
+ csr.to_x509_csr.to_pem
+
+Similarly, reading a CSR in is as simple as providing the PEM formatted version to +SigningRequest.from_x509_csr+.
+
+ csr = CertificateAuthority::SigningRequest.from_x509_csr(@pem_csr)
+
+Once you have the CSR in the form of a +SigningRequest+ you can transform it to a +Certificate+ with +to_cert+. At this point it works just like any other certificate. You'll have to provide a serial number to actually sign it.
+
+= Certificate Revocation Lists (CRLs)
+
+Revocation lists let clients know when a certificate in the wild should no longer be trusted.
+
+Like end-user certificates, CRLs have to be signed by a signing authority to be valid. Additionally, you will need to furnish a +nextUpdate+ value that indicates to the client when it should look for updates to the CRL and how long it should consider a cached value valid.
+
+Ideally you would place the result CRL somewhere generally accessible on the Internet and reference the URI in the +crlDistributionPoints+ extension on issued certificates.
+
+ crl = CertificateAuthority::CertificateRevocationList.new
+ crl << certificate # Some CertificateAuthority::Certificate
+ crl << serial_number # Also works with plain CertificateAuthority::SerialNumber
+ crl.parent = root_certificate # A valid root
+ crl.next_update = (60 * 60 * 10) # 10 Hours
+ crl.sign!
+ crl.to_pem
+
+= OCSP Support
+
+OCSP is the Online Certificate Status Protocol. It provides a mechanism to query an authority to see if a certificate is still valid without downloading an entire CRL. To use this mechanism you provide a URI in the Authority Information Access extension.
+If a client wishes to check the validity of a certificate they can query this endpoint.
+This request will only contain serial numbers, so you'll need to uniquely identify your authority in the AIA path.
+
+If a client sends you a DER encoded OCSP request you can read it out via +OCSPRequestReader+
+
+ ocsp_request_reader = CertificateAuthority::OCSPRequestReader.from_der(@ocsp_request.to_der)
+ ocsp_request_reader.serial_numbers
+
+Then, you can construct a response like this
+
+ response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
+ response_builder.parent = root
+ response = response_builder.build_response # Returns OpenSSL::OCSP::Response
+ response.to_der
+
+The response builder will copy a (possible) nonce from the request. By default, the +OCSPResponseBuilder+ will say that every certificate is GOOD.
+You should definitely override this if you plan on revoking certificates.
+If you want to override this you'll need to supply a proc/lambda that takes a serial number and returns an array of status and reason.
+
+ response_builder = CertificateAuthority::OCSPResponseBuilder.from_request_reader(ocsp_request_reader)
+ response_builder.verification_mechanism = lambda {|certid|
+ [CertificateAuthority::OCSPResponseBuilder::REVOKED,CertificateAuthority::OCSPResponseBuilder::UNSPECIFIED]
+ }
+ response_builder.parent = root
+ response = response_builder.build_response # Response will say everything is revoked for unspecified reasons
+
+Lastly, you can configure a nextUpdate time in the response. This is the length of time for which a client may consider this response valid.
+The default is 15 minutes.
+
+ response_builder.next_update = 30 * 60 # 30 minutes
+
= PKCS#11 Support
If you happen to have a PKCS#11 compliant hardware token you can use +certificate_authority+ to maintain private key materials in hardware security modules. At this point the scope of operating that hardware is out of scope of this README but it's there and it is supported.
To configure a certificate to utilize PKCS#11 instead of in memory keys all you need to do is:
@@ -221,17 +297,30 @@
[Your company] Do you make a PKCS#11 device? I'd love to get it working but I probably can't afford your device. Get in touch with me and if you're willing to loan me one for a week I can get it listed.
Also of note, I have gotten these to work with 32-bit copies of Ubuntu 10.10 and pre-Snow Leopard versions of OS X. If you are running Snow Leopard you're out of luck since none of the companies I've contacted make a 64 bit driver.
-= Coming Soon
+= Hopefully in the future
* More PKCS#11 hardware (I need driver support from the manufacturers)
+
+= Todone
+
* Support for working with CSRs to request & issue certificates
+* OCSP support
= Misc notes
* Firefox will complain about root/intermediate certificates unless both digitalSignature and keyEncipherment are specified as keyUsage attributes. Thanks diogomonica
+
+= Special thanks and Contributions
+
+* Diogo Monica @diogo
+* Justin Cummins @sul3n3t
+* @databus23
+* Colin Jones @trptcolin
+* Eric Monti @emonti
+* TJ Vanderpoel @bougyman
== Meta
Written by Chris Chandler(http://chrischandler.name)