Skip to content

Commit

Permalink
Remove CSR from CS.cfg and store them in certs folder
Browse files Browse the repository at this point in the history
CSR are created and stored in `<instance_config>/certs` folder as `<certs_id>.csr` files.

Fix #2111
  • Loading branch information
fmarco76 committed Oct 16, 2023
1 parent 2402ae9 commit 436f01b
Show file tree
Hide file tree
Showing 7 changed files with 141 additions and 46 deletions.
64 changes: 42 additions & 22 deletions base/server/python/pki/server/deployment/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1391,15 +1391,15 @@ def import_master_config(self, subsystem):
continue

# check CSR in CS.cfg
param = '%s.%s.certreq' % (subsystem.name, tag)
csr = subsystem.config.get(param)
cert_id = self.get_cert_id(subsystem, tag)
param = 'pki_%s_csr_path' % cert_id

if csr:
if self.mdict.get(param):
# CSR already exists
continue

# CSR doesn't exist, import from master
names.append(param)
# CSR doesn't provided, import from master
names.append('%s.%s.certreq' % (subsystem.name, tag))

if subsystem.name == 'ca':
substores.append('ca.connector.KRA')
Expand Down Expand Up @@ -1429,10 +1429,26 @@ def import_master_config(self, subsystem):

logger.info('Importing %s master config params', subsystem.type)

subsystem.import_master_config(master_properties)
requests = {key: val for key, val in master_properties.items() if key.endswith('.certreq')}
for key, value in requests.items():
self.store_master_cert_request(subsystem, key, value)
master_properties.pop(key)

subsystem.import_master_config(master_properties)
return master_config

def store_master_cert_request(self, subsystem, key, csr):

nickname = subsystem.config.get(key.replace('.certreq', '.nickname'))

csr_path = os.path.join(self.instance.conf_dir, 'certs', nickname + '.csr')
try:
self.file.create(csr_path)
with open(csr_path, 'w', encoding='utf-8') as f:
f.write(pki.nssdb.convert_csr(csr, 'base64', 'pem'))
except OSError:
logger.debug('Certificate request %s not stored', key)

def setup_database(self, subsystem, master_config):

if config.str2bool(self.mdict['pki_ds_remove_data']):
Expand Down Expand Up @@ -1904,6 +1920,7 @@ def import_system_cert_request(self, subsystem, tag):
cert_id = self.get_cert_id(subsystem, tag)
param = 'pki_%s_csr_path' % cert_id
csr_path = self.mdict.get(param)
certs_folder = os.path.join(self.instance.conf_dir, 'certs')

if not csr_path:
# no CSR file to import
Expand All @@ -1914,11 +1931,11 @@ def import_system_cert_request(self, subsystem, tag):
if not os.path.exists(csr_path):
raise Exception('Invalid path in %s: %s' % (param, csr_path))

with open(csr_path, encoding='utf-8') as f:
csr_data = f.read()

b64_csr = pki.nssdb.convert_csr(csr_data, 'pem', 'base64')
subsystem.config['%s.%s.certreq' % (subsystem.name, tag)] = b64_csr
cert_nickname = subsystem.config.get('%s.%s.nickname' % (subsystem.name, tag))
self.file.copy(
old_name=csr_path,
new_name=os.path.join(certs_folder, cert_nickname + '.csr'),
overwrite_flag=True)

def import_system_cert_requests(self, subsystem):

Expand All @@ -1938,7 +1955,6 @@ def import_system_cert_requests(self, subsystem):
self.import_system_cert_request(subsystem, 'sslserver')

def import_ca_signing_cert(self, nssdb):

param = 'pki_ca_signing_cert_path'
cert_file = self.mdict.get(param)

Expand Down Expand Up @@ -2710,12 +2726,17 @@ def create_cert_setup_request(self, subsystem, tag, cert):
request.systemCert.keyAlgorithm = subsystem.config['preop.cert.%s.keyalgorithm' % tag]

request.systemCert.requestType = 'pkcs10'
request.systemCert.request = subsystem.config.get('%s.%s.certreq' % (subsystem.name, tag))
try:
csr_path = os.path.join(self.instance.conf_dir, 'certs', cert.get('nickname') + '.csr')
with open(csr_path, 'r', encoding='utf-8') as f:
csr_data = f.read()
request.systemCert.request = pki.nssdb.convert_csr(csr_data, 'pem', 'base64')

request.systemCert.cert = cert.get('data')
except FileNotFoundError:
logger.debug('Certificate request for %s not provided', tag)

