cfssl is CloudFlare's PKI/TLS toolkit.
openssl なり CA.sh CA.pl の代替コマンド、という位置付け。あとは証明書サーバー?にもなるらしい。
各種ファイルを JSON 形式で表現する。この JSON の syntax リファレンスが(README.md にサンプルは書いてあるものの)不明で使い方がわからん、と思ったが print-defaults コマンドで雛形を作って適宜編集して使う、というもののようだ。
selfsign サブコマンドで自己署名証明書を作ってみる。
❯ cfssl print-defaults csr | tee csr.json
{
"CN": "example.net",
"hosts": [
"example.net",
"www.example.net"
],
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "US",
"ST": "CA",
"L": "San Francisco"
}
]
}
❯ cfssl selfsign example.com csr.json | tee cert.json
2023/10/16 12:41:57 [INFO] generate received request
2023/10/16 12:41:57 [INFO] received CSR
2023/10/16 12:41:57 [INFO] generating key: ecdsa-256
2023/10/16 12:41:57 [INFO] encoded CSR
*** WARNING ***
Self-signed certificates are dangerous. Use this self-signed
certificate at your own risk.
It is strongly recommended that these certificates NOT be used
in production.
*** WARNING ***
{"cert":"-----BEGIN CERTIFICATE-----\nMIICDzCCAbWgAwIBAgIIbf+wpkgJXUwwCgYIKoZIzj0EAwIwSDELMAkGA1UEBhMC\nVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQD\nEwtleGFtcGxlLm5ldDAeFw0yMzEwMTYwMzM2NTdaFw0yNDAxMTUwOTQxNTdaMEgx\nCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\nbzEUMBIGA1UEAxMLZXhhbXBsZS5uZXQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAARBtN40okpotQNeix9ZDZDUrSmaK8fs039Nb3U7DaRXaDv5YzTmGfzmhUuQhTwT\neYTKT/f7gG7YoaGzf4WtsQ0Jo4GIMIGFMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE\nFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU\n6t1+02wYfSzNFD4w9A6Br/q8+egwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3\ndy5leGFtcGxlLm5ldDAKBggqhkjOPQQDAgNIADBFAiEA9q81kBp/j8AMxxZlORhL\nfKBOj3eJP+QQWb8e8goKXGECICxGw+MmQHd/sPyZ+MoPHjH+I6GJPP1sSeFvaSZa\nRgEc\n-----END CERTIFICATE-----\n","csr":"-----BEGIN CERTIFICATE REQUEST-----\nMIIBPDCB5AIBADBIMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcT\nDVNhbiBGcmFuY2lzY28xFDASBgNVBAMTC2V4YW1wbGUubmV0MFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAEQbTeNKJKaLUDXosfWQ2Q1K0pmivH7NN/TW91Ow2kV2g7\n+WM05hn85oVLkIU8E3mEyk/3+4Bu2KGhs3+FrbENCaA6MDgGCSqGSIb3DQEJDjEr\nMCkwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm5ldDAKBggq\nhkjOPQQDAgNHADBEAiA2NjDwqlSikvk7txHNfJbNp8X28+QjSFhiAJEvwKXcSQIg\nL1sTEKohQRpKqe5hSDhlgP94xaPJFQsauFKwU6Saiiw=\n-----END CERTIFICATE REQUEST-----\n","key":"-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIAEIP6D7JWYlBTcC21YvTyflu+aW/XAvDsEgRcfwppieoAoGCCqGSM49\nAwEHoUQDQgAEQbTeNKJKaLUDXosfWQ2Q1K0pmivH7NN/TW91Ow2kV2g7+WM05hn8\n5oVLkIU8E3mEyk/3+4Bu2KGhs3+FrbENCQ==\n-----END EC PRIVATE KEY-----\n"}
❯ jq . cert.json
{
"cert": "-----BEGIN CERTIFICATE-----\nMIICDzCCAbWgAwIBAgIIbf+wpkgJXUwwCgYIKoZIzj0EAwIwSDELMAkGA1UEBhMC\nVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQD\nEwtleGFtcGxlLm5ldDAeFw0yMzEwMTYwMzM2NTdaFw0yNDAxMTUwOTQxNTdaMEgx\nCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\nbzEUMBIGA1UEAxMLZXhhbXBsZS5uZXQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAARBtN40okpotQNeix9ZDZDUrSmaK8fs039Nb3U7DaRXaDv5YzTmGfzmhUuQhTwT\neYTKT/f7gG7YoaGzf4WtsQ0Jo4GIMIGFMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE\nFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU\n6t1+02wYfSzNFD4w9A6Br/q8+egwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3\ndy5leGFtcGxlLm5ldDAKBggqhkjOPQQDAgNIADBFAiEA9q81kBp/j8AMxxZlORhL\nfKBOj3eJP+QQWb8e8goKXGECICxGw+MmQHd/sPyZ+MoPHjH+I6GJPP1sSeFvaSZa\nRgEc\n-----END CERTIFICATE-----\n",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBPDCB5AIBADBIMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcT\nDVNhbiBGcmFuY2lzY28xFDASBgNVBAMTC2V4YW1wbGUubmV0MFkwEwYHKoZIzj0C\nAQYIKoZIzj0DAQcDQgAEQbTeNKJKaLUDXosfWQ2Q1K0pmivH7NN/TW91Ow2kV2g7\n+WM05hn85oVLkIU8E3mEyk/3+4Bu2KGhs3+FrbENCaA6MDgGCSqGSIb3DQEJDjEr\nMCkwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3dy5leGFtcGxlLm5ldDAKBggq\nhkjOPQQDAgNHADBEAiA2NjDwqlSikvk7txHNfJbNp8X28+QjSFhiAJEvwKXcSQIg\nL1sTEKohQRpKqe5hSDhlgP94xaPJFQsauFKwU6Saiiw=\n-----END CERTIFICATE REQUEST-----\n",
"key": "-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEIAEIP6D7JWYlBTcC21YvTyflu+aW/XAvDsEgRcfwppieoAoGCCqGSM49\nAwEHoUQDQgAEQbTeNKJKaLUDXosfWQ2Q1K0pmivH7NN/TW91Ow2kV2g7+WM05hn8\n5oVLkIU8E3mEyk/3+4Bu2KGhs3+FrbENCQ==\n-----END EC PRIVATE KEY-----\n"
}
certinfo サブコマンドで、証明書ファイルの情報を JSON 形式で表示できる。プログラムから扱うときは openssl x509 の出力よりパースしやすくて便利そう。というか、あの情報はこうやって構造化するといいんだな、というお手本になる。まあすでにこの形式(とツール)があるので、もはや自分で独自フォーマットの構造化をする必要はないわけだが。
❯ jq -r .cert cert.json > server.crt
❯ cfssl certinfo -cert server.crt
{
"subject": {
"common_name": "example.net",
"country": "US",
"locality": "San Francisco",
"province": "CA",
"names": [
"US",
"CA",
"San Francisco",
"example.net"
]
},
"issuer": {
"common_name": "example.net",
"country": "US",
"locality": "San Francisco",
"province": "CA",
"names": [
"US",
"CA",
"San Francisco",
"example.net"
]
},
"serial_number": "7926248097414995276",
"sans": [
"example.net",
"www.example.net"
],
"not_before": "2023-10-16T03:36:57Z",
"not_after": "2024-01-15T09:41:57Z",
"sigalg": "ECDSAWithSHA256",
"authority_key_id": "",
"subject_key_id": "EA:DD:7E:D3:6C:18:7D:2C:CD:14:3E:30:F4:0E:81:AF:FA:BC:F9:E8",
"pem": "-----BEGIN CERTIFICATE-----\nMIICDzCCAbWgAwIBAgIIbf+wpkgJXUwwCgYIKoZIzj0EAwIwSDELMAkGA1UEBhMC\nVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQD\nEwtleGFtcGxlLm5ldDAeFw0yMzEwMTYwMzM2NTdaFw0yNDAxMTUwOTQxNTdaMEgx\nCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNj\nbzEUMBIGA1UEAxMLZXhhbXBsZS5uZXQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\nAARBtN40okpotQNeix9ZDZDUrSmaK8fs039Nb3U7DaRXaDv5YzTmGfzmhUuQhTwT\neYTKT/f7gG7YoaGzf4WtsQ0Jo4GIMIGFMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE\nFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU\n6t1+02wYfSzNFD4w9A6Br/q8+egwJwYDVR0RBCAwHoILZXhhbXBsZS5uZXSCD3d3\ndy5leGFtcGxlLm5ldDAKBggqhkjOPQQDAgNIADBFAiEA9q81kBp/j8AMxxZlORhL\nfKBOj3eJP+QQWb8e8goKXGECICxGw+MmQHd/sPyZ+MoPHjH+I6GJPP1sSeFvaSZa\nRgEc\n-----END CERTIFICATE-----\n"
}
ちゃんとした証明書が発行されている。
❯ openssl x509 -in server.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 7926248097414995276 (0x6dffb0a648095d4c)
Signature Algorithm: ecdsa-with-SHA256
Issuer: C = US, ST = CA, L = San Francisco, CN = example.net
Validity
Not Before: Oct 16 03:36:57 2023 GMT
Not After : Jan 15 09:41:57 2024 GMT
Subject: C = US, ST = CA, L = San Francisco, CN = example.net
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:41:b4:de:34:a2:4a:68:b5:03:5e:8b:1f:59:0d:
90:d4:ad:29:9a:2b:c7:ec:d3:7f:4d:6f:75:3b:0d:
a4:57:68:3b:f9:63:34:e6:19:fc:e6:85:4b:90:85:
3c:13:79:84:ca:4f:f7:fb:80:6e:d8:a1:a1:b3:7f:
85:ad:b1:0d:09
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Key Identifier:
EA:DD:7E:D3:6C:18:7D:2C:CD:14:3E:30:F4:0E:81:AF:FA:BC:F9:E8
X509v3 Subject Alternative Name:
DNS:example.net, DNS:www.example.net
Signature Algorithm: ecdsa-with-SHA256
Signature Value:
30:45:02:21:00:f6:af:35:90:1a:7f:8f:c0:0c:c7:16:65:39:
18:4b:7c:a0:4e:8f:77:89:3f:e4:10:59:bf:1e:f2:0a:0a:5c:
61:02:20:2c:46:c3:e3:26:40:77:7f:b0:fc:99:f8:ca:0f:1e:
31:fe:23:a1:89:3c:fd:6c:49:e1:6f:69:26:5a:46:01:1c