From cd68b1b5d7d476c316cdedd5eb99cf246dc6bc17 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Fri, 19 Jan 2024 13:35:53 +0700 Subject: [PATCH] Add HSM support for LWCA The CAEngine.createCA() has been modified to get the token name from LWCA's keyNickname. If the token name exists, it will use that token to create the private key and store the cert. Otherwise, it will use the internal token. The CASigningUnit.init() has been modified to get the token name from name from LWCA's keyNickname. If the token name exists, it will use that token to load the cert and the private key, and for signing and verification. Otherwise, it will use the internal token. The LWCA test with HSM has been modified to verify that the LWCA cert and key will be created in HSM instead of internal token. Resolves: https://github.com/dogtagpki/pki/issues/2412 --- .../workflows/subca-lightweight-hsm-test.yml | 31 ++++++++++--------- .github/workflows/subca-lightweight-test.yml | 10 ++++-- .../java/com/netscape/ca/CASigningUnit.java | 24 +++++++++++--- .../com/netscape/ca/CertificateAuthority.java | 8 ++--- .../org/dogtagpki/server/ca/CAEngine.java | 23 +++++++++++--- 5 files changed, 63 insertions(+), 33 deletions(-) diff --git a/.github/workflows/subca-lightweight-hsm-test.yml b/.github/workflows/subca-lightweight-hsm-test.yml index aaa1ca619ab..4d4bd35449d 100644 --- a/.github/workflows/subca-lightweight-hsm-test.yml +++ b/.github/workflows/subca-lightweight-hsm-test.yml @@ -208,12 +208,9 @@ jobs: "(objectClass=*)" | tee output # check authorityKeyNickname - echo "ca_signing $LWCA_ID" > expected + echo "HSM:ca_signing $LWCA_ID" > expected sed -n 's/^authorityKeyNickname:\s*\(.*\)$/\1/p' output > actual diff expected actual - # TODO: remove continue-on-error once this issue is fixed: - # https://github.com/dogtagpki/pki/issues/2412 - continue-on-error: true - name: Check certs and keys in internal token run: | @@ -222,8 +219,8 @@ jobs: -f /etc/pki/pki-tomcat/password.conf \ nss-cert-find | tee output - # there should be 6 certs now - echo "6" > expected + # there should still be 5 certs + echo "5" > expected sed -n 's/^\s*Nickname:\s*\(.*\)$/\1/p' output | wc -l > actual diff expected actual @@ -232,8 +229,8 @@ jobs: -f /etc/pki/pki-tomcat/password.conf \ nss-key-find | tee output - # there should be 2 keys now - echo "2" > expected + # there should still be 1 key + echo "1" > expected sed -n 's/^\s*Key ID:\s*\(.*\)$/\1/p' output | wc -l > actual diff expected actual @@ -245,8 +242,8 @@ jobs: --token HSM \ nss-cert-find | tee output - # there should be 4 certs now - echo "4" > expected + # there should be 5 certs now + echo "5" > expected sed -n 's/^\s*Nickname:\s*\(.*\)$/\1/p' output | wc -l > actual diff expected actual @@ -256,8 +253,8 @@ jobs: --token HSM \ nss-key-find | tee output - # there should be 4 keys now - echo "4" > expected + # there should be 5 keys now + echo "5" > expected sed -n 's/^\s*Key ID:\s*\(.*\)$/\1/p' output | wc -l > actual diff expected actual @@ -293,10 +290,15 @@ jobs: # https://github.com/dogtagpki/pki/issues/2412 continue-on-error: true + - name: Check CA debug logs + if: always() + run: | + docker exec pki bash -c "cat /var/log/pki/pki-tomcat/ca/debug.*" + - name: Gather artifacts if: always() run: | - tests/bin/ds-artifacts-save.sh --output=/tmp/artifacts/pki ds + tests/bin/ds-artifacts-save.sh ds tests/bin/pki-artifacts-save.sh pki continue-on-error: true @@ -313,5 +315,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: ca-lightweight-hsm - path: | - /tmp/artifacts/pki + path: /tmp/artifacts diff --git a/.github/workflows/subca-lightweight-test.yml b/.github/workflows/subca-lightweight-test.yml index 7eacec3c456..67ea066f6e6 100644 --- a/.github/workflows/subca-lightweight-test.yml +++ b/.github/workflows/subca-lightweight-test.yml @@ -212,10 +212,15 @@ jobs: sed -n -e 's/^\s*Issuer DN:\s*\(.*\)$/\1/p' output > actual diff expected actual + - name: Check CA debug logs + if: always() + run: | + docker exec pki bash -c "cat /var/log/pki/pki-tomcat/ca/debug.*" + - name: Gather artifacts if: always() run: | - tests/bin/ds-artifacts-save.sh --output=/tmp/artifacts/pki ds + tests/bin/ds-artifacts-save.sh ds tests/bin/pki-artifacts-save.sh pki continue-on-error: true @@ -227,5 +232,4 @@ jobs: uses: actions/upload-artifact@v3 with: name: ca-lightweight - path: | - /tmp/artifacts/pki + path: /tmp/artifacts diff --git a/base/ca/src/main/java/com/netscape/ca/CASigningUnit.java b/base/ca/src/main/java/com/netscape/ca/CASigningUnit.java index 95f0a962272..640d90b98d9 100644 --- a/base/ca/src/main/java/com/netscape/ca/CASigningUnit.java +++ b/base/ca/src/main/java/com/netscape/ca/CASigningUnit.java @@ -70,19 +70,33 @@ public void init(SigningUnitConfig config, String nickname) throws EBaseExceptio mManager = CryptoManager.getInstance(); if (nickname == null) { + // use nickname from config try { mNickname = mConfig.getCertNickname(); } catch (EPropertyNotFound e) { mNickname = mConfig.getCACertNickname(); } + + // use token name from config + tokenname = config.getTokenName(); + mToken = CryptoUtil.getKeyStorageToken(tokenname); + + // prepend token name to nickname + if (!CryptoUtil.isInternalToken(tokenname)) { + mNickname = tokenname + ":" + mNickname; + } + } else { + // use specified nickname (which might contain token name) mNickname = nickname; - } - tokenname = config.getTokenName(); - mToken = CryptoUtil.getKeyStorageToken(tokenname); - if (!CryptoUtil.isInternalToken(tokenname)) { - mNickname = tokenname + ":" + mNickname; + // get token name from nickname + int i = mNickname.indexOf(':'); + if (i >= 0) { + tokenname = mNickname.substring(0, i); + } + + mToken = CryptoUtil.getKeyStorageToken(tokenname); } try { diff --git a/base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java b/base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java index 935d6714757..3c473481065 100644 --- a/base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java +++ b/base/ca/src/main/java/com/netscape/ca/CertificateAuthority.java @@ -1703,14 +1703,10 @@ public Collection getAuthorityKeyHosts() { public X509CertImpl generateSigningCert( X500Name subjectX500Name, - AuthToken authToken) + AuthToken authToken, + CryptoToken token) throws Exception { - CryptoManager cryptoManager = CryptoManager.getInstance(); - - // TODO: read PROP_TOKEN_NAME config - CryptoToken token = cryptoManager.getInternalKeyStorageToken(); - logger.info("CertificateAuthority: generating RSA key"); // Key size of sub-CA shall be key size of this CA. diff --git a/base/ca/src/main/java/org/dogtagpki/server/ca/CAEngine.java b/base/ca/src/main/java/org/dogtagpki/server/ca/CAEngine.java index f94f1a60c89..9a7cc4c6484 100644 --- a/base/ca/src/main/java/org/dogtagpki/server/ca/CAEngine.java +++ b/base/ca/src/main/java/org/dogtagpki/server/ca/CAEngine.java @@ -46,6 +46,7 @@ import org.dogtagpki.server.authentication.AuthenticationConfig; import org.dogtagpki.util.cert.CertUtil; import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.crypto.CryptoStore; import org.mozilla.jss.crypto.CryptoToken; import org.mozilla.jss.crypto.EncryptionAlgorithm; import org.mozilla.jss.crypto.KeyWrapAlgorithm; @@ -1165,12 +1166,26 @@ public CertificateAuthority createCA( X509CertImpl cert = null; try { + int i = keyNickname.indexOf(':'); + String tokenname; + String nickname; + + if (i >= 0) { + tokenname = keyNickname.substring(0, i); + nickname = keyNickname.substring(i + 1); + } else { + tokenname = null; + nickname = keyNickname; + } + + CryptoToken token = CryptoUtil.getKeyStorageToken(tokenname); + logger.info("CAEngine: Generating signing certificate"); - cert = parentCA.generateSigningCert(subjectX500Name, authToken); + cert = parentCA.generateSigningCert(subjectX500Name, authToken, token); - logger.info("CAEngine: Importing signing certificate into NSS database"); - CryptoManager cryptoManager = CryptoManager.getInstance(); - cryptoManager.importCertPackage(cert.getEncoded(), keyNickname); + logger.info("CAEngine: Importing " + nickname + " cert into " + token.getName()); + CryptoStore store = token.getCryptoStore(); + store.importCert(cert.getEncoded(), nickname); } catch (Exception e) { logger.error("Unable to generate signing certificate: " + e.getMessage(), e);