So the other day I got a bee in my bonnet and decided I wanted a simple web service I could pass common day X509 objects to and get a JSON representation of that same object. We had recently done a project in Go at work and we found it quick, robust and easy to build, additionally it looks it’s certificate support decent enough so I thought it was the way to go.
In comes Freelancer, I threw my rough (and that’s kind) goals in a paragraph or two and a few days later I had a bid proposal from an engineer in Chicago — Eli Frey.
Based on a quick review of the Go documentation for cryptography it looked like this was going to be pretty straight forward, and for the most part it was – we did find that there were a few cases that just were not possible without more work than we wanted to put in, I will summarize those a little later.
As things progressed we also decided to add the ability to get an X509 certificate from the interface. Normally one would do this by generating a PKCS #10 request (CSR) and sending it to a CA for processing, unfortunately one of those cases that required more work than we wanted to put in was parsing PKCS #10s since go does not as of yet support it. With that said a CSR is really just a self-signed certificate we just did the same thing with a self-signed X509 certificate request.
So how do these interfaces work? Here are a few examples of how you would call them:
Decode a PEM encoded X509 certificate curl -F “[email protected]” “api.x509labs.com/v1/x509/certificate?action=decode&inputEncoding=PEM” Decode a DER encoded X509 certificate curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/certificate?action=decode&inputEncoding=DER” Request and issue an X509 certificate based on a DER encoded self-signed certificate with one hostname openssl genrsa -out request.key 2048 openssl req -config openssl.cfg -subj “/CN=www.example.com” -new -x509 -set_serial 01 -days 1 -key request.key -out request.cer curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/certificate?action=issue&hostnames=bob.com&inputEncoding=DER” Request and issue an X509 certificate based on a PEM encoded self-signed certificate with one hostname openssl genrsa -out request.key 2048 openssl req -config openssl.cfg -subj “/CN=www.example.com” -new -x509 -set_serial 01 -days 1 -key request.key -out request.cer curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/certificate?action=issue&hostnames=bob.com&inputEncoding=PEM” Request and issue an X509 certificate based on a PEM encoded self-signed certificate with several hostnames openssl genrsa -out request.key 2048 openssl req -config openssl.cfg -subj “/CN=www.example.com” -new -x509 -set_serial 01 -days 1 -key request.key -out request.cer curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/certificate?action=issue&hostnames=bob.com,fred.com&inputEncoding=PEM” Decode a set of PEM encoded X509 certificates curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/certificates?action=decode&inputEncoding=PEM” Decode a PEM encoded X509 crl curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/crl?action=decode&inputEncoding=PEM” Decode a DER encoded X509 crl curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/crl?action=decode&inputEncoding=DER” Decode an OCSP response openssl ocsp -noverify -no_nonce -respout ocsp.resp -reqout ocsp.req -issuer ca.cer -cert www.cer -url “http://ocsp2.globalsign.com/gsextendvalg2” -header “HOST” “ocsp2.globalsign.com” -text curl –fail -F “[email protected]” “api.x509labs.com/v1/x509/ocsp?action=decode&type=response”
So even though this started out as a pet project I actually think these interfaces are pretty useful, the largest limitations of these interfaces are:
X509Certificate
- Not every element of the structures is included in the JSON serialization, for example AIA, CDP, Name Constraints and Certificate Policy are not present (most extensions actually); this is because there is not a decoder for them in GO.
- ECC based certificates are not supported, this is because at this time the released version of GO doesn’t include support for these.
- Only issuing certificates based on self-signed X509 certificates are supported, this is as I mentioned a result of the lack of support for the PKCS #10 object in GO.
- No OID is specified for the Signature algorithm, this is because it’s not exposed in GO.
- Only one certificate profile is supported when using the issue action, this is mostly due to limitations in go (time was also a factor) for example the lack of AIA and OCSP support mean these regardless of CA key material these certs are just good for playing around.
- No user supplied information is included in the generated certificate, this was really just a function of time and building a proper workflow that would not be valuable without addressing other go limitations.
- Requested certificates that contain RSA keys must have a bit length of at least 2048 bits in length, just a best practice.
- Requested certificates will only be issued if the submitted certificate contains a self-signed certificate with a valid signature, this is to ensure the requestor actually holds the private key.
- Not all SAN types are supported, only DNSnames really again a limitation of GO.
- Certificates with name constraints are not supported, again a limitation of GO.
- Not possible to put EKU in certificates, again a limitation of GO.
X509OCSP
- ResponderID is not specified, this is because it’s not exposed in GO.
- Only responses with a single response are supported, this is because more that response is not exposed in GO.
- No OCSP extensions are supported, this is because this is not exposed in GO.
- Only responses are supported, this is because the request is not supported in GO.
Here are some things you might want to know about these interfaces:
- Both X509crl and X509ocsp default to DER but you can specify PEM in the encode query string parameter.
- X509Certificate defaults to the PEM encoding but DER is supported via the encode query string parameter.
- X509Certificates defaults to PEM encoding but DER is not supported.
- X509Certificates takes the file you might use in Apache or Nginx to configure which certificates to send — a concatenation of PEM encoded certificates.
- All interfaces use HTTP error codes to report issues.
- I can’t propose they will always be up and available, be reliable, performant or accurate 🙂
All in-all I think this was a fun project and I really enjoyed working with Eli and Freelancer (though its mail client is awful and the site needs some UI work).
Ryan