Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds 3-level certificate chain generation script #165

Merged
merged 1 commit into from
Feb 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ presubmit:
.PHONY: licenses
licenses: ; @./scripts/licenses.sh

.PHONY: test-certs
test-certs:
@echo "Regenerating certificate chain..."
@$(SHELL) scripts/gen-certs.sh create

.PHONY: help
help:
@echo "Available targets:"
Expand All @@ -58,3 +63,4 @@ help:
@echo " * presubmit: check you are ready to push your local branch to remote"
@echo " * help: print this menu"
@echo " * licenses: check licenses of dependent packages"
@echo " * test-certs: regenerate the certificate chain"
Binary file added misc/endEntity.der
Binary file not shown.
5 changes: 5 additions & 0 deletions misc/endEntity.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIFaWg82uhJd5ejmQxb5HmxLveE4NZ9W/CeyYwYjiFximoAoGCCqGSM49
AwEHoUQDQgAECc8hy7bQIFZJBtS1pQW9E0LT56doX04VB/lWX3S0fJCCAQbcwdkv
tBImTgx96mL4ZyZSJo8rKyJ6UgIEUHEHPQ==
-----END EC PRIVATE KEY-----
Binary file added misc/intermediateCA.der
Binary file not shown.
Binary file added misc/rootCA.der
Binary file not shown.
202 changes: 202 additions & 0 deletions scripts/gen-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
#!/bin/bash
# SPDX-License-Identifier: Apache-2.0
set -eu
set -o pipefail

ROOT_CERT_NAME=rootCA
INTERMEDIATE_CERT_NAME=intermediateCA
END_ENTITY_CERT_NAME=endEntity

THIS_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
MISC_DIR="$THIS_DIR/../misc"

mkdir -p "$MISC_DIR"

trap '[[ $_should_clean_certs_artifacts == true ]] && clean_certs_artifacts' EXIT

function create_root_cert() {
_check_openssl

if [[ -f "${MISC_DIR}/${ROOT_CERT_NAME}.der" ]]; then
echo "Root certificate already exists. Skipping creation."
return
fi

openssl ecparam -name prime256v1 -genkey -noout -out ${MISC_DIR}/${ROOT_CERT_NAME}.key
openssl req -x509 -new -nodes -key ${MISC_DIR}/${ROOT_CERT_NAME}.key \
-sha256 -days 3650 \
-subj "/CN=Acme Inc." \
-out ${MISC_DIR}/${ROOT_CERT_NAME}.crt
openssl x509 -in ${MISC_DIR}/${ROOT_CERT_NAME}.crt -outform der \
-out ${MISC_DIR}/${ROOT_CERT_NAME}.der
rm -f ${MISC_DIR}/${ROOT_CERT_NAME}.crt

echo "Created ${MISC_DIR}/${ROOT_CERT_NAME}.der and ${MISC_DIR}/${ROOT_CERT_NAME}.key"
}

function create_intermediate_cert() {
_check_openssl
_check_root_cert

if [[ -f "${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.der" ]]; then
echo "Intermediate certificate already exists. Skipping creation."
return
fi

openssl ecparam -name prime256v1 -genkey -noout -out ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.key
openssl req -new -key ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.key \
-out ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.csr \
-subj "/CN=Acme Gizmos"
openssl x509 -req -in ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.csr \
-CA ${MISC_DIR}/${ROOT_CERT_NAME}.der \
-CAkey ${MISC_DIR}/${ROOT_CERT_NAME}.key \
-CAcreateserial \
-out ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.crt \
-days 3650 -sha256
openssl x509 -in ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.crt \
-outform der -out ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.der
rm -f ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.crt

echo "Created ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.der and ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.key"
}

