Notes and useful commands and configuration for a minimal setup of CFSSL using root CA issued by mkcert.
To be able to store certificates their states we need to set up a database
backend. CFSSL is shipped with goose
migrations so we just install goose
and migrate!
# Install goose
go get -u github.com/pressly/goose/cmd/goose
# Run migration
goose -dir certdb/sqlite/migrations sqlite3 cerstore.db up
We must create a few configration files for CFSSL to use.
config.json
holds configuration related to the signing of certificates.
{
"signing": {
"profiles": {
"CA": {
"usages": [
"cert sign"
],
"expiry": "720h",
"auth_key": "ca-auth"
},
"email": {
"usages": [
"s/mime"
],
"expiry": "720h"
}
},
"default": {
"usages": [
"digital signature",
"email protection"
],
"expiry": "8000h"
}
},
"auth_keys": {
"ca-auth": {
"type": "standard",
"key": "0123456789ABCDEF0123456789ABCDEF"
}
}
}
Minimum configuration for database connections.
{
"driver": "sqlite3",
"data_source": "./certstore.db"
}
Generate a root CA and root CA key with mkcert. Copy to your working directory.
mkcert -install
cp "$(mkcert -CAROOT)/rootCA*" .
go run cmd/cfssl/cfssl.go serve \
--ca rootCA.pem \
--ca-key rootCA-key.pem \
--config config.json \
--db-config db-config.json
Just create a certificate and save to file.
echo '{"request":{"CN":"Test"}}' | \
http POST http://127.0.0.1:8888/api/v1/cfssl/newcert | \
jq .result.certificate | \
gsed 's,\\n,\n,g' | gsed 's,",,g' > my-cert.pem
Create a certificate and store both the certificate and the key file.
r=$( echo '{"request":{"CN":"Test"}}' | \
http POST http://127.0.0.1:8888/api/v1/cfssl/newcert); \
echo $r | jq .result.certificate | \
gsed 's,\\n,\n,g' | gsed 's,",,g' > my-cert.pem; \
echo $r | jq .result.private_key | \
gsed 's,\\n,\n,g' | gsed 's,",,g' > my-key.pem
http POST http://127.0.0.1:8888/api/v1/cfssl/revoke \
serial=74809552255845637962813547409096274906778910495 \
authority_key_id=d9dda678a8b7292a7c16033195a350c8af6a8c95 \
reason=keycompromise
HTTP/1.1 200 OK
Content-Length: 55
Content-Type: application/json
Date: Thu, 27 Jun 2019 11:57:21 GMT
{
"errors": [],
"messages": [],
"result": {},
"success": true
}
cfssl ocsprefresh \
-db-config my-config.json \
-ca my-ca.pem \
-responder my-ca.pem \
-responder-key my-ca-key.pem
cfssl ocspdump -db-config my-config.json > ocsp-responses
The OCSP server can serve information from file or from the database holding all the certificates issued.
cfssl ocspserve \
-port=8889 \
-loglevel=0 \
-responses=ocsp-responses
cfssl ocspserve \
-port 8889 \
-ca rootCA.pem \
-ca-key rootCA_key.pem \
-config config.json \
-db-config db-config.json \
-loglevel 0
openssl ocsp \
-no_nonce \
-text \
-issuer rootCA.pem \
-cert my-cert.pem \
-CAfile rootCA.pem \
-respout response.out \
-reqout request.out \
-url http://127.0.0.1:8889
http http://127.0.0.1:8889/"$(cat request.out | base64)"
HTTP/1.1 200 OK
Cache-Control: max-age=343501, public, no-transform, must-revalidate
Content-Length: 707
Content-Type: application/ocsp-response
Date: Sat, 06 Apr 2019 20:34:58 GMT
Etag: "2FB278A1D5CF3CD7E6F4BEF90BEF1307E1626F07F2BC4C7E52608679EA08C96D"
Expires: Wed, 10 Apr 2019 20:00:00 UTC
Last-Modified: Sat, 06 Apr 2019 20:00:00 UTC
+-----------------------------------------+
| NOTE: binary data not shown in terminal |
+-----------------------------------------+
// Construct an OCSP request from the *x509.Certificate
request, _ := ocsp.CreateRequest(cert, issuing, nil)
// Construct the URL with the base64 encoded request
httpResponse, _ := http.Get(
fmt.Sprintf("http://127.0.0.1:8889/%s", base64.StdEncoding.EncodeToString(request)),
)
// Read response from body
responseBody, _ := ioutil.ReadAll(httpResponse.Body)
// Parse OCSP response
ocspResponse, _ := ocsp.ParseResponse(responseBody, issuing)
// ocspResponse.Status == ocsp.Good returns true