OpenSSL is a great library with many great utilities. One knock against it though are the tools for maintaining a PKI. The tools feel raw and unfinished. I have been searching for a new tool. A while back someone recommened cfssl. Looks like it’s a decent tool.

Building

Release 1.3.3 does not have prebuilt binaries, which was a bit interesting. This means I had to build it from source (screams in the background). cfssl uses the older style dependecy setup. go get -u looks to grab prebuilt binaries from somewhere, so that was a bit interesting and looks like I might be able to avoid building myself.

Generating a new CA

A new root certificate requires a CSR JSON file like the following:

{
        "CN" : "test",
        "name" : [
        {
            "C":  "US",
            "L":  "Davis",
            "O":  "Mark Eschbach",
            "OU": "PKI",
            "ST": "California"
        }
        ]
}

If the above is titled root.json the examples show something like cfssl genkey -initca root.json | cfssljson -bare ca.

By default this generates a new root which is good for 5 years. Curiously enough the Issuer (and subject because they are the same in the root) only contain the CN property. Although looking at the documentation there is a selfsign subcommand.

selfsign produces a series of warnings regarding how insecure the keys are. The first argument is a hostname and a second is the CSR in JSON format like above.

Back to the original method. cfssljson seems to convert the output of the key into a certificate. cfssl genkey looks to be the configuration of interest. There is an optional configuration file which may allow me to tweak additional parameters, such as including additional elements in the certificate.

Given an example of a valid test configuration I don’t think this is what I am looking for. When in doubt look in docs.

After reviewing the source for the csr there is a member variable named ca in JSON which contains the field expiry which is passed to the func ParseDuration(s string) (Duration, error) of time. The largest unit currently supported is hours. This means 10 * 24 * 265 = 85440h for the field value. A full example as follows for a reasonable length PKI certificate is as follows:

{
        "hosts": [
                "ca.example.com"
        ],
        "key" : {
                "algo" : "rsa",
                "size" : 2048
        },
        "names" : [
        {
            "C":  "US",
            "L":  "Davis",
            "O":  "Example Inc",
            "OU": "PKI",
            "ST": "California"
        }
        ],
        "ca" : {
                "expiry" : "85440h"
        }
}

Not bad for making it easier. Let us see what the pains are generating a signed key from this one.

Signing

One has to generate a CSR from the JSON in order to sign. This can be accomplished via cfssl genky intermediate.json |cfssljson -bare intermediate-ca. This will produce a new CSR. Unfortunately no matter what options I try this does not result in a certificate which allows for intermediate CAs.