function create_end_entity_cert() {
_check_openssl
_check_root_cert

if ([[ -f "${MISC_DIR}/${END_ENTITY_CERT_NAME}.der" ]] && [[ -f "${MISC_DIR}/${END_ENTITY_CERT_NAME}.key" ]]); then
echo "End-entity certificate and key already exist. Skipping creation."
return
fi

openssl ecparam -name prime256v1 -genkey -noout -out ${MISC_DIR}/${END_ENTITY_CERT_NAME}.key
openssl req -new -key ${MISC_DIR}/${END_ENTITY_CERT_NAME}.key \
-out ${MISC_DIR}/${END_ENTITY_CERT_NAME}.csr \
-subj "/CN=Acme Gizmo CoRIM signer"
openssl x509 -req -in ${MISC_DIR}/${END_ENTITY_CERT_NAME}.csr \
-CA ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.der \
-CAkey ${MISC_DIR}/${INTERMEDIATE_CERT_NAME}.key \
-CAcreateserial \
-out ${MISC_DIR}/${END_ENTITY_CERT_NAME}.crt \
-days 1825 -sha256 \
-CAform der
openssl x509 -in ${MISC_DIR}/${END_ENTITY_CERT_NAME}.crt \
-outform der -out ${MISC_DIR}/${END_ENTITY_CERT_NAME}.der
rm -f ${MISC_DIR}/${END_ENTITY_CERT_NAME}.crt

echo "Created ${MISC_DIR}/${END_ENTITY_CERT_NAME}.der and ${MISC_DIR}/${END_ENTITY_CERT_NAME}.key"
}

function clean_certs_artifacts() {
pushd "$MISC_DIR" > /dev/null || exit 1
echo "rm -f -- *.csr *.srl"
rm -f -- *.csr *.srl
popd > /dev/null || exit 1
}

function clean_cert() {
pushd "$MISC_DIR" > /dev/null || exit 1
local cert="$1"
echo "rm -f \"${cert}.der\" \"${cert}.key\""
rm -f "${cert}.der" "${cert}.key"
popd > /dev/null || exit 1
}

function clean_all() {
clean_certs_artifacts
clean_cert "$ROOT_CERT_NAME"
clean_cert "$INTERMEDIATE_CERT_NAME"
clean_cert "$END_ENTITY_CERT_NAME"
}

function help() {
set +e
read -r -d '' usage <<-EOF
Usage: gen-certs [-h] [-C] [COMMAND]

This script is used to (re-)generate certificates used for a veraison
deployment. The certificates are signed by a CA certificate called
${ROOT_CERT_NAME}.crt. If this does not exist, a self-signed one will
be (re-)generated.

Commands:

create
Create the root, intermediate, and end-entity certificates.

clean_certs_artifacts
Clean output artifacts for the certificates.

clean_all
Clean both intermediate and output artifacts for everything (including
the root CA cert).

help
Print this message and exit (same as -h option).

Options:

-h Print this message and exit.
-C Do not clean up intermediate artifacts (e.g., CSRs).

Note: Regenerating the certificate chain is an exceptional action and should
only be done when necessary (e.g., when certificates expire).
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also update the help message in the Makefile. And maybe use "regenerate" rather than "generate" as the certs are already generated, so normally there would be no need to generate them again.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


EOF

echo "$usage"
set -e
}

function _check_openssl() {
if [[ "$(which openssl 2>/dev/null)" == "" ]]; then
echo -e "ERROR: openssl executable must be installed to use this command."
exit 1
fi
}

function _check_root_cert() {
if [[ ! -f "${MISC_DIR}/${ROOT_CERT_NAME}.der" ]]; then
create_root_cert
fi
}

_should_clean_certs_artifacts=true

OPTIND=1

while getopts "hC" opt; do
case "$opt" in
h) help; exit 0;;
C) _should_clean_certs_artifacts=false;;
*) break;;
esac
done

shift $((OPTIND-1))
[ "${1:-}" = "--" ] && shift

command=$1
case $command in
help)
help
exit 0
;;
clean)
clean_certs_artifacts
;;
clean_all)
clean_all
;;
create)
create_root_cert
create_intermediate_cert
create_end_entity_cert
if [[ $_should_clean_certs_artifacts == true ]]; then
clean_certs_artifacts
fi
;;
*)
echo -e "ERROR: unexpected command: \"$command\" (use -h for help)"
;;
esac