Simplify NSSDatabase password file handling

https://fedorahosted.org/freeipa/ticket/5959

Signed-off-by: Simo Sorce <simo@redhat.com>
Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Simo Sorce 2016-12-22 14:24:21 -05:00 committed by Jan Cholasta
parent d124e307f3
commit f648c5631a
6 changed files with 33 additions and 47 deletions

View File

@ -97,6 +97,7 @@ class NSSDatabase(object):
else: else:
self.secdir = nssdir self.secdir = nssdir
self._is_temporary = False self._is_temporary = False
self.pwd_file = os.path.join(self.secdir, 'pwdfile.txt')
def close(self): def close(self):
if self._is_temporary: if self._is_temporary:
@ -145,7 +146,7 @@ class NSSDatabase(object):
os.makedirs(self.secdir, dirmode) os.makedirs(self.secdir, dirmode)
if password_filename is None: if password_filename is None:
password_filename = os.path.join(self.secdir, 'pwdfile.txt') password_filename = self.pwd_file
if not os.path.exists(password_filename): if not os.path.exists(password_filename):
# Create the password file for this db # Create the password file for this db
@ -218,12 +219,11 @@ class NSSDatabase(object):
return root_nicknames return root_nicknames
def export_pkcs12(self, nickname, pkcs12_filename, db_password_filename, def export_pkcs12(self, nickname, pkcs12_filename, pkcs12_passwd=None):
pkcs12_passwd=None):
args = [PK12UTIL, "-d", self.secdir, args = [PK12UTIL, "-d", self.secdir,
"-o", pkcs12_filename, "-o", pkcs12_filename,
"-n", nickname, "-n", nickname,
"-k", db_password_filename] "-k", self.pwd_file]
pkcs12_password_file = None pkcs12_password_file = None
if pkcs12_passwd is not None: if pkcs12_passwd is not None:
pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n') pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n')
@ -243,11 +243,10 @@ class NSSDatabase(object):
if pkcs12_password_file is not None: if pkcs12_password_file is not None:
pkcs12_password_file.close() pkcs12_password_file.close()
def import_pkcs12(self, pkcs12_filename, db_password_filename, def import_pkcs12(self, pkcs12_filename, pkcs12_passwd=None):
pkcs12_passwd=None):
args = [PK12UTIL, "-d", self.secdir, args = [PK12UTIL, "-d", self.secdir,
"-i", pkcs12_filename, "-i", pkcs12_filename,
"-k", db_password_filename, '-v'] "-k", self.pwd_file, '-v']
pkcs12_password_file = None pkcs12_password_file = None
if pkcs12_passwd is not None: if pkcs12_passwd is not None:
pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n') pkcs12_password_file = ipautil.write_tmp_file(pkcs12_passwd + '\n')
@ -267,8 +266,8 @@ class NSSDatabase(object):
if pkcs12_password_file is not None: if pkcs12_password_file is not None:
pkcs12_password_file.close() pkcs12_password_file.close()
def import_files(self, files, db_password_filename, import_keys=False, def import_files(self, files, import_keys=False, key_password=None,
key_password=None, key_nickname=None): key_nickname=None):
""" """
Import certificates and a single private key from multiple files Import certificates and a single private key from multiple files
@ -276,8 +275,6 @@ class NSSDatabase(object):
PKCS#8 and raw private key and PKCS#12 formats. PKCS#8 and raw private key and PKCS#12 formats.
:param files: Names of files to import :param files: Names of files to import
:param db_password_filename: Name of file containing the database
password
:param import_keys: Whether to import private keys :param import_keys: Whether to import private keys
:param key_password: Password to decrypt private keys :param key_password: Password to decrypt private keys
:param key_nickname: Nickname of the private key to import from PKCS#12 :param key_nickname: Nickname of the private key to import from PKCS#12
@ -352,7 +349,7 @@ class NSSDatabase(object):
args = [ args = [
OPENSSL, 'pkcs8', OPENSSL, 'pkcs8',
'-topk8', '-topk8',
'-passout', 'file:' + db_password_filename, '-passout', 'file:' + self.pwd_file,
] ]
if ((label != 'PRIVATE KEY' and key_password) or if ((label != 'PRIVATE KEY' and key_password) or
label == 'ENCRYPTED PRIVATE KEY'): label == 'ENCRYPTED PRIVATE KEY'):
@ -390,8 +387,7 @@ class NSSDatabase(object):
# Try to import the file as PKCS#12 file # Try to import the file as PKCS#12 file
if import_keys: if import_keys:
try: try:
self.import_pkcs12( self.import_pkcs12(filename, key_password)
filename, db_password_filename, key_password)
except RuntimeError: except RuntimeError:
pass pass
else: else:
@ -442,7 +438,7 @@ class NSSDatabase(object):
'-export', '-export',
'-in', in_file.name, '-in', in_file.name,
'-out', out_file.name, '-out', out_file.name,
'-passin', 'file:' + db_password_filename, '-passin', 'file:' + self.pwd_file,
'-passout', 'file:' + out_pwdfile.name, '-passout', 'file:' + out_pwdfile.name,
] ]
try: try:
@ -452,8 +448,7 @@ class NSSDatabase(object):
"No matching certificate found for private key from %s" % "No matching certificate found for private key from %s" %
key_file) key_file)
self.import_pkcs12(out_file.name, db_password_filename, self.import_pkcs12(out_file.name, out_password)
out_password)
def trust_root_cert(self, root_nickname, trust_flags=None): def trust_root_cert(self, root_nickname, trust_flags=None):
if root_nickname[:7] == "Builtin": if root_nickname[:7] == "Builtin":

