Skip to content

Commit f45416f

Browse files
committed
Update pkispawn to verify admin cert
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).
1 parent 57387d8 commit f45416f

File tree

10 files changed

+328
-41
lines changed

10 files changed

+328
-41
lines changed

.github/workflows/ca-existing-certs-test.yml

Lines changed: 96 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -189,54 +189,128 @@ jobs:
189189
nss-key-find \
190190
--nickname sslserver | tee sslserver.key.before
191191
192-
- name: Create admin cert
192+
- name: Export system certs
193+
run: |
194+
docker exec pki pki \
195+
pkcs12-export \
196+
--pkcs12 ca-certs.p12 \
197+
--password Secret.123 \
198+
ca_signing \
199+
ca_ocsp_signing \
200+
ca_audit_signing \
201+
subsystem \
202+
sslserver
203+
docker exec pki pki \
204+
pkcs12-cert-find \
205+
--pkcs12 ca-certs.p12 \
206+
--password Secret.123
207+
208+
- name: Create self-signed admin cert
193209
run: |
210+
# create cert request
194211
docker exec pki pki \
195212
nss-cert-request \
196213
--subject "CN=Administrator" \
197214
--ext /usr/share/pki/server/certs/admin.conf \
198215
--csr admin.csr
216+
217+
# create self-signed cert
199218
docker exec pki pki \
200219
nss-cert-issue \
201-
--issuer ca_signing \
202220
--csr admin.csr \
203221
--ext /usr/share/pki/server/certs/admin.conf \
204222
--cert admin.crt
205223
206-
docker exec pki pki nss-cert-import \
224+
# import cert
225+
docker exec pki pki \
226+
nss-cert-import \
207227
--cert admin.crt \
208228
caadmin
209229
210-
docker exec pki pki \
211-
nss-cert-show \
212-
caadmin
230+
# check cert
231+
docker exec pki pki nss-cert-show caadmin
213232
214-
- name: Export system certs
233+
# cert should be invalid
234+
docker exec pki pki nss-cert-verify caadmin \
235+
> >(tee stdout) 2> >(tee stderr >&2) || true
236+
237+
cat > expected << EOF
238+
ERROR: Invalid certificate: Unable to validate certificate signature: CN=Administrator
239+
EOF
240+
241+
diff expected stderr
242+
243+
- name: Install CA with existing system certs and self-signed admin cert
215244
run: |
245+
# run step 1
246+
docker exec pki pkispawn \
247+
-f /usr/share/pki/server/examples/installation/ca.cfg \
248+
-s CA \
249+
-D pki_ds_url=ldap://ds.example.com:3389 \
250+
-D pki_external=True \
251+
-D pki_external_step_two=False \
252+
-v
253+
254+
# run step 2
255+
rc=0
256+
docker exec pki pkispawn \
257+
-f /usr/share/pki/server/examples/installation/ca.cfg \
258+
-s CA \
259+
-D pki_ds_url=ldap://ds.example.com:3389 \
260+
-D pki_external=True \
261+
-D pki_external_step_two=True \
262+
-D pki_pkcs12_path=ca-certs.p12 \
263+
-D pki_pkcs12_password=Secret.123 \
264+
-D pki_ca_signing_csr_path=ca_signing.csr \
265+
-D pki_ocsp_signing_csr_path=ca_ocsp_signing.csr \
266+
-D pki_audit_signing_csr_path=ca_audit_signing.csr \
267+
-D pki_subsystem_csr_path=subsystem.csr \
268+
-D pki_sslserver_csr_path=sslserver.csr \
269+
-D pki_admin_cert_path=admin.crt \
270+
-D pki_admin_csr_path=admin.csr \
271+
-v \
272+
|| rc=$?
273+
274+
# pkispawn should fail
275+
[ $rc -ne 0 ]
276+
277+
- name: Create CA-signed admin cert
278+
run: |
279+
# remove old cert
280+
docker exec pki pki nss-cert-del caadmin
281+
282+
# create CA-signed cert
216283
docker exec pki pki \
217-
pkcs12-export \
218-
--pkcs12 ca-certs.p12 \
219-
--password Secret.123 \
220-
ca_signing \
221-
ca_ocsp_signing \
222-
ca_audit_signing \
223-
subsystem \
224-
sslserver
284+
nss-cert-issue \
285+
--issuer ca_signing \
286+
--csr admin.csr \
287+
--ext /usr/share/pki/server/certs/admin.conf \
288+
--cert admin.crt
289+
290+
# import new cert
225291
docker exec pki pki \
226-
pkcs12-cert-find \
227-
--pkcs12 ca-certs.p12 \
228-
--password Secret.123
292+
nss-cert-import \
293+
--cert admin.crt \
294+
caadmin
229295
230-
- name: Install CA with existing certs
296+
# check new cert
297+
docker exec pki pki nss-cert-show caadmin
298+
299+
# cert should be valid
300+
docker exec pki pki nss-cert-verify caadmin
301+
302+
- name: Install CA with existing system certs and CA-signed admin cert
231303
run: |
304+
# run step 1
232305
docker exec pki pkispawn \
233306
-f /usr/share/pki/server/examples/installation/ca.cfg \
234307
-s CA \
235308
-D pki_ds_url=ldap://ds.example.com:3389 \
236309
-D pki_external=True \
237310
-D pki_external_step_two=False \
238311
-v
239-
sleep 1 # avoid pkispawn log conflict due to identical timestamps
312+
313+
# run step 2
240314
docker exec pki pkispawn \
241315
-f /usr/share/pki/server/examples/installation/ca.cfg \
242316
-s CA \
@@ -254,6 +328,8 @@ jobs:
254328
-D pki_admin_csr_path=admin.csr \
255329
-v
256330
331+
# pkispawn should succeed
332+
257333
- name: Run PKI healthcheck
258334
run: docker exec pki pki-healthcheck --failures-only
259335

