cfssl
cfssl copied to clipboard
Unable to set multiple OUs in the "names" field
x.509 allows for multiple OU fields, so that certificate ownership can be clearly identified even in very large organizations. It's common to see something like this in the Subject Name:
O="Company", OU="Engineering", OU="Operations", OU="Security"
CFSSL does not support this, which may surprise people who are used to this practice with x.509 certificates. Specifying the OU multiple times[1] silently ignores all but the last value. Specifying an array fails.
If it's possible to handle an array for the OU, that would be great. If not, having an alternative parameter that does accept an array ("OUs"?) would also be fine. If this isn't going to be implemented any time soon, printing a warning about multiple OUs being ignored would be nice, so people understand why they're not getting back the certificate they expect.
[1] https://coreos.com/os/docs/latest/generate-self-signed-certificates.html
It's actually possible to use cfssl/csr package to generate a CSR with a subject containing multiple OUs. Here is an example csr_test.json:
{ "key": { "algo": "ecdsa", "size": 256 }, "names": [ { "C": "US", "L": "San Francisco", "ST": "California", "O": "ACME, Inc.", "OU": "First OU" }, { "OU": "Second OU" } ], "cn": "I heard cn is useless" }
cfssl genkey csr_test.json should give you a csr with multiple OUs. But I found a problem with Go's asn1 parser, which will not parse multiple OUs. In fact we can attempt to parse the resulting CSR with Go's x509.ParseCertificateRequest and it only returns a CSR with single OU, "First OU". Meanwhile, openssl will shows the CSR with multiple OUs.
I would consider to raise an issue with Go's core developer.
@lziest is it possible to use cfssl to generate a certificate with a subject containing multiple OUs? Using the json format above I was able to create a csr with multiple OUs, but the certificate still only contained one of them. I tried generating the certificate with multiple OUs using the gencert and newcert commands.
you are right, we can generate a PEM-encoded CSR which has multiple OUs, but when we trying to parse that CSR into go structure, we only get the first OU in the structure. And since we sign certificate with go structure (doing verification etc.), the resulting cert has only one OU.
This seems to happen for multiple organizations, as well. My use case is that Kubernetes uses the O field to assign Kubernetes user groups, and people can be in more than one group.
Thanks @jimmycuadra this is exactly what I am trying to do. Got all the way to the CSR and then it failed. Built so much around cfssl, hate to pull it out.
@deitch Same! We switched from using the openssl command line tool to cfssl because cfssl's API is nicer, but I'm not sure how to proceed now, cause this bug is actually blocking some use cases for us. I get the sense that cfssl is not updated very often, so it doesn't seem like we can assume it will be fixed anytime soon, especially given the suggestion that the problem lies in Go's ASN.1 parser and not cfssl itself. We may just have to switch back to openssl. :\
@jimmycuadra yeah. I am loathe to switch off of it, since it is an easier API than openssl, and the cfssl serve is neat (although running over http and not https, and passing a token; ugh), but it is on my list now to get off of it, unfortunately.
I went through the example from @lziest above and I was able to create a signed certificate with 2 OU's. I put my steps below (I'm running go version go1.8 darwin/amd64). Is it possible the issue's been fixed?
ca_csr.json:
{
"cn": "I heard cn is useless",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"L": "San Francisco",
"O": "ACME, Inc.",
"OU": "First OU",
"ST": "California"
},
{
"OU": "Second OU"
}
]
}
csr_signee.json:
{
"cn": "Bob",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"L": "Philly",
"O": "Slack's",
"OU": "Steaks",
"ST": "Pennsylvania"
},
{
"OU": "Fries"
}
]
}
$ cfssl gencert -initca ca_csr.json
$ echo -e "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" > ca.pem
$ echo -e "-----BEGIN EC PRIVATE KEY-----\n...\n-----END EC PRIVATE KEY-----\n" > ca_key.pem
$ cfssl gencert -initca csr_signee.json
$ echo -e "-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----\n" > signee_csr.pem
$ cfssl sign -ca ca.pem -ca-key ca_key.pem signee_csr.pem
$ echo -e "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n" > signed_signee.pem
$ cfssl certinfo -cert signed_signee.pem
That last command gave me this:
{
"subject": {
"common_name": "Bob",
"country": "US",
"organization": "Slack's",
"organizational_unit": "Steaks,Fries",
"locality": "Philly",
"province": "Pennsylvania",
"names": [
"US",
"Pennsylvania",
"Philly",
"Slack's",
"Steaks",
"Fries",
"Bob"
]
},
"issuer": {
"common_name": "I heard cn is useless",
"country": "US",
"organization": "ACME, Inc.",
"organizational_unit": "First OU,Second OU",
"locality": "San Francisco",
"province": "California",
"names": [
"US",
"California",
"San Francisco",
"ACME, Inc.",
"First OU",
"Second OU",
"I heard cn is useless"
]
},
"serial_number": "77888877478957473953290554776194418363091613331",
"not_before": "2017-04-14T22:34:00Z",
"not_after": "2018-04-14T22:34:00Z",
"sigalg": "ECDSAWithSHA256",
"authority_key_id": "79:23:52:E8:8:2C:A9:32:B1:8A:E5:B7:37:62:F4:B6:12:8C:54:83",
"subject_key_id": "F6:B1:F8:C6:AA:2:B0:53:FA:E7:AF:E1:29:A6:4D:DB:90:33:70:7A",
"pem": "-----BEGIN CERTIFICATE-----\nMIICizCCAjCgAwIBAgIUDaSodqvHR4ytxNI1jTJbvhVDdpMwCgYIKoZIzj0EAwIw\ngZQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMRMwEQYDVQQKEwpBQ01FLCBJbmMuMSMwDwYDVQQLEwhGaXJz\ndCBPVTAQBgNVBAsTCVNlY29uZCBPVTEeMBwGA1UEAxMVSSBoZWFyZCBjbiBpcyB1\nc2VsZXNzMB4XDTE3MDQxNDIyMzQwMFoXDTE4MDQxNDIyMzQwMFowdDELMAkGA1UE\nBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTEPMA0GA1UEBxMGUGhpbGx5MRAw\nDgYDVQQKEwdTbGFjaydzMR0wDQYDVQQLEwZTdGVha3MwDAYDVQQLEwVGcmllczEM\nMAoGA1UEAxMDQm9iMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoXdV4odAuTFx\nHG+Vl1ZEEC/zxzFpjywt4cmaenHLXwNRft3kdZAR1USjsmBEpiJkXgbOBH2lEceO\nn4azgb0UNqN/MH0wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMB\nBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBT2sfjGqgKwU/rnr+Ep\npk3bkDNwejAfBgNVHSMEGDAWgBR5I1LoCCypMrGK5bc3YvS2EoxUgzAKBggqhkjO\nPQQDAgNJADBGAiEArXbbz563aVJDx+OEtAFUpGxHHhFJf01h2PnpvTkmmOQCIQDt\nhJIHHEL0OP8J0re6nzKX0D/DGJNK/u5nyCmYUQ/HQg==\n-----END CERTIFICATE-----\n"
}
Yes! I just tried it with cfssl built with Go 1.8.1 and the final signed certificate had all the organizations that were in the CSR!
Would it be possible to release new cfssl binaries to https://pkg.cfssl.org/ and/or https://github.com/cloudflare/cfssl/releases?
homebrew's cfssl is still compiled against Go 1.7. You can recompile cfssl against Go 1.8:
brew remove cfssl
brew upgrade go
brew install --build-from-source cfssl
Multiple O or OU fields works!
That should help.
cloudflare team, can we get the docker image updated? I just pulled it again, ran strings:
$ docker run --rm --entrypoint=strings cfssl/cfssl /go/bin/cfssl | grep 'go1\.'
go1.6.4
1.6.4?
When 1.8-built binaries will be released?
A year old...