Created
January 16, 2025 13:33
-
-
Save joostd/9c6c3db393cf112d1fe2d87b8db18fc8 to your computer and use it in GitHub Desktop.
Generate a CSR for an asymmetric key stored in a YubiHSM 2 with OpenSSL and yubihsm-shell
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Generate a Certificate Signing Request (CSR) for an asymmetric key stored in a YubiHSM 2 | |
# Usage: | |
# ./gencsr.sh <id> <cn> | |
# | |
# where <id> is the object ID of the asymmetric key, | |
# and <cn> is the Common Name of the subject DN in the generated CSR. | |
ID=$1 | |
CN=$2 | |
# note that the subject DN of the generated CSR will consist of a Common Name only | |
# other fields will typically be overwritten by the CA anyway | |
if [[ -z "$ID" ]]; then | |
echo need an object ID | |
echo "usage: $0 <id> <cn>" | |
exit | |
fi | |
if [[ -z "$CN" ]]; then | |
echo need a Common Name | |
echo "$usage: 0 <id> <cn>" | |
exit | |
fi | |
TMP=$(mktemp -d) | |
echo === Retrieving Public Key | |
yubihsm-shell -C yhusb:// -p password -a get-public-key -i $ID > pubkey.pem || { echo "ERROR: Cannot find asymmetric key with ID $ID"; exit ; } | |
# quick & dirty: extract public key bytes from a EC p256 public key | |
LEN=$(openssl asn1parse -in pubkey.pem | tail -1 | sed -E 's/.*l= +([0-9]+).*/\1/') | |
pubkey=$(openssl pkey -in pubkey.pem -pubin -outform der | tail -c $(($LEN-1)) | xxd -p | tr -d '\n') | |
echo === Getting Key Info | |
ALG=$(yubihsm-shell -C yhusb:// -p password -a get-object-info -i $ID -t asymmetric-key | grep -o 'algorithm: [[:alnum:]]*' | cut -d' ' -f2) | |
echo === Algorithm $ALG | |
case "$ALG" in | |
rsa2048 | rsa3072 | rsa4096) | |
signatureAlgorithm="sha256WithRSAEncryption" | |
SIGALG=rsa-pkcs1-sha256 | |
SIGN=sign-pkcs1v15 ;; | |
ecp224 | ecp256 | ecp384 | ecp521 | eck256) | |
signatureAlgorithm="ecdsa-with-SHA256" | |
SIGALG=ecdsa-sha256 | |
SIGN=sign-ecdsa ;; | |
ed25519*) | |
signatureAlgorithm="ED25519" | |
SIGALG=ed25519 | |
SIGN=sign-eddsa ;; | |
*) | |
echo "unknown algorithm $ALG" | |
exit ;; | |
esac | |
echo "=== Generate Certificate Signing Request (CSR)" | |
# CSR template before signing | |
cat << EOF > $TMP/tbs.asn1 | |
asn1 = SEQUENCE:CertificationRequestInfo | |
[CertificationRequestInfo] | |
version = INTEGER:0x00 | |
subject = SEQUENCE:dn | |
subjectPKInfo = SEQUENCE:PublicKeyInfo | |
attributes = IMPLICIT:0,SEQUENCE:Attributes | |
[dn] | |
dn = SET:rdn | |
[rdn] | |
cn = SEQUENCE:cn | |
[cn] | |
cn = OBJECT:commonName | |
val = FORMAT:UTF8,UTF8String:"$CN" | |
[PublicKeyInfo] | |
algorithm = SEQUENCE:$ALG | |
subjectPublicKey = FORMAT:HEX,BITSTRING:$pubkey | |
[ecp224] | |
algorithm = OBJECT:id-ecPublicKey | |
parameters = OBJECT:secp224r1 | |
[ecp256] | |
algorithm = OBJECT:id-ecPublicKey | |
parameters = OBJECT:prime256v1 | |
[ecp384] | |
algorithm = OBJECT:id-ecPublicKey | |
parameters = OBJECT:secp384r1 | |
[ecp521] | |
algorithm = OBJECT:id-ecPublicKey | |
parameters = OBJECT:secp521r1 | |
[eck256] | |
algorithm = OBJECT:id-ecPublicKey | |
parameters = OBJECT:secp256k1 | |
[ed25519] | |
parameters = OBJECT:ED25519 | |
[rsa2048] | |
parameters = OBJECT:rsaEncryption | |
parameters = NULL | |
[rsa3072] | |
algorithm = OBJECT:rsaEncryption | |
parameters = NULL | |
[rsa4096] | |
algorithm = OBJECT:rsaEncryption | |
parameters = NULL | |
[Attributes] | |
EOF | |
# The YubiHSM uses different names for PublicKeyInfo algorithm objects than OpenSSL | |
# | |
# YubiHSM OpenSSL | |
# ------- ------- | |
# ecp224 secp224r1 | |
# ecp256 prime256v1 | |
# ecp384 secp384r1 | |
# ecp521 secp521r1 | |
# eck256 secp256k1 | |
# ecbp256 - | |
# ecbp384 - | |
# ecbp512 - | |
# rsa2048 rsaEncryption | |
# rsa3072 rsaEncryption | |
# rsa4096 rsaEncryption | |
# compile ASN.1 | |
openssl asn1parse -genconf $TMP/tbs.asn1 -out $TMP/tbs.der #>/dev/null | |
# sign using YubiHSM | |
echo === Signing $SIGN / $SIGALG | |
yubihsm-shell -C yhusb:// -p password -a $SIGN -A $SIGALG -i $ID --in $TMP/tbs.der | base64 -d > $TMP/sig.der #2>/dev/null | |
# double check: verify signature | |
openssl dgst -sha256 -verify pubkey.pem -signature $TMP/sig.der $TMP/tbs.der | |
rm $TMP/tbs.der | |
# Generate CSR, include self-signature | |
cat << EOF > $TMP/csr.asn1 | |
asn1 = SEQUENCE:csr | |
[csr] | |
cri = SEQUENCE:CertificationRequestInfo | |
signatureAlgorithm = SEQUENCE:signatureAlgorithm | |
signature = FORMAT:HEX,BITSTRING:$(xxd -p $TMP/sig.der | tr -d '\n') | |
[signatureAlgorithm] | |
algorithm = OBJECT:$signatureAlgorithm | |
parameters = NULL | |
EOF | |
rm $TMP/sig.der | |
cat $TMP/tbs.asn1 | grep -v ^asn1 >> $TMP/csr.asn1 | |
rm $TMP/tbs.asn1 | |
# compile ASN.1 | |
openssl asn1parse -genconf $TMP/csr.asn1 -out $TMP/csr.der >/dev/null | |
rm $TMP/csr.asn1 | |
# verify signature | |
openssl req -in $TMP/csr.der -inform der -verify -out csr.pem && openssl req -in csr.pem | |
rm $TMP/csr.der | |
rmdir $TMP |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment