Skip to content

Commit

Permalink
Update pkispawn to verify admin cert
Browse files Browse the repository at this point in the history
The pki nss-cert-verify has been added to verify that a cert
is issued by a trusted CA. The cert can be provided in an NSS
database, in a file, or via standard input.

The PKITrustManager class has been moved into pki-common.jar
such that it can be used by the CLI. This class is not yet
officially supported so it's not necessary to provide an
upgrade script.

The NSSDatabase.verify_cert() has been added to verify a cert
using pki nss-cert-verify.

The PKIDeployer.import_system_certs() and setup_admin_cert()
have been modified to verify the admin cert provided during
installation.

The test for installing CA with existing certs has been updated
to install the CA with a self-signed admin cert (which should
fail), then install it again with a CA-signed cert (which should
work).
  • Loading branch information
edewata committed Feb 5, 2025
1 parent 57387d8 commit cd0daf6
Show file tree
Hide file tree
Showing 10 changed files with 330 additions and 52 deletions.
116 changes: 96 additions & 20 deletions .github/workflows/ca-existing-certs-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -189,54 +189,128 @@ jobs:
nss-key-find \
--nickname sslserver | tee sslserver.key.before
- name: Create admin cert
- name: Export system certs
run: |
docker exec pki pki \
pkcs12-export \
--pkcs12 ca-certs.p12 \
--password Secret.123 \
ca_signing \
ca_ocsp_signing \
ca_audit_signing \
subsystem \
sslserver
docker exec pki pki \
pkcs12-cert-find \
--pkcs12 ca-certs.p12 \
--password Secret.123
- name: Create self-signed admin cert
run: |
# create cert request
docker exec pki pki \
nss-cert-request \
--subject "CN=Administrator" \
--ext /usr/share/pki/server/certs/admin.conf \
--csr admin.csr
# create self-signed cert
docker exec pki pki \
nss-cert-issue \
--issuer ca_signing \
--csr admin.csr \
--ext /usr/share/pki/server/certs/admin.conf \
--cert admin.crt
docker exec pki pki nss-cert-import \
# import cert
docker exec pki pki \
nss-cert-import \
--cert admin.crt \
caadmin
docker exec pki pki \
nss-cert-show \
caadmin
# check cert
docker exec pki pki nss-cert-show caadmin
- name: Export system certs
# cert should be invalid
docker exec pki pki nss-cert-verify caadmin \
> >(tee stdout) 2> >(tee stderr >&2) || true
cat > expected << EOF
ERROR: Invalid certificate: Unable to validate certificate signature: CN=Administrator
EOF
diff expected stderr
- name: Install CA with existing system certs and self-signed admin cert
run: |
# run step 1
docker exec pki pkispawn \
-f /usr/share/pki/server/examples/installation/ca.cfg \
-s CA \
-D pki_ds_url=ldap://ds.example.com:3389 \
-D pki_external=True \
-D pki_external_step_two=False \
-v
# run step 2
rc=0
docker exec pki pkispawn \
-f /usr/share/pki/server/examples/installation/ca.cfg \
-s CA \
-D pki_ds_url=ldap://ds.example.com:3389 \
-D pki_external=True \
-D pki_external_step_two=True \
-D pki_pkcs12_path=ca-certs.p12 \
-D pki_pkcs12_password=Secret.123 \
-D pki_ca_signing_csr_path=ca_signing.csr \
-D pki_ocsp_signing_csr_path=ca_ocsp_signing.csr \
-D pki_audit_signing_csr_path=ca_audit_signing.csr \
-D pki_subsystem_csr_path=subsystem.csr \
-D pki_sslserver_csr_path=sslserver.csr \
-D pki_admin_cert_path=admin.crt \
-D pki_admin_csr_path=admin.csr \
-v \
|| rc=$?
# pkispawn should fail
[ $rc -ne 0 ]
- name: Create CA-signed admin cert
run: |
# remove old cert
docker exec pki pki nss-cert-del caadmin
# create CA-signed cert
docker exec pki pki \
pkcs12-export \
--pkcs12 ca-certs.p12 \
--password Secret.123 \
ca_signing \
ca_ocsp_signing \
ca_audit_signing \
subsystem \
sslserver
nss-cert-issue \
--issuer ca_signing \
--csr admin.csr \
--ext /usr/share/pki/server/certs/admin.conf \
--cert admin.crt
# import new cert
docker exec pki pki \
pkcs12-cert-find \
--pkcs12 ca-certs.p12 \
--password Secret.123
nss-cert-import \
--cert admin.crt \
caadmin
- name: Install CA with existing certs
# check new cert
docker exec pki pki nss-cert-show caadmin
# cert should be valid
docker exec pki pki nss-cert-verify caadmin
- name: Install CA with existing system certs and CA-signed admin cert
run: |
# run step 1
docker exec pki pkispawn \
-f /usr/share/pki/server/examples/installation/ca.cfg \
-s CA \
-D pki_ds_url=ldap://ds.example.com:3389 \
-D pki_external=True \
-D pki_external_step_two=False \
-v
sleep 1 # avoid pkispawn log conflict due to identical timestamps
# run step 2
docker exec pki pkispawn \
-f /usr/share/pki/server/examples/installation/ca.cfg \
-s CA \
Expand All @@ -254,6 +328,8 @@ jobs:
-D pki_admin_csr_path=admin.csr \
-v
# pkispawn should succeed
- name: Run PKI healthcheck
run: docker exec pki pki-healthcheck --failures-only

