Make certificates in Node with CoffeeScript (or any old ECMAScript) using OpenSSL via Ruby.
Authority generates X.509 public key certificates that can be used to:
- Verify the identity of a host on the internet.
- Verify the identity of a peer on the internet.
- Issue additional certificates.
For example, here is a script to make a basic self-signed certificate for an internet mail service:
#!/usr/bin/env coffee
{readFileSync, writeFileSync} = require "fs"
Authority = require "authority"
Authority.createCertificate
"subject":
"common_name": "mail.example.org"
"title": "Example Mail Service"
"email_address": "postmaster@example.org"
"country_code": "CA"
"subject_key": readFileSync "mail.example.org.private.key"
"started_at": (new Date).toJSON()
"expires_at": "2020-01-01T00:00:01.000Z"
"callback": (error, certificate) ->
throw error if error
writeFileSync "mail.example.org.crt", certificate.pem
Run npm install 45678/authority.git to get the module. Require it in your program like so:
Authority = require "authority"
You’ll also need a copy of ruby installed on your computer. Authority employs the OpenSSL bindings in Ruby to construct certificates because Node didn’t have built-in support for that kind of thing when this was written. Authority will run /usr/bin/which ruby to locate your ruby executable. If that doesn’t work, or if you just enjoy being explicit, you can set the path manually with:
Authority.ruby = "/path/to/your/ruby"
Authority.createCertificate(params, callback) accepts the following named params:
subject defines the distinguished name of the subject of the certificate. Authority accepts the following distinguished name attributes: common_name, title, organization, organizational_unit, business_category, email_address, street_address location, region, country_code and user_id. The common_name attribute is the only one that is required.
subject_key is a PEM encoded RSA key that belongs to the subject of the certificate. The public key component of this key defines the public key information section of the certificate. You can pass this parameter as a Buffer or a String. This parameter is not required when you supply a signed_public_key and a signing_key.
signed_public_key is an SPKAC/Netscape SPKI structure that might have been generated via openssl -spkac ... or the <keygen> element in HTML. The public key component of this key becomes the public key information section of the certificate. You can only pass this parameter as a String.
signing_certificate is a PEM encoded X.509 certificate the belongs to the authority that is issuing the certificate. The subject of the signing certificate becomes the issuer of the created certificate. You can pass this parameter as a Buffer or a String. This parameter isn’t required when you’re creating self-signed certificate.
signing_key is a PEM encoded RSA key that belongs to the authority that is issuing the certificate. You can pass this parameter as a Buffer or a String. If you don’t supply a signing_key the certificate will be signed with the
subject_key producing a self-signed certificate.
The started_at and expires_at parameters define the validity period of the certificate. started_at defines the instant in time when the certificate comes into effect. expires_at defines the instant in time when the certificate expires. These parameters should be instances of Date. Both are always required.
serial_number defines the serial number of the certificate. A unique serial number in the form of a SHA1 hash is generated automatically if you omit this parameter.
certificate_authority specifies whether or not the certificate may be used to issue additional certificates. This parameter is optional. By default new certificates will have their basic constraints set to CA:FALSE to indicate that they may not be used to issue certificates under the authority of the issuer. Pass true or {pathlen:0}, {pathlen:1}, etc., to bless the certificate with the authoring capabilities that you require.
callback is a function that will be called when the certificate is ready (or an error occurs). You can pass your callback as a member of the params argument or you can pass it separately as the second argument in the form Authority.createCertificate(params, callback).
When Authority.createCertificate is finished your callback function will receive a certificate as its second argument. Each certificate has the following members:
certificate.pem is a Buffer that contains a PEM encoded binary copy of the certificate. Use this format if you’re saving your certificate to the file system. Or call certificate.pem.toString() to get a UTF-8 representation that you can easily save in a database.
certificate.der is a Buffer that contains a DER encoded binary copy of the certificate. Use this format if you are sending an "application/x-509-user-cert" to a web browser.
certificate.fingerprint is a SHA1 hex digest that uniquely identifies the certificate.
certificate.serialNumber is the serial number of the certificate.
Authority instances make it convenient to certify signed public keys posted from Mozilla, Opera and Webkit (excluding Mobile Safari, unfortunately). That means you can perform secure public key exchange on the web without too much hassle (except that the human interface is unbearable, unfortunately).
Authority = require "authority"
Express = require "express"
HTTPS = require "https"
{readFileSync} = require "fs"
club = new Authority
cert: readFileSync "example.org.crt"
key: readFileSync "example.org.private.key"
httpsOptions =
ca: club.certificate
cert: club.certificate
key: club.key
requestCert: true
rejectUnauthorized: false
(HTTPS.createServer httpsOptions, app = new Express).listen("0443")
app.get "/members/only", (request, response, next) ->
if request.client.authorized
response.statusCode = 200
response.setHeader "Content-Type", "text/plain"
response.end "’Sup friendly member?"
else
response.redirect 303, "/membership/form"
app.get "/membership/form", (request, response, next) ->
response.statusCode = 200
response.setHeader "Content-Type", "text/html"
response.end """
<form method="post" action="/membership">
<input placeholder="Your Name" type="text" name="common_name">
<p>
A <keygen name="signed_public_key">-bit RSA key pair will be
added to your Keychain when you start your membership.
</p>
<button>Start your membership</button>
</form>
"""
app.post "/membership", (request, response, next) ->
club.certify
"common_name": request.params["common_name"]
"signed_public_key": request.params["signed_public_key"]
callback: (error, certificate) ->
response.statusCode = 201
response.setHeader "Connection", "close"
response.setHeader "Content-Type", "application/x-x509-user-cert"
response.end certificate.der
Establishing Identity Without Certification Authorities by Carl Ellison. Published at the 6th USENIX Security Symposium in 1996.
- Authority doesn’t create RSA keys. Generate them yourself with
openssl genrsa -out my.private.key 2048or a similar command. - Authority has no support for X.509 certificate signing requests.
- Authority doesn’t provide methods to read-or-write certificates to-or-from the file system.
- The bundled Ruby script only accepts JSON arguments.