CA replica PKCS12 workaround for SQL NSSDB

CA replica installation fails, because 'caSigningCert cert-pki-ca' is
imported a second time under a different name. The issue is caused
by the fact, that SQL NSS DB handles duplicated certificates differently
than DBM format.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1561730
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Fraser Tweedale <ftweedal@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Christian Heimes 2018-04-17 07:10:48 +02:00
parent 07be3306c1
commit ad2eb3d09b
2 changed files with 35 additions and 34 deletions

View File

@ -84,7 +84,7 @@
%endif %endif
# Require Dogtag PKI 10.6.0 with Python 3 and SQL NSSDB fixes # Require Dogtag PKI 10.6.0 with Python 3 and SQL NSSDB fixes
%global pki_version 10.6.0-0.2 %global pki_version 10.6.0-1
%define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+') %define krb5_base_version %(LC_ALL=C rpm -q --qf '%%{VERSION}' krb5-devel | grep -Eo '^[^.]+\.[^.]+')

View File

@ -4,22 +4,22 @@ from __future__ import print_function, absolute_import
import logging import logging
from ipalib import api
from ipalib.install.certstore import get_ca_certs_nss
from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap
from ipaserver.secrets.client import CustodiaClient from ipaserver.secrets.client import CustodiaClient
from ipaplatform.paths import paths from ipaplatform.paths import paths
from ipaplatform.constants import constants from ipaplatform.constants import constants
from ipaserver.install.service import SimpleServiceInstance from ipaserver.install.service import SimpleServiceInstance
from ipapython import ipautil from ipapython import ipautil
from ipapython.certdb import NSSDatabase from ipapython.certdb import NSSDatabase, get_ca_nickname
from ipaserver.install import installutils from ipaserver.install import installutils
from ipaserver.install import ldapupdate from ipaserver.install import ldapupdate
from ipaserver.install import sysupgrade from ipaserver.install import sysupgrade
from base64 import b64decode from base64 import b64decode
from jwcrypto.common import json_decode from jwcrypto.common import json_decode
import shutil
import os import os
import stat import stat
import tempfile
import time import time
import pwd import pwd
@ -178,54 +178,55 @@ class CustodiaInstance(SimpleServiceInstance):
paths.KRB5_KEYTAB, server, realm=self.realm) paths.KRB5_KEYTAB, server, realm=self.realm)
def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
# Fecth all needed certs one by one, then combine them in a single # Fetch all needed certs one by one, then combine them in a single
# p12 file # PKCS12 file
prefix = data['prefix'] prefix = data['prefix']
certlist = data['list'] certlist = data['list']
cli = self.__CustodiaClient(server=ca_host) cli = self.__CustodiaClient(server=ca_host)
# Temporary nssdb with NSSDatabase(None) as tmpdb:
tmpnssdir = tempfile.mkdtemp(dir=paths.TMP)
tmpdb = NSSDatabase(tmpnssdir)
tmpdb.create_db() tmpdb.create_db()
try:
# Cert file password # Cert file password
crtpwfile = os.path.join(tmpnssdir, 'crtpwfile') crtpwfile = os.path.join(tmpdb.secdir, 'crtpwfile')
with open(crtpwfile, 'w+') as f: with open(crtpwfile, 'w+') as f:
f.write(cacerts_pwd) f.write(cacerts_pwd)
f.flush()
for nickname in certlist: for nickname in certlist:
value = cli.fetch_key(os.path.join(prefix, nickname), False) value = cli.fetch_key(os.path.join(prefix, nickname), False)
v = json_decode(value) v = json_decode(value)
pk12pwfile = os.path.join(tmpnssdir, 'pk12pwfile') pk12pwfile = os.path.join(tmpdb.secdir, 'pk12pwfile')
with open(pk12pwfile, 'w+') as f: with open(pk12pwfile, 'w+') as f:
f.write(v['export password']) f.write(v['export password'])
pk12file = os.path.join(tmpnssdir, 'pk12file') pk12file = os.path.join(tmpdb.secdir, 'pk12file')
with open(pk12file, 'wb') as f: with open(pk12file, 'wb') as f:
f.write(b64decode(v['pkcs12 data'])) f.write(b64decode(v['pkcs12 data']))
ipautil.run([paths.PK12UTIL, tmpdb.run_pk12util([
'-d', tmpdb.secdir,
'-k', tmpdb.pwd_file, '-k', tmpdb.pwd_file,
'-n', nickname, '-n', nickname,
'-i', pk12file, '-i', pk12file,
'-w', pk12pwfile]) '-w', pk12pwfile
])
# Add CA certificates # Add CA certificates, but don't import the main CA cert. It's
self.suffix = ipautil.realm_to_suffix(self.realm) # already present as 'caSigningCert cert-pki-ca'. With SQL db
self.export_ca_certs_nssdb(tmpdb, True) # format, a second import would rename the certificate. See
# https://pagure.io/freeipa/issue/7498 for more details.
conn = api.Backend.ldap2
suffix = ipautil.realm_to_suffix(self.realm)
ca_certs = get_ca_certs_nss(conn, suffix, self.realm, True)
for cert, nickname, trust_flags in ca_certs:
if nickname == get_ca_nickname(self.realm):
continue
tmpdb.add_cert(cert, nickname, trust_flags)
# Now that we gathered all certs, re-export # Now that we gathered all certs, re-export
ipautil.run([paths.PKCS12EXPORT, ipautil.run([
paths.PKCS12EXPORT,
'-d', tmpdb.secdir, '-d', tmpdb.secdir,
'-p', tmpdb.pwd_file, '-p', tmpdb.pwd_file,
'-w', crtpwfile, '-w', crtpwfile,
'-o', cacerts_file]) '-o', cacerts_file
])
finally:
shutil.rmtree(tmpnssdir)
def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd): def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd):
certlist = ['caSigningCert cert-pki-ca', certlist = ['caSigningCert cert-pki-ca',