Expand Down
43 changes: 43 additions & 0 deletions base/common/python/pki/nssdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,49 @@ def get_cert_info(self, nickname, token=None):

return cert

def verify_cert(
self,
nickname=None,
token=None,
cert_data=None,
cert_file=None,
cert_format='PEM'):

if cert_file and not cert_data:
with open(cert_file, 'r', encoding='utf-8') as f:
cert_data = f.read()

if cert_data:
cert_data = convert_cert(cert_data, cert_format, 'PEM')

cmd = [
'pki',
'-d', self.directory,
'-f', self.password_conf
]

token = self.get_effective_token(token)

if token:
cmd.extend(['--token', token])

cmd.append('nss-cert-verify')

if nickname:
if token:
fullname = token + ':' + nickname
else:
fullname = nickname
cmd.append(fullname)

if logger.isEnabledFor(logging.DEBUG):
cmd.append('--debug')

elif logger.isEnabledFor(logging.INFO):
cmd.append('--verbose')

self.run(cmd, input=cert_data, text=True, check=True, runas=True)

@staticmethod
def convert_time_to_millis(date):
return date.timestamp() * 1000
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.dogtagpki.tomcat;
package org.dogtagpki.cert;

import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
Expand All @@ -20,8 +21,8 @@ public class PKITrustManager implements X509TrustManager {

final static Logger logger = LoggerFactory.getLogger(PKITrustManager.class);

final static String SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
final static String CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";
public final static String SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
public final static String CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";

public void checkCertChain(X509Certificate[] certChain, String keyUsage) throws Exception {

Expand Down Expand Up @@ -57,6 +58,10 @@ public void checkCertChain(X509Certificate[] certChain, String keyUsage) throws
}
}

public void checkCert(X509Certificate cert) throws Exception {
checkCert(cert, getAcceptedIssuers(), null);
}

public void checkCert(X509Certificate cert, X509Certificate[] caCerts, String keyUsage) throws Exception {

logger.debug("PKITrustManager: checkCert(" + cert.getSubjectDN() + "):");
Expand All @@ -74,13 +79,13 @@ public void checkCert(X509Certificate cert, X509Certificate[] caCerts, String ke
cert.verify(caCert.getPublicKey(), "Mozilla-JSS");
issuer = caCert;
break;
} catch (Exception e) {
logger.debug("PKITrustManager: invalid certificate: " + e);
} catch (SignatureException e) {
logger.debug("PKITrustManager: cert not issued by " + caCert.getSubjectDN() + ": " + e.getMessage());
}
}

if (issuer == null) {
throw new CertificateException("Unable to validate signature: " + cert.getSubjectDN());
throw new SignatureException("Unable to validate certificate signature: " + cert.getSubjectDN());
}

logger.debug("PKITrustManager: cert signed by " + issuer.getSubjectDN());
Expand Down
2 changes: 1 addition & 1 deletion base/server/python/pki/server/cli/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,7 +569,7 @@ def execute(self, argv, args=None):
HTTPConnectorCLI.set_param(connector, 'keyAlias', 'sslserver')

HTTPConnectorCLI.set_param(connector, 'trustManagerClassName',
'org.dogtagpki.tomcat.PKITrustManager')
'org.dogtagpki.cert.PKITrustManager')

HTTPConnectorCLI.set_param(connector, 'certdbDir', nss_database_dir)
HTTPConnectorCLI.set_param(connector, 'passwordClass',
Expand Down
Loading

0 comments on commit cd0daf6

Please sign in to comment.