diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index 336839b71..dddefea0b 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -215,6 +215,7 @@ class BasePathNamespace(object): NTPD = "/usr/sbin/ntpd" PKIDESTROY = "/usr/sbin/pkidestroy" PKISPAWN = "/usr/sbin/pkispawn" + PKI = "/usr/bin/pki" REMOVE_DS_PL = "/usr/sbin/remove-ds.pl" RESTORECON = "/usr/sbin/restorecon" SELINUXENABLED = "/usr/sbin/selinuxenabled" diff --git a/ipapython/secrets/store.py b/ipapython/secrets/store.py index 26dcc4688..095da7d1f 100644 --- a/ipapython/secrets/store.py +++ b/ipapython/secrets/store.py @@ -51,6 +51,56 @@ def HTTPD_password_callback(): return password +class NSSWrappedCertDB(DBMAPHandler): + ''' + Store that extracts private keys from an NSSDB, wrapped with the + private key of the primary CA. + ''' + + def __init__(self, config, dbmap, nickname): + if 'path' not in dbmap: + raise ValueError( + 'Configuration does not provide NSSDB path') + if 'pwcallback' not in dbmap: + raise ValueError( + 'Configuration does not provide Password Calback') + if 'wrap_nick' not in dbmap: + raise ValueError( + 'Configuration does not provide nickname of wrapping key') + self.nssdb_path = dbmap['path'] + self.nssdb_password = dbmap['pwcallback']() + self.wrap_nick = dbmap['wrap_nick'] + self.target_nick = nickname + + def export_key(self): + tdir = tempfile.mkdtemp(dir=paths.TMP) + try: + nsspwfile = os.path.join(tdir, 'nsspwfile') + with open(nsspwfile, 'w+') as f: + f.write(self.nssdb_password) + wrapped_key_file = os.path.join(tdir, 'wrapped_key') + certificate_file = os.path.join(tdir, 'certificate') + ipautil.run([ + paths.PKI, '-d', self.nssdb_path, '-C', nsspwfile, + 'ca-authority-key-export', + '--wrap-nickname', self.wrap_nick, + '--target-nickname', self.target_nick, + '-o', wrapped_key_file]) + ipautil.run([ + paths.CERTUTIL, '-d', self.nssdb_path, + '-L', '-n', self.target_nick, + '-a', '-o', certificate_file]) + with open(wrapped_key_file, 'r') as f: + wrapped_key = f.read() + with open(certificate_file, 'r') as f: + certificate = f.read() + finally: + shutil.rmtree(tdir) + return json_encode({ + 'wrapped_key': b64encode(wrapped_key), + 'certificate': certificate}) + + class NSSCertDB(DBMAPHandler): def __init__(self, config, dbmap, nickname): @@ -148,6 +198,12 @@ NAME_DB_MAP = { 'handler': NSSCertDB, 'pwcallback': PKI_TOMCAT_password_callback, }, + 'ca_wrapped': { + 'handler': NSSWrappedCertDB, + 'path': paths.PKI_TOMCAT_ALIAS_DIR, + 'pwcallback': PKI_TOMCAT_password_callback, + 'wrap_nick': 'caSigningCert cert-pki-ca', + }, 'ra': { 'type': 'NSSDB', 'path': paths.HTTPD_ALIAS_DIR,