request.systemCert.cert = cert.get('data')
request.systemCert.profile = subsystem.config['preop.cert.%s.profile' % tag]

request.systemCert.req_ext_oid = subsystem.config.get('preop.cert.%s.ext.oid' % tag)
request.systemCert.req_ext_data = subsystem.config.get('preop.cert.%s.ext.data' % tag)
request.systemCert.req_ext_critical = subsystem.config.get(
Expand Down Expand Up @@ -2835,7 +2856,7 @@ def generate_csr(self,

logger.debug('generate_csr: calling PKCS10Client for %s', cert_id)

b64_csr = nssdb.create_request_with_wrapping_key(
nssdb.create_request_with_wrapping_key(
subject_dn=subject_dn,
request_file=csr_path,
key_size=key_size)
Expand All @@ -2858,14 +2879,13 @@ def generate_csr(self,
generic_exts=generic_exts,
use_jss=True)

with open(csr_pathname, encoding='utf-8') as f:
csr = f.read()

b64_csr = pki.nssdb.convert_csr(csr, 'pem', 'base64')

shutil.move(csr_pathname, csr_path)

subsystem.config['%s.%s.certreq' % (subsystem.name, tag)] = b64_csr
certs_folder = os.path.join(self.instance.conf_dir, 'certs')
self.file.copy(
old_name=csr_path,
new_name=os.path.join(certs_folder, cert_id + '.csr'),
overwrite_flag=True)

def create_cert_request(self, nssdb, tag, request):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,28 +71,9 @@ def spawn(self, deployer):

deployer.update_sslserver_cert_nickname(subsystem)

if len(subsystems) > 1:
if len(subsystems) == 1:

for s in subsystems:

# find a subsystem that is already installed
if s.name == subsystem.name:
continue

# import request data from the existing subsystem
# into the new subsystem being installed

logger.info('Importing sslserver request data from %s', s.type)
subsystem.config['%s.sslserver.certreq' % subsystem.name] = \
s.config['%s.sslserver.certreq' % s.name]

logger.info('Importing subsystem request data from %s', s.type)
subsystem.config['%s.subsystem.certreq' % subsystem.name] = \
s.config['%s.subsystem.certreq' % s.name]

break

else: # self-signed CA
# self-signed CA

# To be implemented in ticket #1692.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ def spawn(self, deployer):
instance.conf_dir,
conf_link)

# Create /etc/pki/<instance>/certs
certs_path = os.path.join(instance.conf_dir, 'certs')
deployer.directory.create(certs_path)

# Link /var/lib/pki/<instance>/logs to /var/log/pki/<instance>
logs_link = os.path.join(instance.base_dir, 'logs')
deployer.symlink.create(
Expand Down
9 changes: 6 additions & 3 deletions base/server/python/pki/server/subsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,6 @@ def get_cert_info(self, tag):
cert['id'] = tag
cert['nickname'] = self.config.get('%s.%s.nickname' % (self.name, tag))
cert['token'] = self.config.get('%s.%s.tokenname' % (self.name, tag))
cert['data'] = self.config.get('%s.%s.cert' % (self.name, tag))
cert['request'] = self.config.get('%s.%s.certreq' % (self.name, tag))
cert['certusage'] = self.config.get('%s.cert.%s.certusage' % (self.name, tag))

return cert
Expand All @@ -330,7 +328,12 @@ def update_system_cert(self, cert):
cert_id = cert['id']
self.config['%s.%s.nickname' % (self.name, cert_id)] = cert.get('nickname')
self.config['%s.%s.tokenname' % (self.name, cert_id)] = cert.get('token')
self.config['%s.%s.certreq' % (self.name, cert_id)] = cert.get('request')
certs_path = os.path.join(self.instance.conf_dir, 'certs')
if not os.path.isdir(certs_path):
os.mkdir(certs_path)
csr_file = os.path.join(certs_path, cert.get('nickname') + '.csr')
with open(csr_file, "w", encoding='utf-8') as f:
f.write(pki.nssdb.convert_csr(cert.get('request'), 'base64', 'pem'))

def validate_system_cert(self, tag):

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package com.netscape.cms.servlet.csadmin;

import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.Locale;
import java.util.StringTokenizer;
Expand All @@ -27,6 +30,7 @@

import org.dogtagpki.server.authentication.AuthToken;
import org.dogtagpki.server.authorization.AuthzToken;
import org.dogtagpki.util.cert.CertUtil;
import org.w3c.dom.Node;

import com.netscape.certsrv.authorization.EAuthzAccessDenied;
Expand Down Expand Up @@ -159,6 +163,8 @@ protected void process(CMSRequest cmsReq) throws EBaseException {
} else if (name.equals("internaldb.replication.password")) {
value = getReplicationPassword();

} else if (name.endsWith(".certreq")) {
value = getCSR(name);
} else {
value = config.getString(name, null);
if ("localhost".equals(value))
Expand Down Expand Up @@ -218,4 +224,27 @@ private String getReplicationPassword() throws EBaseException {
return pwdStore.getPassword("replicationdb", 0);
}

/**
* @author Marco Fargetta
* @deprecated <subsystem_name>.<cert_id>,certreq configuration properties will be removed in future versions..
*/
@Deprecated (since = "11.5.0")
private String getCSR(String param) throws EBaseException {
CMSEngine engine = getCMSEngine();
EngineConfig config = engine.getConfig();
String csr = null;

String nickname = config.getString(param.replace(".certreq", ".nickname"), null);
if (nickname == null || nickname.isEmpty()) {
return null;
}
Path csrConfCertsPath = FileSystems.getDefault().getPath(CMS.getInstanceDir(), "conf", "certs", nickname + ".csr");
try {
csr = Files.readString(csrConfCertsPath);
} catch (IOException e) {
logger.warn("GetConfigEntries: impossible to access the csr file" + csrConfCertsPath, e);
return null;
}
return CertUtil.unwrapPKCS10(csr, true);
}
}
52 changes: 52 additions & 0 deletions base/server/upgrade/11.5.0/04-RemoveCertCSRfromConfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Authors:
# Marco Fargetta <[email protected]>
#
# Copyright Red Hat, Inc.
#
# SPDX-License-Identifier: GPL-2.0-or-later

import logging
import os

import pki

logger = logging.getLogger(__name__)


class RemoveCertCSRfromConfig(pki.server.upgrade.PKIServerUpgradeScriptlet):

def __init__(self):
super().__init__()
self.message = 'Removes certs data and CSR from CS.cfg'

def upgrade_subsystem(self, instance, subsystem):

self.backup(subsystem.cs_conf)
certs_path = os.path.join(instance.conf_dir, 'certs')
if not os.path.isdir(certs_path):
os.mkdir(certs_path)

logger.info('Removing certs data')
if subsystem.name == 'ca':
self.clean_cert_csr('signing', subsystem, certs_path)
self.clean_cert_csr('ocsp_signing', subsystem, certs_path)
if subsystem.name == 'kra':
self.clean_cert_csr('storage', subsystem, certs_path)
self.clean_cert_csr('transport', subsystem, certs_path)
if subsystem.name == 'ocsp':
self.clean_cert_csr('signing', subsystem, certs_path)

self.clean_cert_csr('sslserver', subsystem, certs_path)
self.clean_cert_csr('subsystem', subsystem, certs_path)
self.clean_cert_csr('audit_signing', subsystem, certs_path)

subsystem.save()

def clean_cert_csr(self, tag, subsystem, dest_path):
subsystem.config.pop('%s.%s.cert' % (subsystem.name, tag), None)
cert_req = subsystem.config.pop('%s.%s.certreq' % (subsystem.name, tag), None)
nickname = subsystem.config.get('%s.%s.nickname' % (subsystem.name, tag))
if cert_req:
csr_data = pki.nssdb.convert_csr(cert_req, 'base64', 'pem')
with open(os.path.join(dest_path, nickname + '.csr'), 'w', encoding='utf-8') as f:
f.write(csr_data)
6 changes: 6 additions & 0 deletions docs/changes/v11.5.0/Server-Changes.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ A new `pki_ds_url` parameter has been added for `pkispawn` to replace the follow
A new `pki_http_enable` parameter has been added for `pkispawn`
to enable/disable the plain HTTP connector in `server.xml`.
The default value is `True`.

== Remove cert and CSR from _CS.cfg_ ==

The parameters `<subsystem_name>.<cert_id>.cert` and `<subsystem_name>.<cert_id>.certreq` are removed from `CS.cfg` files.
Certificates are retrieved from the nssdb configured and they are not stored in other places.
CSR are stored in the folder `<instance_config>/certs` as `<cert_nickname>.csr` and they are retrieved from this location.

0 comments on commit 436f01b

Please sign in to comment.