View File

@ -83,7 +83,6 @@ class CertDB(object):
self.realm = realm self.realm = realm
self.noise_fname = self.secdir + "/noise.txt" self.noise_fname = self.secdir + "/noise.txt"
self.passwd_fname = self.secdir + "/pwdfile.txt"
self.certdb_fname = self.secdir + "/cert8.db" self.certdb_fname = self.secdir + "/cert8.db"
self.keydb_fname = self.secdir + "/key3.db" self.keydb_fname = self.secdir + "/key3.db"
self.secmod_fname = self.secdir + "/secmod.db" self.secmod_fname = self.secdir + "/secmod.db"
@ -119,6 +118,10 @@ class CertDB(object):
ca_subject = ipautil.dn_attribute_property('_ca_subject') ca_subject = ipautil.dn_attribute_property('_ca_subject')
subject_base = ipautil.dn_attribute_property('_subject_base') subject_base = ipautil.dn_attribute_property('_subject_base')
@property
def passwd_fname(self):
return self.nssdb.pwd_file
def __del__(self): def __del__(self):
if self.reqdir is not None: if self.reqdir is not None:
shutil.rmtree(self.reqdir, ignore_errors=True) shutil.rmtree(self.reqdir, ignore_errors=True)
@ -189,7 +192,7 @@ class CertDB(object):
ipautil.backup_file(self.certdb_fname) ipautil.backup_file(self.certdb_fname)
ipautil.backup_file(self.keydb_fname) ipautil.backup_file(self.keydb_fname)
ipautil.backup_file(self.secmod_fname) ipautil.backup_file(self.secmod_fname)
self.nssdb.create_db(self.passwd_fname) self.nssdb.create_db()
self.set_perms(self.passwd_fname, write=True) self.set_perms(self.passwd_fname, write=True)
def list_certs(self): def list_certs(self):
@ -510,7 +513,7 @@ class CertDB(object):
return self.nssdb.find_server_certs() return self.nssdb.find_server_certs()
def import_pkcs12(self, pkcs12_fname, pkcs12_passwd=None): def import_pkcs12(self, pkcs12_fname, pkcs12_passwd=None):
return self.nssdb.import_pkcs12(pkcs12_fname, self.passwd_fname, return self.nssdb.import_pkcs12(pkcs12_fname,
pkcs12_passwd=pkcs12_passwd) pkcs12_passwd=pkcs12_passwd)
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None): def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname=None):

View File

@ -1003,19 +1003,16 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files,
the CA certificate of the CA that issued the server certificate the CA certificate of the CA that issued the server certificate
""" """
with certs.NSSDatabase() as nssdb: with certs.NSSDatabase() as nssdb:
db_password = ipautil.ipa_generate_password() nssdb.create_db()
db_pwdfile = ipautil.write_tmp_file(db_password)
nssdb.create_db(db_pwdfile.name)
try: try:
nssdb.import_files(cert_files, db_pwdfile.name, nssdb.import_files(cert_files, True, key_password, key_nickname)
True, key_password, key_nickname)
except RuntimeError as e: except RuntimeError as e:
raise ScriptError(str(e)) raise ScriptError(str(e))
if ca_cert_files: if ca_cert_files:
try: try:
nssdb.import_files(ca_cert_files, db_pwdfile.name) nssdb.import_files(ca_cert_files)
except RuntimeError as e: except RuntimeError as e:
raise ScriptError(str(e)) raise ScriptError(str(e))
@ -1068,7 +1065,7 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files,
'-o', out_file.name, '-o', out_file.name,
'-n', key_nickname, '-n', key_nickname,
'-d', nssdb.secdir, '-d', nssdb.secdir,
'-k', db_pwdfile.name, '-k', nssdb.pwd_file,
'-w', out_pwdfile.name, '-w', out_pwdfile.name,
] ]
ipautil.run(args) ipautil.run(args)
@ -1143,12 +1140,10 @@ def load_external_cert(files, ca_subject):
with the external CA certificate chain with the external CA certificate chain
""" """
with certs.NSSDatabase() as nssdb: with certs.NSSDatabase() as nssdb:
db_password = ipautil.ipa_generate_password() nssdb.create_db()
db_pwdfile = ipautil.write_tmp_file(db_password)
nssdb.create_db(db_pwdfile.name)
try: try:
nssdb.import_files(files, db_pwdfile.name) nssdb.import_files(files)
except RuntimeError as e: except RuntimeError as e:
raise ScriptError(str(e)) raise ScriptError(str(e))