base/common/python/pki/nssdb.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2128,6 +2128,49 @@ def get_cert_info(self, nickname, token=None):
21282128

21292129
return cert
21302130

2131+
def verify_cert(
2132+
self,
2133+
nickname=None,
2134+
token=None,
2135+
cert_data=None,
2136+
cert_file=None,
2137+
cert_format='PEM'):
2138+
2139+
if cert_file and not cert_data:
2140+
with open(cert_file, 'r', encoding='utf-8') as f:
2141+
cert_data = f.read()
2142+
2143+
if cert_data:
2144+
cert_data = convert_cert(cert_data, cert_format, 'PEM')
2145+
2146+
cmd = [
2147+
'pki',
2148+
'-d', self.directory,
2149+
'-f', self.password_conf
2150+
]
2151+
2152+
token = self.get_effective_token(token)
2153+
2154+
if token:
2155+
cmd.extend(['--token', token])
2156+
2157+
cmd.append('nss-cert-verify')
2158+
2159+
if nickname:
2160+
if token:
2161+
fullname = token + ':' + nickname
2162+
else:
2163+
fullname = nickname
2164+
cmd.append(fullname)
2165+
2166+
if logger.isEnabledFor(logging.DEBUG):
2167+
cmd.append('--debug')
2168+
2169+
elif logger.isEnabledFor(logging.INFO):
2170+
cmd.append('--verbose')
2171+
2172+
self.run(cmd, input=cert_data, text=True, check=True, runas=True)
2173+
21312174
@staticmethod
21322175
def convert_time_to_millis(date):
21332176
return date.timestamp() * 1000

base/tomcat/src/main/java/org/dogtagpki/tomcat/PKITrustManager.java renamed to base/common/src/main/java/org/dogtagpki/cert/PKITrustManager.java

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
package org.dogtagpki.tomcat;
1+
package org.dogtagpki.cert;
22

