summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/common/python/pki/nss.py247
-rw-r--r--base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java12
-rw-r--r--base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java101
-rw-r--r--base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java38
-rw-r--r--base/server/etc/default.cfg10
-rw-r--r--base/server/python/pki/server/__init__.py5
-rw-r--r--base/server/python/pki/server/deployment/pkihelper.py70
-rw-r--r--base/server/python/pki/server/deployment/scriptlets/configuration.py128
-rw-r--r--base/server/python/pki/server/deployment/scriptlets/finalization.py12
9 files changed, 557 insertions, 66 deletions
diff --git a/base/common/python/pki/nss.py b/base/common/python/pki/nss.py
index f36b771f8..196fe462f 100644
--- a/base/common/python/pki/nss.py
+++ b/base/common/python/pki/nss.py
@@ -32,12 +32,19 @@ CSR_FOOTER = '-----END NEW CERTIFICATE REQUEST-----'
CERT_HEADER = '-----BEGIN CERTIFICATE-----'
CERT_FOOTER = '-----END CERTIFICATE-----'
+PKCS7_HEADER = '-----BEGIN PKCS7-----'
+PKCS7_FOOTER = '-----END PKCS7-----'
+
def convert_data(data, input_format, output_format, header=None, footer=None):
+ if input_format == output_format:
+ return data
+
if input_format == 'base64' and output_format == 'pem':
# split a single line into multiple lines
+ data = data.rstrip('\r\n')
lines = [data[i:i+64] for i in range(0, len(data), 64)]
return '%s\n%s\n%s\n' % (header, '\n'.join(lines), footer)
@@ -65,11 +72,32 @@ def convert_cert(cert_data, input_format, output_format):
return convert_data(cert_data, input_format, output_format, CERT_HEADER, CERT_FOOTER)
+def convert_pkcs7(pkcs7_data, input_format, output_format):
+
+ return convert_data(pkcs7_data, input_format, output_format, PKCS7_HEADER, PKCS7_FOOTER)
+
+def get_file_type(filename):
+
+ with open(filename, 'r') as f:
+ data = f.read()
+
+ if data.startswith(CSR_HEADER):
+ return 'csr'
+
+ if data.startswith(CERT_HEADER):
+ return 'cert'
+
+ if data.startswith(PKCS7_HEADER):
+ return 'pkcs7'
+
+ return None
+
class NSSDatabase(object):
- def __init__(self, directory, password=None, password_file=None):
+ def __init__(self, directory, token='internal', password=None, password_file=None):
self.directory = directory
+ self.token = token
self.tmpdir = tempfile.mkdtemp()
@@ -88,29 +116,38 @@ class NSSDatabase(object):
shutil.rmtree(self.tmpdir)
def add_cert(self,
- nickname, cert_file,
- trust_attributes='u,u,u'):
+ nickname,
+ cert_file,
+ trust_attributes=',,'):
- subprocess.check_call([
+ cmd = [
'certutil',
'-A',
'-d', self.directory,
+ '-h', self.token,
+ '-f', self.password_file,
'-n', nickname,
'-i', cert_file,
'-t', trust_attributes
- ])
+ ]
+
+ subprocess.check_call(cmd)
def modify_cert(self,
nickname,
- trust_attributes='u,u,u'):
+ trust_attributes):
- subprocess.check_call([
+ cmd = [
'certutil',
'-M',
'-d', self.directory,
+ '-h', self.token,
+ '-f', self.password_file,
'-n', nickname,
'-t', trust_attributes
- ])
+ ]
+
+ subprocess.check_call(cmd)
def create_noise(self, noise_file, size=2048):
@@ -123,27 +160,56 @@ class NSSDatabase(object):
def create_request(self,
subject_dn,
- noise_file,
- request_file):
+ request_file,
+ noise_file=None,
+ key_type=None,
+ key_size=None,
+ curve=None,
+ hash_alg=None):
tmpdir = tempfile.mkdtemp()
try:
+ if not noise_file:
+ noise_file = os.path.join(tmpdir, 'noise.bin')
+ if key_size:
+ size = key_size
+ else:
+ size = 2048
+ self.create_noise(
+ noise_file=noise_file,
+ size=size)
+
binary_request_file = os.path.join(tmpdir, 'request.bin')
- b64_request_file = os.path.join(tmpdir, 'request.b64')
- # generate binary request
- subprocess.check_call([
+ cmd = [
'certutil',
'-R',
'-d', self.directory,
+ '-h', self.token,
'-f', self.password_file,
'-s', subject_dn,
- '-z', noise_file,
- '-o', binary_request_file
- ])
+ '-o', binary_request_file,
+ '-z', noise_file
+ ]
+
+ if key_type:
+ cmd.extend(['-k', key_type])
+
+ if key_size:
+ cmd.extend(['-g', str(key_size)])
+
+ if curve:
+ cmd.extend(['-q', curve])
+
+ if hash_alg:
+ cmd.extend(['-Z', hash_alg])
+
+ # generate binary request
+ subprocess.check_call(cmd)
# encode binary request in base-64
+ b64_request_file = os.path.join(tmpdir, 'request.b64')
subprocess.check_call([
'BtoA', binary_request_file, b64_request_file])
@@ -167,11 +233,12 @@ class NSSDatabase(object):
serial='1',
validity=240):
- p = subprocess.Popen([
+ cmd = [
'certutil',
'-C',
'-x',
'-d', self.directory,
+ '-h', self.token,
'-f', self.password_file,
'-c', subject_dn,
'-a',
@@ -184,7 +251,9 @@ class NSSDatabase(object):
'-3',
'--extSKID',
'--extAIA'
- ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ ]
+
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
keystroke = ''
@@ -245,7 +314,7 @@ class NSSDatabase(object):
rc = p.wait()
if rc:
- raise Exception('Failed to generate self-signed CA certificate. RC: %d' + rc)
+ raise Exception('Failed to generate self-signed CA certificate. RC: %d' % rc)
def get_cert(self, nickname, output_format='pem'):
@@ -258,13 +327,17 @@ class NSSDatabase(object):
else:
raise Exception('Unsupported output format: %s' % output_format)
- cert_data = subprocess.check_output([
+ cmd = [
'certutil',
'-L',
'-d', self.directory,
+ '-h', self.token,
+ '-f', self.password_file,
'-n', nickname,
output_format_option
- ])
+ ]
+
+ cert_data = subprocess.check_output(cmd)
if output_format == 'base64':
cert_data = base64.b64encode(cert_data)
@@ -273,12 +346,127 @@ class NSSDatabase(object):
def remove_cert(self, nickname):
- subprocess.check_call([
+ cmd = [
'certutil',
'-D',
'-d', self.directory,
+ '-h', self.token,
+ '-f', self.password_file,
'-n', nickname
- ])
+ ]
+
+ subprocess.check_call(cmd)
+
+ def import_cert_chain(self, nickname, cert_chain_file, trust_attributes=None):
+
+ tmpdir = tempfile.mkdtemp()
+
+ try:
+ file_type = get_file_type(cert_chain_file)
+
+ if file_type == 'cert': # import single PEM cert
+ self.add_cert(
+ nickname=nickname,
+ cert_file=cert_chain_file,
+ trust_attributes=trust_attributes)
+ return self.get_cert(
+ nickname=nickname,
+ output_format='base64')
+
+ elif file_type == 'pkcs7': # import PKCS #7 cert chain
+ return self.import_pkcs7(
+ pkcs7_file=cert_chain_file,
+ nickname=nickname,
+ trust_attributes=trust_attributes,
+ output_format='base64')
+
+ else: # import PKCS #7 data without header/footer
+ with open(cert_chain_file, 'r') as f:
+ base64_data = f.read()
+ pkcs7_data = convert_pkcs7(base64_data, 'base64', 'pem')
+
+ tmp_cert_chain_file = os.path.join(tmpdir, 'cert_chain.p7b')
+ with open(tmp_cert_chain_file, 'w') as f:
+ f.write(pkcs7_data)
+
+ self.import_pkcs7(
+ pkcs7_file=tmp_cert_chain_file,
+ nickname=nickname,
+ trust_attributes=trust_attributes)
+
+ return base64_data
+
+ finally:
+ shutil.rmtree(tmpdir)
+
+ def import_pkcs7(self, pkcs7_file, nickname, trust_attributes=None, output_format='pem'):
+
+ tmpdir = tempfile.mkdtemp()
+
+ try:
+ # export certs from PKCS #7 into PEM output
+ output = subprocess.check_output([
+ 'openssl',
+ 'pkcs7',
+ '-print_certs',
+ '-in', pkcs7_file
+ ])
+
+ # parse PEM output into separate PEM certificates
+ certs = []
+ lines = []
+ state = 'header'
+
+ for line in output.splitlines():
+
+ if state == 'header':
+ if line != CERT_HEADER:
+ # ignore header lines
+ pass
+ else:
+ # save cert header
+ lines.append(line)
+ state = 'body'
+
+ elif state == 'body':
+ if line != CERT_FOOTER:
+ # save cert body
+ lines.append(line)
+ else:
+ # save cert footer
+ lines.append(line)
+
+ # construct PEM cert
+ cert = '\n'.join(lines)
+ certs.append(cert)
+ lines = []
+ state = 'header'
+
+ # import PEM certs into NSS database
+ counter = 1
+ for cert in certs:
+
+ cert_file = os.path.join(tmpdir, 'cert%d.pem' % counter)
+ with open(cert_file, 'w') as f:
+ f.write(cert)
+
+ if counter == 1:
+ n = nickname
+ else:
+ n = '%s #%d' % (nickname, counter)
+
+ self.add_cert(n, cert_file, trust_attributes)
+
+ counter += 1
+
+ # convert PKCS #7 data to the requested format
+ with open(pkcs7_file, 'r') as f:
+ data = f.read()
+
+ return convert_pkcs7(data, 'pem', output_format)
+
+ finally:
+ shutil.rmtree(tmpdir)
def import_pkcs12(self, pkcs12_file, pkcs12_password=None, pkcs12_password_file=None):
@@ -296,13 +484,16 @@ class NSSDatabase(object):
else:
raise Exception('Missing PKCS #12 password')
- subprocess.check_call([
+ cmd = [
'pk12util',
'-d', self.directory,
+ '-h', self.token,
'-k', self.password_file,
'-i', pkcs12_file,
'-w', password_file
- ])
+ ]
+
+ subprocess.check_call(cmd)
finally:
shutil.rmtree(tmpdir)
@@ -323,14 +514,16 @@ class NSSDatabase(object):
else:
raise Exception('Missing PKCS #12 password')
- subprocess.check_call([
+ cmd = [
'pk12util',
'-d', self.directory,
'-k', self.password_file,
'-o', pkcs12_file,
'-w', password_file,
'-n', nickname
- ])
+ ]
+
+ subprocess.check_call(cmd)
finally:
shutil.rmtree(tmpdir)
diff --git a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
index 7c6c339f5..8c9da6f37 100644
--- a/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
+++ b/base/common/src/com/netscape/certsrv/system/ConfigurationRequest.java
@@ -178,6 +178,9 @@ public class ConfigurationRequest {
protected String adminCert;
@XmlElement
+ protected Boolean external;
+
+ @XmlElement
protected String standAlone;
@XmlElement
@@ -754,6 +757,14 @@ public class ConfigurationRequest {
this.adminCert = adminCert;
}
+ public Boolean isExternal() {
+ return external;
+ }
+
+ public void setExternal(Boolean external) {
+ this.external = external;
+ }
+
public boolean getStandAlone() {
return (standAlone != null && standAlone.equalsIgnoreCase("true"));
}
@@ -945,6 +956,7 @@ public class ConfigurationRequest {
", adminCert=" + adminCert +
", importAdminCert=" + importAdminCert +
", generateServerCert=" + generateServerCert +
+ ", external=" + external +
", standAlone=" + standAlone +
", stepTwo=" + stepTwo +
", authdbBaseDN=" + authdbBaseDN +
diff --git a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
index 88118adf8..91dad159b 100644
--- a/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
+++ b/base/server/cms/src/com/netscape/cms/servlet/csadmin/ConfigurationUtils.java
@@ -126,6 +126,7 @@ import com.netscape.certsrv.base.EBaseException;
import com.netscape.certsrv.base.EPropertyNotFound;
import com.netscape.certsrv.base.IConfigStore;
import com.netscape.certsrv.base.ISubsystem;
+import com.netscape.certsrv.base.MetaInfo;
import com.netscape.certsrv.base.PKIException;
import com.netscape.certsrv.base.ResourceNotFoundException;
import com.netscape.certsrv.ca.ICertificateAuthority;
@@ -133,6 +134,8 @@ import com.netscape.certsrv.client.ClientConfig;
import com.netscape.certsrv.client.PKIClient;
import com.netscape.certsrv.client.PKIConnection;
import com.netscape.certsrv.dbs.IDBSubsystem;
+import com.netscape.certsrv.dbs.certdb.ICertRecord;
+import com.netscape.certsrv.dbs.certdb.ICertificateRepository;
import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord;
import com.netscape.certsrv.key.KeyData;
import com.netscape.certsrv.ldap.ILdapConnFactory;
@@ -2248,6 +2251,54 @@ public class ConfigurationUtils {
certObj.setCertChain(certChainStr);
}
+ public static KeyPair loadKeyPair(String nickname) throws Exception {
+
+ CMS.debug("ConfigurationUtils: loadKeyPair(" + nickname + ")");
+
+ CryptoManager cm = CryptoManager.getInstance();
+
+ X509Certificate cert = cm.findCertByNickname(nickname);
+ PublicKey publicKey = cert.getPublicKey();
+ PrivateKey privateKey = cm.findPrivKeyByCert(cert);
+
+ return new KeyPair(publicKey, privateKey);
+ }
+
+ public static void storeKeyPair(IConfigStore config, String tag, KeyPair pair)
+ throws TokenException, EBaseException {
+
+ CMS.debug("ConfigurationUtils: storeKeyPair(" + tag + ")");
+
+ PublicKey publicKey = pair.getPublic();
+
+ if (publicKey instanceof RSAPublicKey) {
+
+ RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
+
+ byte modulus[] = rsaPublicKey.getModulus().toByteArray();
+ config.putString(PCERT_PREFIX + tag + ".pubkey.modulus",
+ CryptoUtil.byte2string(modulus));
+
+ byte exponent[] = rsaPublicKey.getPublicExponent().toByteArray();
+ config.putString(PCERT_PREFIX + tag + ".pubkey.exponent",
+ CryptoUtil.byte2string(exponent));
+
+ } else { // ECC
+
+ CMS.debug("ConfigurationUtils: Public key class: " + publicKey.getClass().getName());
+ byte encoded[] = publicKey.getEncoded();
+ config.putString(PCERT_PREFIX + tag + ".pubkey.encoded", CryptoUtil.byte2string(encoded));
+ }
+
+ PrivateKey privateKey = (PrivateKey) pair.getPrivate();
+ byte id[] = privateKey.getUniqueID();
+ String kid = CryptoUtil.byte2string(id);
+ config.putString(PCERT_PREFIX + tag + ".privkey.id", kid);
+
+ String keyAlgo = config.getString(PCERT_PREFIX + tag + ".signingalgorithm");
+ setSigningAlgorithm(tag, keyAlgo, config);
+ }
+
public static void createECCKeyPair(String token, String curveName, IConfigStore config, String ct)
throws NoSuchAlgorithmException, NoSuchTokenException, TokenException,
CryptoManager.NotInitializedException, EPropertyNotFound, EBaseException {
@@ -2812,6 +2863,20 @@ public class ConfigurationUtils {
}
}
+ public static void loadCertRequest(IConfigStore config, String tag, Cert cert) throws Exception {
+
+ CMS.debug("ConfigurationUtils.loadCertRequest(" + tag + ")");
+
+ String subjectDN = config.getString(PCERT_PREFIX + tag + ".dn");
+ cert.setDN(subjectDN);
+
+ String subsystem = config.getString(PCERT_PREFIX + tag + ".subsystem");
+ String certreq = config.getString(subsystem + "." + tag + ".certreq");
+ String formattedCertreq = CryptoUtil.reqFormat(certreq);
+
+ cert.setRequest(formattedCertreq);
+ }
+
public static void handleCertRequest(IConfigStore config, String certTag, Cert cert) throws EPropertyNotFound,
EBaseException, InvalidKeyException, NotInitializedException, TokenException, NoSuchAlgorithmException,
NoSuchProviderException, CertificateException, SignatureException, IOException {
@@ -2953,6 +3018,42 @@ public class ConfigurationUtils {
return pubk;
}
+ public static void loadCert(IConfigStore config, Cert cert) throws Exception {
+
+ String tag = cert.getCertTag();
+ CMS.debug("ConfigurationUtils: loadCert(" + tag + ")");
+
+ CryptoManager cm = CryptoManager.getInstance();
+ X509Certificate x509Cert = cm.findCertByNickname(cert.getNickname());
+
+ if (!x509Cert.getSubjectDN().equals(x509Cert.getIssuerDN())) {
+ CMS.debug("ConfigurationUtils: " + tag + " cert is not self-signed");
+
+ String subsystem = config.getString(PCERT_PREFIX + tag + ".subsystem");
+ String certChain = config.getString(subsystem + ".external_ca_chain.cert");
+ cert.setCertChain(certChain);
+
+ return;
+ }
+
+ CMS.debug("ConfigurationUtils: " + tag + " cert is self-signed");
+
+ // When importing existing self-signed CA certificate, create a
+ // certificate record to reserve the serial number. Otherwise it
+ // might conflict with system certificates to be created later.
+
+ X509CertImpl x509CertImpl = new X509CertImpl(x509Cert.getEncoded());
+
+ ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem(ICertificateAuthority.ID);
+ ICertificateRepository cr = ca.getCertificateRepository();
+
+ BigInteger serialNo = x509Cert.getSerialNumber();
+ MetaInfo meta = new MetaInfo();
+
+ ICertRecord record = cr.createCertRecord(serialNo, x509CertImpl, meta);
+ cr.addCertificateRecord(record);
+ }
+
public static int handleCerts(Cert cert) throws IOException, EBaseException, CertificateException,
NotInitializedException, TokenException, InvalidKeyException {
String certTag = cert.getCertTag();
diff --git a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
index a0138681a..697196a6e 100644
--- a/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
+++ b/base/server/cms/src/org/dogtagpki/server/rest/SystemConfigService.java
@@ -20,6 +20,7 @@ package org.dogtagpki.server.rest;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.ArrayList;
@@ -420,7 +421,13 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
}
cs.commit(false);
- if (!request.getStepTwo()) {
+ if (request.isExternal() && tag.equals("signing")) { // external/existing CA
+ // load key pair for existing and externally-signed signing cert
+ CMS.debug("SystemConfigService: loading signing cert key pair");
+ KeyPair pair = ConfigurationUtils.loadKeyPair(certData.getNickname());
+ ConfigurationUtils.storeKeyPair(cs, tag, pair);
+
+ } else if (!request.getStepTwo()) {
if (keytype.equals("ecc")) {
String curvename = certData.getKeyCurveName() != null ?
certData.getKeyCurveName() : cs.getString("keys.ecc.curve.default");
@@ -443,7 +450,15 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
cert.setSubsystem(cs.getString("preop.cert." + tag + ".subsystem"));
cert.setType(cs.getString("preop.cert." + tag + ".type"));
- if (!request.getStepTwo()) {
+ if (request.isExternal() && tag.equals("signing")) { // external/existing CA
+
+ // update configuration for existing or externally-signed signing certificate
+ String certStr = cs.getString("ca." + tag + ".cert" );
+ cert.setCert(certStr);
+ CMS.debug("SystemConfigService: certificate " + tag + ": " + certStr);
+ ConfigurationUtils.updateConfig(cs, tag);
+
+ } else if (!request.getStepTwo()) {
ConfigurationUtils.configCert(null, null, null, cert);
} else {
@@ -465,8 +480,16 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
CMS.debug("Step 2: certStr for '" + tag + "' is " + certStr);
}
- // Handle Cert Requests for everything EXCEPT Stand-alone PKI (Step 2)
- if (request.getStandAlone()) {
+ if (request.isExternal() && tag.equals("signing")) { // external/existing CA
+
+ CMS.debug("SystemConfigService: Loading cert request for " + tag + " cert");
+ ConfigurationUtils.loadCertRequest(cs, tag, cert);
+
+ CMS.debug("SystemConfigService: Loading cert " + tag);
+ ConfigurationUtils.loadCert(cs, cert);
+
+ } else if (request.getStandAlone()) {
+ // Handle Cert Requests for everything EXCEPT Stand-alone PKI (Step 2)
if (!request.getStepTwo()) {
// Stand-alone PKI (Step 1)
ConfigurationUtils.handleCertRequest(cs, tag, cert);
@@ -489,6 +512,13 @@ public class SystemConfigService extends PKIService implements SystemConfigResou
ConfigurationUtils.updateCloneConfig();
}
+ if (request.isExternal() && tag.equals("signing")) { // external/existing CA
+ CMS.debug("SystemConfigService: External CA has signing cert");
+ hasSigningCert.setValue(true);
+ certs.add(cert);
+ continue;
+ }
+
// to determine if we have the signing cert when using an external ca
// this will only execute on a ca or stand-alone pki
String b64 = certData.getCert();
diff --git a/base/server/etc/default.cfg b/base/server/etc/default.cfg
index ddd2d8367..1c1ae92b3 100644
--- a/base/server/etc/default.cfg
+++ b/base/server/etc/default.cfg
@@ -22,6 +22,7 @@ sensitive_parameters=
pki_client_pkcs12_password
pki_clone_pkcs12_password
pki_ds_password
+ pki_external_pkcs12_password
pki_one_time_pin
pki_pin
pki_replication_password
@@ -365,10 +366,13 @@ pki_req_ext_add=False
pki_req_ext_oid=1.3.6.1.4.1.311.20.2
pki_req_ext_critical=False
pki_req_ext_data=1E0A00530075006200430041
-pki_external_csr_path=%(pki_instance_configuration_path)s/ca_signing.csr
+pki_external_csr_path=
pki_external_step_two=False
-pki_external_ca_cert_chain_path=%(pki_instance_configuration_path)s/external_ca_chain.cert
-pki_external_ca_cert_path=%(pki_instance_configuration_path)s/external_ca.cert
+pki_external_ca_cert_chain_path=
+pki_external_ca_cert_chain_nickname=caSigningCert External CA
+pki_external_ca_cert_path=
+pki_external_pkcs12_path=
+pki_external_pkcs12_password=
pki_import_admin_cert=False
pki_ocsp_signing_key_algorithm=SHA256withRSA
pki_ocsp_signing_key_size=2048
diff --git a/base/server/python/pki/server/__init__.py b/base/server/python/pki/server/__init__.py
index d55a3691d..bf592dcd5 100644
--- a/base/server/python/pki/server/__init__.py
+++ b/base/server/python/pki/server/__init__.py
@@ -328,10 +328,11 @@ class PKIInstance(object):
return password
- def open_nssdb(self):
+ def open_nssdb(self, token='internal'):
return pki.nss.NSSDatabase(
directory=self.nssdb_dir,
- password=self.get_password('internal'))
+ token=token,
+ password=self.get_password(token))
def get_subsystem(self, name):
for subsystem in self.subsystems:
diff --git a/base/server/python/pki/server/deployment/pkihelper.py b/base/server/python/pki/server/deployment/pkihelper.py
index 61f04d215..9c9b40454 100644
--- a/base/server/python/pki/server/deployment/pkihelper.py
+++ b/base/server/python/pki/server/deployment/pkihelper.py
@@ -757,8 +757,7 @@ class ConfigurationFile:
# External CA
if not self.external_step_two:
# External CA (Step 1)
- self.confirm_data_exists("pki_external_csr_path")
- self.confirm_missing_file("pki_external_csr_path")
+ # The pki_external_csr_path is optional.
# generic extension support in CSR - for external CA
if self.add_req_ext:
self.confirm_data_exists("pki_req_ext_oid")
@@ -766,10 +765,9 @@ class ConfigurationFile:
self.confirm_data_exists("pki_req_ext_data")
else:
# External CA (Step 2)
- self.confirm_data_exists("pki_external_ca_cert_chain_path")
- self.confirm_file_exists("pki_external_ca_cert_chain_path")
- self.confirm_data_exists("pki_external_ca_cert_path")
- self.confirm_file_exists("pki_external_ca_cert_path")
+ # The pki_external_ca_cert_chain_path and
+ # pki_external_ca_cert_path are optional.
+ pass
elif not self.skip_configuration and self.standalone:
if not self.external_step_two:
# Stand-alone PKI Admin CSR (Step 1)
@@ -3813,17 +3811,7 @@ class ConfigClient:
if not isinstance(certs, list):
certs = [certs]
for cdata in certs:
- if (self.subsystem == "CA" and self.external and
- not self.external_step_two):
- # External CA (Step 1)
- if cdata['tag'].lower() == "signing":
- # Save 'External CA Signing Certificate' CSR (Step 1)
- self.save_system_csr(
- cdata['request'],
- log.PKI_CONFIG_EXTERNAL_CSR_SAVE,
- self.mdict['pki_external_csr_path'])
- return
- elif self.standalone and not self.external_step_two:
+ if self.standalone and not self.external_step_two:
# Stand-alone PKI (Step 1)
if cdata['tag'].lower() == "audit_signing":
# Save Stand-alone PKI 'Audit Signing Certificate' CSR
@@ -3991,8 +3979,17 @@ class ConfigClient:
data.token = self.mdict['pki_token_name']
data.tokenPassword = self.mdict['pki_token_password']
data.subsystemName = self.mdict['pki_subsystem_name']
+
+ data.external = self.external
data.standAlone = self.standalone
- data.stepTwo = self.external_step_two
+
+ if self.standalone:
+ # standalone installation uses two-step process (ticket #1698)
+ data.stepTwo = self.external_step_two
+
+ else:
+ # other installations use only one step in the configuration servlet
+ data.stepTwo = False
# Cloning parameters
if self.mdict['pki_instance_type'] == "Tomcat":
@@ -4122,25 +4119,46 @@ class ConfigClient:
self.mdict['pki_req_ext_critical']
cert1.req_ext_data = \
self.mdict['pki_req_ext_data']
- if self.external_step_two:
- # External CA (Step 2) or Stand-alone PKI (Step 2)
- if not self.subsystem == "CA":
- # Stand-alone PKI (Step 2)
- cert1 = pki.system.SystemCertData()
- cert1.tag = self.mdict['pki_ca_signing_tag']
- # Load the External CA or Stand-alone PKI
+
+ if self.external and self.external_step_two: # external/existing CA step 2
+
+ # If specified, load the externally-signed CA cert
+ if self.mdict['pki_external_ca_cert_path']:
+ self.load_system_cert(
+ cert1,
+ log.PKI_CONFIG_EXTERNAL_CA_LOAD,
+ self.mdict['pki_external_ca_cert_path'])
+
+ # If specified, load the external CA cert chain
+ if self.mdict['pki_external_ca_cert_chain_path']:
+ self.load_system_cert_chain(
+ cert1,
+ log.PKI_CONFIG_EXTERNAL_CA_CHAIN_LOAD,
+ self.mdict['pki_external_ca_cert_chain_path'])
+
+ systemCerts.append(cert1)
+
+ elif self.standalone and self.external_step_two: # standalone KRA/OCSP step 2
+
+ cert1 = pki.system.SystemCertData()
+ cert1.tag = self.mdict['pki_ca_signing_tag']
+
+ # Load the stand-alone PKI
# 'External CA Signing Certificate' (Step 2)
self.load_system_cert(
cert1,
log.PKI_CONFIG_EXTERNAL_CA_LOAD,
self.mdict['pki_external_ca_cert_path'])
- # Load the External CA or Stand-alone PKI
+
+ # Load the stand-alone PKI
# 'External CA Signing Certificate Chain' (Step 2)
self.load_system_cert_chain(
cert1,
log.PKI_CONFIG_EXTERNAL_CA_CHAIN_LOAD,
self.mdict['pki_external_ca_cert_chain_path'])
+
systemCerts.append(cert1)
+
elif self.subsystem == "CA":
# PKI CA or Subordinate CA
systemCerts.append(cert1)
diff --git a/base/server/python/pki/server/deployment/scriptlets/configuration.py b/base/server/python/pki/server/deployment/scriptlets/configuration.py
index c6e890235..b8b8fc691 100644
--- a/base/server/python/pki/server/deployment/scriptlets/configuration.py
+++ b/base/server/python/pki/server/deployment/scriptlets/configuration.py
@@ -21,13 +21,18 @@
from __future__ import absolute_import
import json
+import re
# PKI Deployment Imports
from .. import pkiconfig as config
from .. import pkimessages as log
from .. import pkiscriptlet
-import pki.system
+
import pki.encoder
+import pki.nss
+import pki.server
+import pki.system
+import pki.util
# PKI Deployment Configuration Scriptlet
@@ -81,6 +86,127 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
deployer.mdict['pki_client_secmod_database'],
password_file=deployer.mdict['pki_client_password_conf'])
+ instance = pki.server.PKIInstance(deployer.mdict['pki_instance_name'])
+ instance.load()
+
+ subsystem = instance.get_subsystem(deployer.mdict['pki_subsystem'].lower())
+
+ token = deployer.mdict['pki_token_name']
+ nssdb = instance.open_nssdb(token)
+
+ external = config.str2bool(deployer.mdict['pki_external'])
+ step_one = not config.str2bool(deployer.mdict['pki_external_step_two'])
+ step_two = not step_one
+
+ try:
+ if external and step_one: # external/existing CA step 1
+
+ key_type = deployer.mdict['pki_ca_signing_key_type']
+ key_alg = deployer.mdict['pki_ca_signing_key_algorithm']
+
+ if key_type == 'rsa':
+ key_size = int(deployer.mdict['pki_ca_signing_key_size'])
+ curve = None
+
+ m = re.match(r'(.*)withRSA', key_alg)
+ if not m:
+ raise Exception('Invalid key algorithm: %s' % key_alg)
+ hash_alg = m.group(1)
+
+ elif key_type == 'ec' or key_type == 'ecc':
+ key_type = 'ec'
+ key_size = None
+ curve = deployer.mdict['pki_ca_signing_key_size']
+
+ m = re.match(r'(.*)withEC', key_alg)
+ if not m:
+ raise Exception('Invalid key algorithm: %s' % key_alg)
+ hash_alg = m.group(1)
+
+ else:
+ raise Exception('Invalid key type: %s' % key_type)
+
+ # If filename specified, generate CA cert request and
+ # import it into CS.cfg.
+ request_file = deployer.mdict['pki_external_csr_path']
+ if request_file:
+ nssdb.create_request(
+ subject_dn=deployer.mdict['pki_ca_signing_subject_dn'],
+ request_file=request_file,
+ key_type=key_type,
+ key_size=key_size,
+ curve=curve,
+ hash_alg=hash_alg)
+ with open(request_file) as f:
+ signing_csr = f.read()
+ signing_csr = pki.nss.convert_csr(signing_csr, 'pem', 'base64')
+ subsystem.config['ca.signing.certreq'] = signing_csr
+
+ subsystem.save()
+
+ elif external and step_two: # external/existing CA step 2
+
+ # If specified, import existing CA cert request into CS.cfg.
+ request_file = deployer.mdict['pki_external_csr_path']
+ if request_file:
+ with open(request_file) as f:
+ signing_csr = f.read()
+ signing_csr = pki.nss.convert_csr(signing_csr, 'pem', 'base64')
+ subsystem.config['ca.signing.certreq'] = signing_csr
+
+ # If specified, import external CA cert into NSS database.
+ external_ca_cert_chain_nickname = deployer.mdict['pki_external_ca_cert_chain_nickname']
+ external_ca_cert_chain_file = deployer.mdict['pki_external_ca_cert_chain_path']
+ if external_ca_cert_chain_file:
+ cert_chain = nssdb.import_cert_chain(
+ nickname=external_ca_cert_chain_nickname,
+ cert_chain_file=external_ca_cert_chain_file,
+ trust_attributes='CT,C,C')
+ subsystem.config['ca.external_ca_chain.cert'] = cert_chain
+
+ # If specified, import externally-signed CA cert into NSS database.
+ signing_nickname = deployer.mdict['pki_ca_signing_nickname']
+ signing_cert_file = deployer.mdict['pki_external_ca_cert_path']
+ if signing_cert_file:
+ nssdb.add_cert(
+ nickname=signing_nickname,
+ cert_file=signing_cert_file,
+ trust_attributes='CT,C,C')
+
+ # If specified, import CA cert and key from PKCS #12 file into NSS database.
+ pkcs12_file = deployer.mdict['pki_external_pkcs12_path']
+ if pkcs12_file:
+ pkcs12_password = deployer.mdict['pki_external_pkcs12_password']
+ nssdb.import_pkcs12(pkcs12_file, pkcs12_password)
+
+ # Export CA cert from NSS database and import it into CS.cfg.
+ signing_cert_data = nssdb.get_cert(
+ nickname=signing_nickname,
+ output_format='base64')
+ subsystem.config['ca.signing.nickname'] = signing_nickname
+ subsystem.config['ca.signing.tokenname'] = deployer.mdict['pki_ca_signing_token']
+ subsystem.config['ca.signing.cert'] = signing_cert_data
+ subsystem.config['ca.signing.cacertnickname'] = signing_nickname
+ subsystem.config['ca.signing.defaultSigningAlgorithm'] = deployer.mdict['pki_ca_signing_signing_algorithm']
+
+ subsystem.save()
+
+ else: # self-signed CA
+
+ # To be implemented in ticket #1692.
+
+ # Generate CA cert request.
+ # Self sign CA cert.
+ # Import self-signed CA cert into NSS database.
+
+ pass
+
+ finally:
+ nssdb.close()
+
+ if external and step_one:
+ return self.rv
+
# Start/Restart this Tomcat PKI Process
# Optionally prepare to enable a java debugger
# (e. g. - 'eclipse'):
diff --git a/base/server/python/pki/server/deployment/scriptlets/finalization.py b/base/server/python/pki/server/deployment/scriptlets/finalization.py
index 56ddf0219..3c4f469ac 100644
--- a/base/server/python/pki/server/deployment/scriptlets/finalization.py
+++ b/base/server/python/pki/server/deployment/scriptlets/finalization.py
@@ -67,9 +67,15 @@ class PkiScriptlet(pkiscriptlet.AbstractBasePkiScriptlet):
if len(deployer.instance.tomcat_instance_subsystems()) == 1:
# Modify contents of 'serverCertNick.conf' (if necessary)
deployer.servercertnick_conf.modify()
- # Optionally, programmatically 'restart' the configured PKI instance
- if config.str2bool(deployer.mdict['pki_restart_configured_instance']):
- deployer.systemd.restart()
+
+ external = config.str2bool(deployer.mdict['pki_external'])
+ step_one = not config.str2bool(deployer.mdict['pki_external_step_two'])
+
+ if not (external and step_one):
+ # Optionally, programmatically 'restart' the configured PKI instance
+ if config.str2bool(deployer.mdict['pki_restart_configured_instance']):
+ deployer.systemd.restart()
+
# Optionally, 'purge' the entire temporary client infrastructure
# including the client NSS security databases and password files
#