From ad2eb3d09b8336008d7f04c3d134c707530d9eb6 Mon Sep 17 00:00:00 2001 From: Christian Heimes Date: Tue, 17 Apr 2018 07:10:48 +0200 Subject: [PATCH] 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 Reviewed-By: Fraser Tweedale Reviewed-By: Rob Crittenden Reviewed-By: Alexander Bokovoy --- freeipa.spec.in | 2 +- ipaserver/install/custodiainstance.py | 67 ++++++++++++++------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index 41cd59ea8..873a054ec 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -84,7 +84,7 @@ %endif # 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 '^[^.]+\.[^.]+') diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py index 20cc26ef2..1eb195ce0 100644 --- a/ipaserver/install/custodiainstance.py +++ b/ipaserver/install/custodiainstance.py @@ -4,22 +4,22 @@ from __future__ import print_function, absolute_import 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.client import CustodiaClient from ipaplatform.paths import paths from ipaplatform.constants import constants from ipaserver.install.service import SimpleServiceInstance 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 ldapupdate from ipaserver.install import sysupgrade from base64 import b64decode from jwcrypto.common import json_decode -import shutil import os import stat -import tempfile import time import pwd @@ -178,54 +178,55 @@ class CustodiaInstance(SimpleServiceInstance): paths.KRB5_KEYTAB, server, realm=self.realm) def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data): - # Fecth all needed certs one by one, then combine them in a single - # p12 file - + # Fetch all needed certs one by one, then combine them in a single + # PKCS12 file prefix = data['prefix'] certlist = data['list'] - cli = self.__CustodiaClient(server=ca_host) - # Temporary nssdb - tmpnssdir = tempfile.mkdtemp(dir=paths.TMP) - tmpdb = NSSDatabase(tmpnssdir) - tmpdb.create_db() - try: + with NSSDatabase(None) as tmpdb: + tmpdb.create_db() # Cert file password - crtpwfile = os.path.join(tmpnssdir, 'crtpwfile') + crtpwfile = os.path.join(tmpdb.secdir, 'crtpwfile') with open(crtpwfile, 'w+') as f: f.write(cacerts_pwd) - f.flush() for nickname in certlist: value = cli.fetch_key(os.path.join(prefix, nickname), False) v = json_decode(value) - pk12pwfile = os.path.join(tmpnssdir, 'pk12pwfile') + pk12pwfile = os.path.join(tmpdb.secdir, 'pk12pwfile') with open(pk12pwfile, 'w+') as f: f.write(v['export password']) - pk12file = os.path.join(tmpnssdir, 'pk12file') + pk12file = os.path.join(tmpdb.secdir, 'pk12file') with open(pk12file, 'wb') as f: f.write(b64decode(v['pkcs12 data'])) - ipautil.run([paths.PK12UTIL, - '-d', tmpdb.secdir, - '-k', tmpdb.pwd_file, - '-n', nickname, - '-i', pk12file, - '-w', pk12pwfile]) + tmpdb.run_pk12util([ + '-k', tmpdb.pwd_file, + '-n', nickname, + '-i', pk12file, + '-w', pk12pwfile + ]) - # Add CA certificates - self.suffix = ipautil.realm_to_suffix(self.realm) - self.export_ca_certs_nssdb(tmpdb, True) + # Add CA certificates, but don't import the main CA cert. It's + # already present as 'caSigningCert cert-pki-ca'. With SQL db + # 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 - ipautil.run([paths.PKCS12EXPORT, - '-d', tmpdb.secdir, - '-p', tmpdb.pwd_file, - '-w', crtpwfile, - '-o', cacerts_file]) - - finally: - shutil.rmtree(tmpnssdir) + ipautil.run([ + paths.PKCS12EXPORT, + '-d', tmpdb.secdir, + '-p', tmpdb.pwd_file, + '-w', crtpwfile, + '-o', cacerts_file + ]) def get_ca_keys(self, ca_host, cacerts_file, cacerts_pwd): certlist = ['caSigningCert cert-pki-ca',