3+
import java.security.SignatureException;
34
import java.security.cert.CertificateException;
45
import java.security.cert.X509Certificate;
56
import java.util.ArrayList;
@@ -20,8 +21,8 @@ public class PKITrustManager implements X509TrustManager {
2021

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

23-
final static String SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
24-
final static String CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";
24+
public final static String SERVER_AUTH_OID = "1.3.6.1.5.5.7.3.1";
25+
public final static String CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";
2526

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

@@ -57,6 +58,10 @@ public void checkCertChain(X509Certificate[] certChain, String keyUsage) throws
5758
}
5859
}
5960

61+
public void checkCert(X509Certificate cert) throws Exception {
62+
checkCert(cert, getAcceptedIssuers(), null);
63+
}
64+
6065
public void checkCert(X509Certificate cert, X509Certificate[] caCerts, String keyUsage) throws Exception {
6166

6267
logger.debug("PKITrustManager: checkCert(" + cert.getSubjectDN() + "):");
@@ -74,13 +79,13 @@ public void checkCert(X509Certificate cert, X509Certificate[] caCerts, String ke
7479
cert.verify(caCert.getPublicKey(), "Mozilla-JSS");
7580
issuer = caCert;
7681
break;
77-
} catch (Exception e) {
78-
logger.debug("PKITrustManager: invalid certificate: " + e);
82+
} catch (SignatureException e) {
83+
logger.debug("PKITrustManager: cert not issued by " + caCert.getSubjectDN() + ": " + e.getMessage());
7984
}
8085
}
8186

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

8691
logger.debug("PKITrustManager: cert signed by " + issuer.getSubjectDN());

base/server/python/pki/server/cli/http.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,7 @@ def execute(self, argv, args=None):
569569
HTTPConnectorCLI.set_param(connector, 'keyAlias', 'sslserver')
570570

571571
HTTPConnectorCLI.set_param(connector, 'trustManagerClassName',
572-
'org.dogtagpki.tomcat.PKITrustManager')
572+
'org.dogtagpki.cert.PKITrustManager')
573573