View File

@ -25,7 +25,7 @@ import optparse # pylint: disable=deprecated-module
from ipaplatform.constants import constants from ipaplatform.constants import constants
from ipaplatform.paths import paths from ipaplatform.paths import paths
from ipapython import admintool, ipautil from ipapython import admintool
from ipapython.certdb import get_ca_nickname, NSSDatabase from ipapython.certdb import get_ca_nickname, NSSDatabase
from ipapython.dn import DN from ipapython.dn import DN
from ipalib import api, errors from ipalib import api, errors
@ -164,14 +164,11 @@ class ServerCertInstall(admintool.AdminTool):
def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb): def check_chain(self, pkcs12_filename, pkcs12_pin, nssdb):
# create a temp nssdb # create a temp nssdb
with NSSDatabase() as tempnssdb: with NSSDatabase() as tempnssdb:
db_password = ipautil.ipa_generate_password() tempnssdb.create_db()
db_pwdfile = ipautil.write_tmp_file(db_password)
tempnssdb.create_db(db_pwdfile.name)
# import the PKCS12 file, then delete all CA certificates # import the PKCS12 file, then delete all CA certificates
# this leaves only the server certs in the temp db # this leaves only the server certs in the temp db
tempnssdb.import_pkcs12( tempnssdb.import_pkcs12(pkcs12_filename, pkcs12_pin)
pkcs12_filename, db_pwdfile.name, pkcs12_pin)
for nickname, flags in tempnssdb.list_certs(): for nickname, flags in tempnssdb.list_certs():
if 'u' not in flags: if 'u' not in flags:
while tempnssdb.has_nickname(nickname): while tempnssdb.has_nickname(nickname):

View File

@ -54,9 +54,8 @@ def install_check(api, replica_config, options):
return return
with certdb.NSSDatabase() as tmpdb: with certdb.NSSDatabase() as tmpdb:
pw = ipautil.write_tmp_file(ipautil.ipa_generate_password()) tmpdb.create_db()
tmpdb.create_db(pw.name) tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12",
tmpdb.import_pkcs12(replica_config.dir + "/cacert.p12", pw.name,
replica_config.dirman_password) replica_config.dirman_password)
kra_cert_nicknames = [ kra_cert_nicknames = [
"storageCert cert-pki-kra", "transportCert cert-pki-kra", "storageCert cert-pki-kra", "transportCert cert-pki-kra",

View File

@ -37,8 +37,7 @@ class update_ra_cert_store(Updater):
return False, [] return False, []
else: else:
# Create the DB # Create the DB
newdb.create_db(os.path.join(paths.IPA_RADB_DIR, 'pwdfile.txt'), newdb.create_db(user=constants.HTTPD_USER,
user=constants.HTTPD_USER,
group=constants.HTTPD_GROUP, group=constants.HTTPD_GROUP,
mode=0o751, backup=True) mode=0o751, backup=True)
@ -58,18 +57,16 @@ class update_ra_cert_store(Updater):
"chain: {}".format(name, str(e))) "chain: {}".format(name, str(e)))
# As the last step export/import/delete the RA Cert # As the last step export/import/delete the RA Cert
ipa_httpd_pwdfile = os.path.join(paths.HTTPD_ALIAS_DIR, 'pwdfile.txt')
ipa_radb_pwdfile = os.path.join(paths.IPA_RADB_DIR, 'pwdfile.txt')
pw = binascii.hexlify(os.urandom(10)) pw = binascii.hexlify(os.urandom(10))
p12file = os.path.join(paths.IPA_RADB_DIR, 'ipaCert.p12') p12file = os.path.join(paths.IPA_RADB_DIR, 'ipaCert.p12')
olddb.export_pkcs12('ipaCert', p12file, ipa_httpd_pwdfile, pw) olddb.export_pkcs12('ipaCert', p12file, pw)
newdb.import_pkcs12(p12file, ipa_radb_pwdfile, pw) newdb.import_pkcs12(p12file, pw)
certmonger.stop_tracking(secdir=olddb.secdir, certmonger.stop_tracking(secdir=olddb.secdir,
nickname='ipaCert') nickname='ipaCert')
certmonger.start_tracking(secdir=newdb.secdir, certmonger.start_tracking(secdir=newdb.secdir,
nickname='ipaCert', nickname='ipaCert',
password_file=ipa_radb_pwdfile) password_file=newdb.pwd_file)
olddb.delete_cert('ipaCert') olddb.delete_cert('ipaCert')