freeipa/ipatests/test_ipapython/test_certdb.py
Stanislav Levin a102cfe5fa nss: Raise exception earlier on unsupported DB type
For now FreeIPA handles explicit migration of NSS DB (dbm->sql).
But Mozilla's NSS can be built without the support of legacy database
(DBM). This implies that neither implicit nor explicit DB migration
to SQL will work. So, eventually, this support will be removed from
FreeIPA.

With this patch, the instantiation of NSS with legacy db(if not
supported by NSS) is forbidden.

Fixes: https://pagure.io/freeipa/issue/8474
Signed-off-by: Stanislav Levin <slev@altlinux.org>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
2020-08-31 09:46:03 +03:00

287 lines
8.8 KiB
Python

from __future__ import absolute_import
import os
import pytest
from ipapython.certdb import (
NSSDatabase,
TRUSTED_PEER_TRUST_FLAGS,
nss_supports_dbm,
)
from ipapython import ipautil
from ipaplatform.osinfo import osinfo
CERTNICK = 'testcert'
CERTSAN = 'testcert.certdb.test'
if osinfo.id == 'fedora':
if osinfo.version_number >= (28,):
NSS_DEFAULT = 'sql'
else:
NSS_DEFAULT = 'dbm'
else:
NSS_DEFAULT = None
def create_selfsigned(nssdb):
# create self-signed cert + key
noisefile = os.path.join(nssdb.secdir, 'noise')
with open(noisefile, 'wb') as f:
f.write(os.urandom(64))
try:
nssdb.run_certutil([
'-S', '-x',
'-z', noisefile,
'-k', 'rsa', '-g', '2048', '-Z', 'SHA256',
'-t', 'CTu,Cu,Cu',
'-s', 'CN=testcert',
'-n', CERTNICK,
'-m', '365',
'--extSAN', f'dns:{CERTSAN}'
])
finally:
os.unlink(noisefile)
@pytest.mark.skipif(
not nss_supports_dbm(),
reason="NSS is built without support of the legacy database(DBM)",
)
def test_dbm_tmp():
with NSSDatabase(dbtype='dbm') as nssdb:
assert nssdb.dbtype == 'dbm'
for filename in nssdb.filenames:
assert not os.path.isfile(filename)
assert not nssdb.exists()
nssdb.create_db()
for filename in nssdb.filenames:
assert os.path.isfile(filename)
assert os.path.dirname(filename) == nssdb.secdir
assert nssdb.exists()
assert os.path.basename(nssdb.certdb) == 'cert8.db'
assert nssdb.certdb in nssdb.filenames
assert os.path.basename(nssdb.keydb) == 'key3.db'
assert os.path.basename(nssdb.secmod) == 'secmod.db'
@pytest.mark.skipif(
nss_supports_dbm(),
reason="NSS is built with support of the legacy database(DBM)",
)
def test_dbm_raise():
with pytest.raises(ValueError) as e:
NSSDatabase(dbtype="dbm")
assert (
str(e.value) == "NSS is built without support of the legacy "
"database(DBM)"
)
def test_sql_tmp():
with NSSDatabase(dbtype='sql') as nssdb:
assert nssdb.dbtype == 'sql'
for filename in nssdb.filenames:
assert not os.path.isfile(filename)
assert not nssdb.exists()
nssdb.create_db()
for filename in nssdb.filenames:
assert os.path.isfile(filename)
assert os.path.dirname(filename) == nssdb.secdir
assert nssdb.exists()
assert os.path.basename(nssdb.certdb) == 'cert9.db'
assert nssdb.certdb in nssdb.filenames
assert os.path.basename(nssdb.keydb) == 'key4.db'
assert os.path.basename(nssdb.secmod) == 'pkcs11.txt'
@pytest.mark.skipif(
not nss_supports_dbm(),
reason="NSS is built without support of the legacy database(DBM)",
)
def test_convert_db():
with NSSDatabase(dbtype='dbm') as nssdb:
assert nssdb.dbtype == 'dbm'
nssdb.create_db()
assert nssdb.exists()
create_selfsigned(nssdb)
oldcerts = nssdb.list_certs()
assert len(oldcerts) == 1
oldkeys = nssdb.list_keys()
assert len(oldkeys) == 1
nssdb.convert_db()
assert nssdb.exists()
assert nssdb.dbtype == 'sql'
newcerts = nssdb.list_certs()
assert len(newcerts) == 1
assert newcerts == oldcerts
newkeys = nssdb.list_keys()
assert len(newkeys) == 1
assert newkeys == oldkeys
for filename in nssdb.filenames:
assert os.path.isfile(filename)
assert os.path.dirname(filename) == nssdb.secdir
assert os.path.basename(nssdb.certdb) == 'cert9.db'
assert nssdb.certdb in nssdb.filenames
assert os.path.basename(nssdb.keydb) == 'key4.db'
assert os.path.basename(nssdb.secmod) == 'pkcs11.txt'
@pytest.mark.skipif(
not nss_supports_dbm(),
reason="NSS is built without support of the legacy database(DBM)",
)
def test_convert_db_nokey():
with NSSDatabase(dbtype='dbm') as nssdb:
assert nssdb.dbtype == 'dbm'
nssdb.create_db()
create_selfsigned(nssdb)
assert len(nssdb.list_certs()) == 1
assert len(nssdb.list_keys()) == 1
# remove key, readd cert
cert = nssdb.get_cert(CERTNICK)
nssdb.run_certutil(['-F', '-n', CERTNICK])
nssdb.add_cert(cert, CERTNICK, TRUSTED_PEER_TRUST_FLAGS)
assert len(nssdb.list_keys()) == 0
oldcerts = nssdb.list_certs()
assert len(oldcerts) == 1
nssdb.convert_db()
assert nssdb.dbtype == 'sql'
newcerts = nssdb.list_certs()
assert len(newcerts) == 1
assert newcerts == oldcerts
assert nssdb.get_cert(CERTNICK) == cert
newkeys = nssdb.list_keys()
assert newkeys == ()
for filename in nssdb.filenames:
assert os.path.isfile(filename)
assert os.path.dirname(filename) == nssdb.secdir
old = os.path.join(nssdb.secdir, 'cert8.db')
assert not os.path.isfile(old)
assert os.path.isfile(old + '.migrated')
assert os.path.basename(nssdb.certdb) == 'cert9.db'
assert nssdb.certdb in nssdb.filenames
assert os.path.basename(nssdb.keydb) == 'key4.db'
assert os.path.basename(nssdb.secmod) == 'pkcs11.txt'
def test_auto_db():
with NSSDatabase() as nssdb:
assert nssdb.dbtype == 'auto'
assert nssdb.filenames is None
assert not nssdb.exists()
with pytest.raises(RuntimeError):
nssdb.list_certs()
nssdb.create_db()
assert nssdb.dbtype in ('dbm', 'sql')
if NSS_DEFAULT is not None:
assert nssdb.dbtype == NSS_DEFAULT
assert nssdb.filenames is not None
assert nssdb.exists()
nssdb.list_certs()
def test_delete_cert_and_key():
"""Test that delete_cert + delete_key always deletes everything
Test with a NSSDB that contains:
- cert + key
- key only
- cert only
- none of them
"""
cmd = ipautil.run(['mktemp'], capture_output=True)
p12file = cmd.output.strip()
try:
with NSSDatabase() as nssdb:
nssdb.create_db()
# 1. Test delete_key_and_cert when cert + key are present
# Create a NSS DB with cert + key
create_selfsigned(nssdb)
# Save both in a p12 file for latter use
ipautil.run(
[
'pk12util',
'-o', p12file, '-n', CERTNICK, '-d', nssdb.secdir,
'-k', nssdb.pwd_file,
'-w', nssdb.pwd_file
])
# Delete cert and key
nssdb.delete_key_and_cert(CERTNICK)
# make sure that everything was deleted
assert len(nssdb.list_keys()) == 0
assert len(nssdb.list_certs()) == 0
# 2. Test delete_key_and_cert when only key is present
# Import cert and key then remove cert
import_args = [
'pk12util',
'-i', p12file, '-d', nssdb.secdir,
'-k', nssdb.pwd_file,
'-w', nssdb.pwd_file]
ipautil.run(import_args)
nssdb.delete_cert(CERTNICK)
# Delete cert and key
nssdb.delete_key_and_cert(CERTNICK)
# make sure that everything was deleted
assert len(nssdb.list_keys()) == 0
assert len(nssdb.list_certs()) == 0
# 3. Test delete_key_and_cert when only cert is present
# Import cert and key then remove key
ipautil.run(import_args)
nssdb.delete_key_only(CERTNICK)
# make sure the db contains only the cert
assert len(nssdb.list_keys()) == 0
assert len(nssdb.list_certs()) == 1
# Delete cert and key when key is not present
nssdb.delete_key_and_cert(CERTNICK)
# make sure that everything was deleted
assert len(nssdb.list_keys()) == 0
assert len(nssdb.list_certs()) == 0
# 4. Test delete_key_and_cert with a wrong nickname
# Import cert and key
ipautil.run(import_args)
# Delete cert and key
nssdb.delete_key_and_cert('wrongnick')
# make sure that nothing was deleted
assert len(nssdb.list_keys()) == 1
assert len(nssdb.list_certs()) == 1
finally:
os.unlink(p12file)
def test_check_validity():
with NSSDatabase() as nssdb:
nssdb.create_db()
create_selfsigned(nssdb)
with pytest.raises(ValueError):
nssdb.verify_ca_cert_validity(CERTNICK)
nssdb.verify_server_cert_validity(CERTNICK, CERTSAN)
with pytest.raises(ValueError):
nssdb.verify_server_cert_validity(CERTNICK, 'invalid.example')