From 64f3239c66d33ce4ecbeb4c2c732f7926d7d5b54 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Tue, 20 Aug 2024 12:48:50 -0500 Subject: [PATCH] Update cert approval callback Previously if a client tries to connect to a server but it does not have the CA signing cert installed and trusted it will get an UNTRUSTED_ISSUER error from NSS and the cert approval callback will ask the user whether to trust the cert. In the latest NSS the error has changed to UNKNOWN_ISSUER, so the callback has been updated to handle the error in the same way. The tests have also been updated accordingly. --- .github/workflows/server-https-nss-test.yml | 10 ++++---- .../workflows/server-https-pkcs12-test.yml | 10 ++++---- .../PKICertificateApprovalCallback.java | 23 ++++++++++++++----- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/.github/workflows/server-https-nss-test.yml b/.github/workflows/server-https-nss-test.yml index b0fd075ce20..8b5aa18f1af 100644 --- a/.github/workflows/server-https-nss-test.yml +++ b/.github/workflows/server-https-nss-test.yml @@ -163,7 +163,7 @@ jobs: -o /dev/null \ https://pki.example.com:8443 - - name: Check PKI CLI with untrusted server cert + - name: Check PKI CLI with unknown issuer run: | # run PKI CLI but don't trust the cert echo n | docker exec -i client pki -U https://pki.example.com:8443 info \ @@ -178,7 +178,7 @@ jobs: # check stderr cat > expected << EOF - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? SEVERE: FATAL: SSL alert sent: BAD_CERTIFICATE IOException: Unable to write to socket: Failed to write to socket: (-5987) Invalid function argument. EOF @@ -190,7 +190,7 @@ jobs: diff /dev/null output - - name: Check PKI CLI with untrusted server cert with wrong hostname + - name: Check PKI CLI with unknown issuer with wrong hostname run: | # run PKI CLI with wrong hostname echo n | docker exec -i client pki -U https://server.example.com:8443 info \ @@ -205,8 +205,8 @@ jobs: # check stderr cat > expected << EOF + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' WARNING: BAD_CERT_DOMAIN encountered on 'CN=pki.example.com' indicates a common-name mismatch - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? SEVERE: FATAL: SSL alert sent: BAD_CERTIFICATE IOException: Unable to write to socket: Failed to write to socket: (-12276) Unable to communicate securely with peer: requested domain name does not match the server's certificate. EOF @@ -229,7 +229,7 @@ jobs: # check stderr cat > expected << EOF - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? EOF diff --git a/.github/workflows/server-https-pkcs12-test.yml b/.github/workflows/server-https-pkcs12-test.yml index c2be337d02e..6a892fac791 100644 --- a/.github/workflows/server-https-pkcs12-test.yml +++ b/.github/workflows/server-https-pkcs12-test.yml @@ -197,7 +197,7 @@ jobs: -o /dev/null \ https://pki.example.com:8443 - - name: Check PKI CLI with untrusted server cert + - name: Check PKI CLI with unknown issuer run: | # run PKI CLI but don't trust the cert echo n | docker exec -i client pki \ @@ -214,7 +214,7 @@ jobs: # check stderr cat > expected << EOF - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? SEVERE: FATAL: SSL alert sent: BAD_CERTIFICATE IOException: Unable to write to socket: Failed to write to socket: (-5987) Invalid function argument. EOF @@ -226,7 +226,7 @@ jobs: diff /dev/null output - - name: Check PKI CLI with untrusted server cert and wrong hostname + - name: Check PKI CLI with unknown issuer and wrong hostname run: | # run PKI CLI with wrong hostname echo n | docker exec -i client pki \ @@ -243,8 +243,8 @@ jobs: # check stderr cat > expected << EOF + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' WARNING: BAD_CERT_DOMAIN encountered on 'CN=pki.example.com' indicates a common-name mismatch - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? SEVERE: FATAL: SSL alert sent: BAD_CERTIFICATE IOException: Unable to write to socket: Failed to write to socket: (-12276) Unable to communicate securely with peer: requested domain name does not match the server's certificate. EOF @@ -269,7 +269,7 @@ jobs: # check stderr cat > expected << EOF - WARNING: UNTRUSTED ISSUER encountered on 'CN=pki.example.com' indicates a non-trusted CA cert 'CN=CA Signing Certificate' + WARNING: UNKNOWN_ISSUER encountered on 'CN=pki.example.com' indicates an unknown CA cert 'CN=CA Signing Certificate' Trust this certificate (y/N)? EOF diff --git a/base/common/src/main/java/com/netscape/certsrv/client/PKICertificateApprovalCallback.java b/base/common/src/main/java/com/netscape/certsrv/client/PKICertificateApprovalCallback.java index 795acee9e07..4c6e9835bdd 100644 --- a/base/common/src/main/java/com/netscape/certsrv/client/PKICertificateApprovalCallback.java +++ b/base/common/src/main/java/com/netscape/certsrv/client/PKICertificateApprovalCallback.java @@ -109,11 +109,17 @@ public String getMessage(org.mozilla.jss.crypto.X509Certificate serverCert, int } if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) { - return "UNTRUSTED ISSUER encountered on '" + + return "UNTRUSTED_ISSUER encountered on '" + serverCert.getSubjectDN() + "' indicates a non-trusted CA cert '" + serverCert.getIssuerDN() + "'"; } + if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNKNOWN_ISSUER) { + return "UNKNOWN_ISSUER encountered on '" + + serverCert.getSubjectDN() + "' indicates an unknown CA cert '" + + serverCert.getIssuerDN() + "'"; + } + if (reason == SSLCertificateApprovalCallback.ValidityStatus.CA_CERT_INVALID) { return "CA_CERT_INVALID encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!"; } @@ -126,7 +132,7 @@ public String getMessage(org.mozilla.jss.crypto.X509Certificate serverCert, int return "Unknown/undefined reason "+reason+" encountered on '"+serverCert.getSubjectDN()+"' results in a denied SSL server cert!"; } - public boolean handleUntrustedIssuer(org.mozilla.jss.crypto.X509Certificate serverCert) { + public boolean trustCert(org.mozilla.jss.crypto.X509Certificate serverCert) { try { System.err.print("Trust this certificate (y/N)? "); @@ -172,7 +178,9 @@ public boolean approve(X509Certificate cert, ValidityStatus status) { // continue, or you can continue to make further tests of // your own to determine trustworthiness. Enumeration errors = status.getReasons(); + boolean approval = true; + boolean prompt = false; while (errors.hasMoreElements()) { SSLCertificateApprovalCallback.ValidityItem item = @@ -193,14 +201,13 @@ public boolean approve(X509Certificate cert, ValidityStatus status) { } else if (isIgnored(reason)) { // Ignore validity status - } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER) { + } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.UNTRUSTED_ISSUER + || reason == SSLCertificateApprovalCallback.ValidityStatus.UNKNOWN_ISSUER) { // Issue a WARNING, but allow this process // to continue since we haven't installed a trusted CA // cert for this operation. System.err.println("WARNING: " + getMessage(serverCert, reason)); - if (!handleUntrustedIssuer(serverCert)) { - approval = false; - } + prompt = true; } else if (reason == SSLCertificateApprovalCallback.ValidityStatus.BAD_CERT_DOMAIN) { // Issue a WARNING, but allow this process to continue on @@ -224,6 +231,10 @@ public boolean approve(X509Certificate cert, ValidityStatus status) { } } + if (prompt && !trustCert(serverCert)) { + approval = false; + } + return approval; } }