Initial onfca commit
Updated help target in Makefile
Reworked for IM CAs
Added CRL handling
Added docs/references
Change-Id: I2b1eb541464c157d3626bbe4a6cf7db78c2af533
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e1f3d2b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,227 @@
+# onfca Makefile
+#
+# SPDX-FileCopyrightText: © 2022 Open Networking Foundation <support@opennetworking.org>
+# SPDX-License-Identifier: Apache-2.0
+
+# openssl onfiguration is also given in pki.cnf
+#
+# NOTE: This makefile makes heavy use of Automatic Variables
+# https://www.gnu.org/software/make/manual/html_node/Automatic-Variables.html
+
+SHELL = bash -eu -o pipefail
+
+# see bottom for help generation
+.DEFAULT_GOAL := help
+.PHONY: test license help
+
+# common parameters for all options
+KEY_SIZE ?= 2048
+OPENSSL_CNF ?= pki.cnf
+
+# base dir
+BASE_DIR ?= onf_pki
+
+# default CA to use when verifying leaf certs, by default the IM CA
+DEFAULT_CA ?= im_ca
+
+# root CA
+ROOT_CA_NAME ?= root_ca
+ROOT_CA_PASSPHRASE ?= "TestingRootCAPassPhrase"
+ROOT_CA_SUBJECT ?= /C=US/ST=California/L=Menlo Park/O=ONF/OU=Infra/CN=ONF Test Root CA
+
+# intermediate CA
+IM_CA_NAME ?= im_ca
+IM_CA_PASSPHRASE ?= "TestingIMCAPassPhrase"
+IM_CA_SUBJECT ?= /C=US/ST=California/L=Menlo Park/O=ONF/OU=Infra/CN=ONF Test IM CA
+IM_EXPIRATION_DAYS ?= 1095
+IM_REVOKE_REASON ?= CACompromise
+
+# leaf certs
+LEAF_EXPIRATION_DAYS ?= 730
+LEAF_PURPOSE ?= server_cert_ext # alternatively, use client_cert_ext
+LEAF_SUBJECT_PARTIAL ?= /C=US/ST=California/L=Menlo Park/O=ONF/OU=Infra/CN=
+LEAF_KEYPAIR ?= core
+LEAF_SAN ?= DNS:core.example.com,DNS:core.example.net
+LEAF_REVOKE_REASON ?= keyCompromise
+
+# utility/validation targets
+valid_server: ## Check Server Cert validity (set LEAF_KEYPAIR, DEFAULT_CA)
+ openssl verify -verbose -x509_strict -show_chain \
+ -purpose sslserver \
+ -CAfile $(BASE_DIR)/$(DEFAULT_CA)/chain.pem \
+ -CRLfile $(BASE_DIR)/$(DEFAULT_CA)/ca.crl -crl_check \
+ $(BASE_DIR)/certout/$(LEAF_KEYPAIR).pem
+
+valid_client: ## Check Client Cert validity (set LEAF_KEYPAIR, DEFAULT_CA)
+ openssl verify -verbose -x509_strict -show_chain \
+ -purpose sslclient \
+ -CAfile $(BASE_DIR)/$(DEFAULT_CA)/chain.pem \
+ -CRLfile $(BASE_DIR)/$(DEFAULT_CA)/ca.crl -crl_check \
+ $(BASE_DIR)/certout/$(LEAF_KEYPAIR).pem
+
+valid_im: ## Check IM CA validity (set IM_CA_NAME, ROOT_CA_NAME)
+ openssl verify -verbose -x509_strict -purpose any \
+ -CAfile $(BASE_DIR)/$(ROOT_CA_NAME)/ca.pem \
+ -CRLfile $(BASE_DIR)/$(ROOT_CA_NAME)/ca.crl -crl_check_all \
+ $(BASE_DIR)/$(IM_CA_NAME)/ca.pem
+
+printca: $(BASE_DIR)/$(DEFAULT_CA)/ca.pem ## Print CA Public Key (PEM) for DEFAULT_CA
+ openssl x509 -in $< -text -noout
+
+printcrl: $(BASE_DIR)/$(DEFAULT_CA)/ca.crl ## Print CRL (Revoke List) for DEFAULT_CA
+ openssl crl -in $< -text -noout
+
+printkey: ## Print KEY (Private Key) for LEAF_KEYPAIR
+ openssl rsa -in $(BASE_DIR)/certout/$(LEAF_KEYPAIR).key -text -noout -check
+
+printcsr: ## Print CSR (Sign Request) for LEAF_KEYPAIR
+ openssl req -in $(BASE_DIR)/certout/$(LEAF_KEYPAIR).csr -text -noout -verify
+
+printpem: ## Print PEM (Public Key) for LEAF_KEYPAIR
+ openssl x509 -in $(BASE_DIR)/certout/$(LEAF_KEYPAIR).pem -text -noout
+
+revoke_leaf: ## Revoke Leaf Cert (set IM_CA_NAME, LEAF_KEYPAIR, LEAF_REVOKE_REASON)
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl ca \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase \
+ -revoke $(BASE_DIR)/certout/$(LEAF_KEYPAIR).pem \
+ -crl_reason $(LEAF_REVOKE_REASON)
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl ca -gencrl \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase \
+ -out $(BASE_DIR)/$(IM_CA_NAME)/ca.crl
+
+revoke_im: ## Revoke Intermediate CA Cert (set IM_CA_NAME, IM_REVOKE_REASON, ROOT_CA_NAME)
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl ca \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -revoke $(BASE_DIR)/$(IM_CA_NAME)/ca.pem \
+ -crl_reason $(IM_REVOKE_REASON)
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl ca -gencrl \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -out $(BASE_DIR)/$(ROOT_CA_NAME)/ca.crl
+
+destroy: ## Delete all certificates and data
+ rm -rf $(BASE_DIR)
+
+# don't delete intermediate files
+.PRECIOUS: ca_passphrase $(BASE_DIR)/certout/%.csr $(BASE_DIR)/certout/%.key
+
+# Generic CA directory creation
+$(BASE_DIR)/%_ca:
+ mkdir -p $@/private $@/db $@/crl/db $@/certs
+ chmod 700 $@/private
+ touch $@/db/ca.db
+ printf "unique_subject = no\ncopy_extensions = copy\n" > $@/db/ca.db.attr
+ echo 01 > $@/db/ca.srl
+ echo 01 > $@/crl/db/ca.crl.srl
+ touch $@/index.txt
+
+# Root CA creation
+$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase: | $(BASE_DIR)/$(ROOT_CA_NAME)
+ @echo $(ROOT_CA_PASSPHRASE) > $@
+
+$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_key.pem: | $(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase
+ @echo "## Creating root CA private key, $@"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl genrsa -aes256 \
+ -passout file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -out $@ $(KEY_SIZE)
+
+# validity time on root CA is set in the .cnf file
+$(BASE_DIR)/$(ROOT_CA_NAME)/ca.pem: $(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_key.pem
+ @echo "## Creating self-signed root CA cert: $@"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl req -config $(OPENSSL_CNF) \
+ -extensions root_ca_ext \
+ -new -x509 -sha256 \
+ -key $< \
+ -passin file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -subj "$(ROOT_CA_SUBJECT)" \
+ -out $@
+ @echo "## Creating root CA revocation list: $(@D)/ca.crl"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl ca -gencrl \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -out $(@D)/ca.crl
+
+# Intermediate CA creation
+$(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase: | $(BASE_DIR)/$(IM_CA_NAME)
+ @echo $(IM_CA_PASSPHRASE) > $@
+
+$(BASE_DIR)/$(IM_CA_NAME)/private/ca_key.pem: $(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase
+ @echo "## Creating intermediate CA private key: $@"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl genrsa -aes256 \
+ -passout file:$(@D)/ca_passphrase \
+ -out $@ $(KEY_SIZE)
+
+$(BASE_DIR)/$(IM_CA_NAME)/private/im_ca.csr: $(BASE_DIR)/$(IM_CA_NAME)/private/ca_key.pem
+ @echo "## Creating intermediate CA signing request $@ from $<"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl req -config $(OPENSSL_CNF) \
+ -new -sha256 \
+ -key $< \
+ -passin file:$(@D)/ca_passphrase \
+ -subj "$(IM_CA_SUBJECT)" \
+ -out $@
+
+$(BASE_DIR)/$(IM_CA_NAME)/ca.pem: $(BASE_DIR)/$(IM_CA_NAME)/private/im_ca.csr | $(BASE_DIR)/$(ROOT_CA_NAME)/ca.pem
+ @echo "## Signing $< with root CA key to create intermediate CA cert: $@"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(ROOT_CA_NAME) openssl ca -config $(OPENSSL_CNF) \
+ -extensions im_ca_ext \
+ -notext -batch -md sha256 \
+ -days $(IM_EXPIRATION_DAYS) \
+ -passin file:$(BASE_DIR)/$(ROOT_CA_NAME)/private/ca_passphrase \
+ -in $< \
+ -out $@
+ @echo "## Creating chain with Root CA and IM CA: $@"
+ cat $@ $(BASE_DIR)/$(ROOT_CA_NAME)/ca.pem > $(@D)/chain.pem
+ openssl crl2pkcs7 -nocrl -certfile $(@D)/chain.pem | openssl pkcs7 -print_certs -noout
+ @echo "## Creating IM CA revocation list: $(@D)/ca.crl"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl ca -gencrl \
+ -config $(OPENSSL_CNF) \
+ -passin file:$(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase \
+ -out $(@D)/ca.crl
+
+# Leaf cert creation
+$(BASE_DIR)/certout:
+ mkdir -p $@
+
+$(BASE_DIR)/certout/%.key: $(BASE_DIR)/certout
+ @echo "## Creating leaf private key: $@"
+ openssl genrsa -out $@ $(KEY_SIZE)
+
+$(BASE_DIR)/certout/%.csr: $(BASE_DIR)/certout/%.key
+ @echo "## Creating signing request $@ from $<"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl req -config $(OPENSSL_CNF) \
+ -new -sha256 \
+ -key $< \
+ -subj "$(LEAF_SUBJECT_PARTIAL)$*" \
+ -addext "subjectAltName = $(LEAF_SAN)" \
+ -out $@
+
+$(BASE_DIR)/certout/%.pem: $(BASE_DIR)/certout/%.csr | $(BASE_DIR)/$(IM_CA_NAME)/ca.pem
+ @echo "## Signing $< with IM CA key to create signed leaf cert: $@"
+ BASE_DIR=$(BASE_DIR) CA_NAME=$(IM_CA_NAME) openssl ca -config $(OPENSSL_CNF) \
+ -extensions $(LEAF_PURPOSE) \
+ -policy any_pol \
+ -notext -batch -md sha256 \
+ -days $(LEAF_EXPIRATION_DAYS) \
+ -passin file:$(BASE_DIR)/$(IM_CA_NAME)/private/ca_passphrase \
+ -in $< \
+ -out $@
+ @echo "## Creating bundle with IM CA and Leaf: $(basename $@)_bundle.pem"
+ cat $@ $(BASE_DIR)/$(IM_CA_NAME)/ca.pem > $(basename $@)_bundle.pem
+ openssl crl2pkcs7 -nocrl -certfile $(basename $@)_bundle.pem | openssl pkcs7 -print_certs -noout
+
+# testing and license tasks
+test: license
+
+license: $(VENV_NAME) ## Check license with the reuse tool
+ reuse --version ;\
+ reuse --root . lint
+
+help: ## Print help for each target
+ @echo onfca make targets
+ @echo See README.md for more detailed instructions
+ @echo
+ @grep '^[[:alnum:]_-]*:.* ##' $(MAKEFILE_LIST) \
+ | sort | awk 'BEGIN {FS=":.* ## "}; {printf "%-25s %s\n", $$1, $$2};'