574574
HTTPConnectorCLI.set_param(connector, 'certdbDir', nss_database_dir)
575575
HTTPConnectorCLI.set_param(connector, 'passwordClass',

base/server/python/pki/server/deployment/__init__.py

Lines changed: 53 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@
4444
from cryptography import x509
4545
from cryptography.hazmat.backends import default_backend
4646

47-
import pki.nssdb
4847
import pki.account
48+
import pki.cli
4949
import pki.client
50+
import pki.nssdb
5051
import pki.pkcs12
5152
import pki.server
5253
import pki.server.deployment.scriptlets.configuration
@@ -2552,6 +2553,14 @@ def import_system_certs(self, nssdb, subsystem):
25522553

25532554
admin_cert = self.load_admin_cert()
25542555
if admin_cert:
2556+
2557+
cert_file = self.mdict.get('pki_admin_cert_path')
2558+
try:
2559+
logger.info('Verifying admin cert in %s', cert_file)
2560+
self.instance.verify_cert(admin_cert)
2561+
except Exception:
2562+
raise pki.cli.CLIException('Invalid admin certificate in %s' % cert_file)
2563+
25552564
self.import_admin_cert(admin_cert)
25562565

25572566
if subsystem.name == 'ocsp':
@@ -2561,6 +2570,14 @@ def import_system_certs(self, nssdb, subsystem):
25612570

25622571
admin_cert = self.load_admin_cert()
25632572
if admin_cert:
2573+
2574+
cert_file = self.mdict.get('pki_admin_cert_path')
2575+
try:
2576+
logger.info('Verifying admin cert in %s', cert_file)
2577+
self.instance.verify_cert(admin_cert)
2578+
except Exception:
2579+
raise pki.cli.CLIException('Invalid admin certificate in %s' % cert_file)
2580+
25642581
self.import_admin_cert(admin_cert)
25652582

25662583
self.import_system_cert(nssdb, subsystem, 'sslserver')
@@ -4000,6 +4017,13 @@ def setup_admin_cert(self, subsystem):
40004017
pem_cert = pki.nssdb.convert_cert(cert_info['data'], 'base64', 'pem')
40014018
logger.debug('Admin cert:\n%s', pem_cert)
40024019

4020+
try:
4021+
logger.info('Verifying admin cert in %s', client_nssdb.directory)
4022+
self.instance.verify_cert(pem_cert)
4023+
except Exception:
4024+
raise pki.cli.CLIException(
4025+
'Invalid admin certificate in %s' % client_nssdb.directory)
4026+
40034027
if external and subsystem.type != 'CA' or standalone:
40044028
# no need to re-import admin cert into NSS database
40054029
self.store_admin_cert(pem_cert)
@@ -4019,24 +4043,27 @@ def setup_admin_cert(self, subsystem):
40194043
and os.path.exists(pkcs12_file) \
40204044
and os.path.getsize(pkcs12_file) > 0:
40214045

4022-
logger.info('Importing admin cert from %s', pkcs12_file)
4046+
logger.info('Exporting admin cert from %s', pkcs12_file)
40234047
pkcs12_password = self.mdict['pki_client_pkcs12_password']
40244048

4025-
client_nssdb.import_pkcs12(
4026-
pkcs12_file=pkcs12_file,
4027-
pkcs12_password=pkcs12_password)
4049+
pkcs12 = pki.pkcs12.PKCS12(
4050+
path=pkcs12_file,
4051+
password=pkcs12_password)
40284052

4029-
cert_info = client_nssdb.get_cert_info(nickname)
4053+
pem_cert = pkcs12.get_cert(nickname)
4054+
logger.debug('Admin cert:\n%s', pem_cert)
40304055

4031-
if cert_info:
4032-
logger.info('Found %s cert in %s:', nickname, pkcs12_file)
4033-
logger.info('- serial: %s', hex(cert_info['serial_number']))
4034-
logger.info('- subject: %s', cert_info['subject'])
4035-
logger.info('- issuer: %s', cert_info['issuer'])
4036-
logger.info('- trust flags: %s', cert_info['trust_flags'])
4056+
try:
4057+
logger.info('Verifying admin cert in %s', pkcs12_file)
4058+
self.instance.verify_cert(pem_cert)
4059+
except Exception:
4060+
raise pki.cli.CLIException('Invalid admin certificate in %s' % pkcs12_file)
40374061

4038-
pem_cert = pki.nssdb.convert_cert(cert_info['data'], 'base64', 'pem')
4039-
logger.debug('Admin cert:\n%s', pem_cert)
4062+
logger.info('Importing admin cert into %s', client_nssdb.directory)
4063+
4064+
client_nssdb.import_pkcs12(
4065+
pkcs12_file=pkcs12_file,
4066+
pkcs12_password=pkcs12_password)
40404067

40414068
if external and subsystem.type != 'CA' or standalone:
40424069
# no need to re-import admin cert into NSS database
@@ -4058,6 +4085,12 @@ def setup_admin_cert(self, subsystem):
40584085

40594086
logger.debug('Admin cert:\n%s', pem_cert)
40604087

4088+
try:
4089+
logger.info('Verifying admin cert in %s', cert_path)
4090+
self.instance.verify_cert(pem_cert)
4091+
except Exception:
4092+
raise pki.cli.CLIException('Invalid admin certificate in %s' % cert_path)
4093+
40614094
if external and subsystem.type != 'CA' or standalone:
40624095
self.import_admin_cert(pem_cert)
40634096
self.store_admin_cert(pem_cert)
@@ -4076,6 +4109,12 @@ def setup_admin_cert(self, subsystem):
40764109

40774110
logger.debug('Admin cert:\n%s', pem_cert)
40784111

4112+
try:
4113+
logger.info('Verifying admin cert in %s', cert_file)
4114+
self.instance.verify_cert(pem_cert)
4115+
except Exception:
4116+
raise pki.cli.CLIException('Invalid admin certificate in %s' % cert_file)
4117+
40794118
if external and subsystem.type != 'CA' or standalone:
40804119
self.import_admin_cert(pem_cert)
40814120
self.store_admin_cert(pem_cert)

0 commit comments

Comments
 (0)