summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFraser Tweedale <ftweedal@redhat.com>2016-10-13 17:12:31 +1000
committerDavid Kupka <dkupka@redhat.com>2016-11-10 10:21:47 +0100
commitdb116f73fe5fc199bb2e28103cf5e3e2a24eab4c (patch)
treeff1a043b376ec4d98b6399040a868e8b45725ee0
parentc57dc890b2bf447ab575f2e91249179bce3f05d5 (diff)
downloadfreeipa-db116f73fe5fc199bb2e28103cf5e3e2a24eab4c.tar.gz
freeipa-db116f73fe5fc199bb2e28103cf5e3e2a24eab4c.tar.xz
freeipa-db116f73fe5fc199bb2e28103cf5e3e2a24eab4c.zip
x509: use python-cryptography to process certs
Update x509.load_certificate and related functions to return python-cryptography ``Certificate`` objects. Update the call sites accordingly, including removal of NSS initialisation code. Also update GeneralName parsing code to return python-cryptography GeneralName values, for consistency with other code that processes GeneralNames. The new function, `get_san_general_names`, and associated helper functions, can be removed when python-cryptography provides a way to deal with unrecognised critical extensions. Part of: https://fedorahosted.org/freeipa/ticket/6398 Reviewed-By: Jan Cholasta <jcholast@redhat.com> Reviewed-By: Florence Blanc-Renaud <frenaud@redhat.com>
-rwxr-xr-xclient/ipa-client-install27
-rwxr-xr-xinstall/tools/ipa-replica-conncheck15
-rw-r--r--ipalib/certstore.py12
-rw-r--r--ipalib/x509.py327
-rw-r--r--ipapython/certdb.py17
-rw-r--r--ipaserver/install/ca.py2
-rw-r--r--ipaserver/install/cainstance.py25
-rw-r--r--ipaserver/install/certs.py9
-rw-r--r--ipaserver/install/installutils.py14
-rw-r--r--ipaserver/install/ipa_cacert_manage.py103
-rw-r--r--ipaserver/install/krainstance.py2
-rw-r--r--ipaserver/plugins/cert.py115
-rw-r--r--ipaserver/plugins/service.py20
-rw-r--r--ipatests/test_ipalib/test_x509.py66
-rw-r--r--ipatests/test_ipaserver/test_ldap.py8
-rw-r--r--ipatests/test_ipaserver/test_otptoken_import.py4
16 files changed, 369 insertions, 397 deletions
diff --git a/client/ipa-client-install b/client/ipa-client-install
index 639810b62..c228ea3ce 100755
--- a/client/ipa-client-install
+++ b/client/ipa-client-install
@@ -35,9 +35,9 @@ try:
import gssapi
import netifaces
- import nss.nss as nss
import SSSDConfig
from six.moves.urllib.parse import urlparse, urlunparse
+ from cryptography.hazmat.primitives import serialization
from ipapython.ipa_log_manager import standard_logging_setup, root_logger
from ipaclient import ipadiscovery
@@ -92,15 +92,10 @@ def parse_options():
if not os.path.isabs(value):
raise OptionValueError("%s option '%s' is not an absolute file path" % (opt, value))
- initialized = nss.nss_is_initialized()
try:
- cert = x509.load_certificate_from_file(value)
+ x509.load_certificate_from_file(value)
except Exception:
raise OptionValueError("%s option '%s' is not a valid certificate file" % (opt, value))
- else:
- del(cert)
- if not initialized:
- nss.nss_shutdown()
parser.values.ca_cert_file = value
@@ -300,10 +295,10 @@ def cert_summary(msg, certs, indent=' '):
else:
s = ''
for cert in certs:
- s += '%sSubject: %s\n' % (indent, cert.subject)
- s += '%sIssuer: %s\n' % (indent, cert.issuer)
- s += '%sValid From: %s\n' % (indent, cert.valid_not_before_str)
- s += '%sValid Until: %s\n' % (indent, cert.valid_not_after_str)
+ s += '%sSubject: %s\n' % (indent, DN(cert.subject))
+ s += '%sIssuer: %s\n' % (indent, DN(cert.issuer))
+ s += '%sValid From: %s\n' % (indent, cert.not_valid_before)
+ s += '%sValid Until: %s\n' % (indent, cert.not_valid_after)
s += '\n'
s = s[:-1]
@@ -2148,7 +2143,10 @@ def get_ca_certs(fstore, options, server, basedn, realm):
if ca_certs is not None:
try:
- ca_certs = [cert.der_data for cert in ca_certs]
+ ca_certs = [
+ cert.public_bytes(serialization.Encoding.DER)
+ for cert in ca_certs
+ ]
x509.write_certificate_list(ca_certs, ca_file)
except Exception as e:
if os.path.exists(ca_file):
@@ -2815,7 +2813,10 @@ def install(options, env, fstore, statestore):
# Add CA certs to a temporary NSS database
ca_certs = x509.load_certificate_list_from_file(CACERT)
- ca_certs = [cert.der_data for cert in ca_certs]
+ ca_certs = [
+ cert.public_bytes(serialization.Encoding.DER)
+ for cert in ca_certs
+ ]
try:
pwd_file = ipautil.write_tmp_file(ipautil.ipa_generate_password())
tmp_db.create_db(pwd_file.name)
diff --git a/install/tools/ipa-replica-conncheck b/install/tools/ipa-replica-conncheck
index 067afb7b0..4045e41df 100755
--- a/install/tools/ipa-replica-conncheck
+++ b/install/tools/ipa-replica-conncheck
@@ -21,6 +21,7 @@
from __future__ import print_function
from ipapython.config import IPAOptionParser
+from ipapython.dn import DN
from ipapython import version
from ipapython import ipautil, certdb
from ipalib import api, errors, x509
@@ -40,7 +41,7 @@ from socket import SOCK_STREAM, SOCK_DGRAM
import distutils.spawn
from ipaplatform.paths import paths
import gssapi
-from nss import nss
+from cryptography.hazmat.primitives import serialization
CONNECT_TIMEOUT = 5
RESPONDERS = [ ]
@@ -121,16 +122,12 @@ def parse_options():
raise OptionValueError(
"%s option '%s' is not an absolute file path" % (opt, value))
- initialized = nss.nss_is_initialized()
try:
x509.load_certificate_list_from_file(value)
except Exception:
raise OptionValueError(
"%s option '%s' is not a valid certificate file" %
(opt, value))
- finally:
- if not initialized:
- nss.nss_shutdown()
parser.values.ca_cert_file = value
@@ -472,12 +469,12 @@ def main():
nss_db.create_db(password_file.name)
ca_certs = x509.load_certificate_list_from_file(
- options.ca_cert_file, dbdir=nss_db.secdir)
+ options.ca_cert_file)
for ca_cert in ca_certs:
+ data = ca_cert.public_bytes(
+ serialization.Encoding.DER)
nss_db.add_cert(
- ca_cert.der_data, str(ca_cert.subject), 'C,,')
- del ca_cert
- del ca_certs
+ data, str(DN(ca_cert.subject)), 'C,,')
else:
nss_dir = None
diff --git a/ipalib/certstore.py b/ipalib/certstore.py
index d17cb2baa..70ae94210 100644
--- a/ipalib/certstore.py
+++ b/ipalib/certstore.py
@@ -22,7 +22,6 @@
LDAP shared certificate store.
"""
-from nss.error import NSPRError
from pyasn1.error import PyAsn1Error
from ipapython.dn import DN
@@ -31,11 +30,12 @@ from ipalib import errors, x509
def _parse_cert(dercert):
try:
- subject = x509.get_subject(dercert, x509.DER)
- issuer = x509.get_issuer(dercert, x509.DER)
- serial_number = x509.get_serial_number(dercert, x509.DER)
+ cert = x509.load_certificate(dercert, x509.DER)
+ subject = DN(cert.subject)
+ issuer = DN(cert.issuer)
+ serial_number = cert.serial
public_key_info = x509.get_der_public_key_info(dercert, x509.DER)
- except (NSPRError, PyAsn1Error) as e:
+ except (ValueError, PyAsn1Error) as e:
raise ValueError("failed to decode certificate: %s" % e)
subject = str(subject).replace('\\;', '\\3b')
@@ -54,7 +54,7 @@ def init_ca_entry(entry, dercert, nickname, trusted, ext_key_usage):
if ext_key_usage is not None:
try:
cert_eku = x509.get_ext_key_usage(dercert, x509.DER)
- except NSPRError as e:
+ except ValueError as e:
raise ValueError("failed to decode certificate: %s" % e)
if cert_eku is not None:
cert_eku -= {x509.EKU_SERVER_AUTH, x509.EKU_CLIENT_AUTH,
diff --git a/ipalib/x509.py b/ipalib/x509.py
index a807d1270..7f7a89c31 100644
--- a/ipalib/x509.py
+++ b/ipalib/x509.py
@@ -28,31 +28,27 @@
#
# cert: the certificate is a PEM-encoded certificate
# dercert: the certificate is DER-encoded
-# nsscert: the certificate is an NSS Certificate object
# rawcert: the cert is in an unknown format
from __future__ import print_function
import binascii
-import collections
-import os
+import datetime
+import ipaddress
import sys
import base64
import re
+from cryptography.hazmat.backends import default_backend
import cryptography.x509
-import nss.nss as nss
-from nss.error import NSPRError
from pyasn1.type import univ, char, namedtype, tag
from pyasn1.codec.der import decoder, encoder
from pyasn1_modules import rfc2459
import six
from ipalib import api
-from ipalib import _
from ipalib import util
from ipalib import errors
-from ipaplatform.paths import paths
from ipapython.dn import DN
if six.PY3:
@@ -95,32 +91,16 @@ def strip_header(pem):
return pem
-def initialize_nss_database(dbdir=None):
- """
- Initializes NSS database, if not initialized yet. Uses a proper database
- directory (.ipa/alias or HTTPD_ALIAS_DIR), depending on the value of
- api.env.in_tree.
- """
- if not nss.nss_is_initialized():
- if dbdir is None:
- if 'in_tree' in api.env:
- if api.env.in_tree:
- dbdir = api.env.dot_ipa + os.sep + 'alias'
- else:
- dbdir = paths.HTTPD_ALIAS_DIR
- nss.nss_init(dbdir)
- else:
- nss.nss_init_nodb()
- else:
- nss.nss_init(dbdir)
-
-def load_certificate(data, datatype=PEM, dbdir=None):
+def load_certificate(data, datatype=PEM):
"""
- Given a base64-encoded certificate, with or without the
- header/footer, return a request object.
+ Load an X.509 certificate.
+
+ :param datatype: PEM for base64-encoded data (with or without header),
+ or DER
+ :return: a python-cryptography ``CertificateSigningRequest`` object.
+ :raises: ``ValueError`` if unable to load the certificate.
- Returns a nss.Certificate type
"""
if type(data) in (tuple, list):
data = data[0]
@@ -129,82 +109,50 @@ def load_certificate(data, datatype=PEM, dbdir=None):
data = strip_header(data)
data = base64.b64decode(data)
- initialize_nss_database(dbdir=dbdir)
+ return cryptography.x509.load_der_x509_certificate(data, default_backend())
- if six.PY2:
- return nss.Certificate(buffer(data)) # pylint: disable=buffer-builtin
- else:
- # In python 3 , `bytes` has the buffer interface
- return nss.Certificate(data)
def load_certificate_from_file(filename, dbdir=None):
"""
Load a certificate from a PEM file.
- Returns a nss.Certificate type
- """
- fd = open(filename, 'r')
- data = fd.read()
- fd.close()
-
- return load_certificate(data, PEM, dbdir)
-
-def load_certificate_list(data, dbdir=None):
- certs = PEM_REGEX.findall(data)
- certs = [load_certificate(cert, PEM, dbdir) for cert in certs]
- return certs
+ Returns a python-cryptography ``Certificate`` object.
-def load_certificate_list_from_file(filename, dbdir=None):
"""
- Load a certificate list from a PEM file.
+ with open(filename, mode='rb') as f:
+ return load_certificate(f.read(), PEM)
+
- Returns a list of nss.Certificate objects.
+def load_certificate_list(data):
"""
- fd = open(filename, 'r')
- data = fd.read()
- fd.close()
+ Load a certificate list from a sequence of concatenated PEMs.
- return load_certificate_list(data, dbdir)
+ Return a list of python-cryptography ``Certificate`` objects.
-def get_subject(certificate, datatype=PEM, dbdir=None):
- """
- Load an X509.3 certificate and get the subject.
"""
+ certs = PEM_REGEX.findall(data)
+ certs = [load_certificate(cert, PEM) for cert in certs]
+ return certs
- nsscert = load_certificate(certificate, datatype, dbdir)
- subject = nsscert.subject
- del(nsscert)
- return subject
-def get_issuer(certificate, datatype=PEM, dbdir=None):
- """
- Load an X509.3 certificate and get the issuer.
+def load_certificate_list_from_file(filename):
"""
+ Load a certificate list from a PEM file.
- nsscert = load_certificate(certificate, datatype, dbdir)
- issuer = nsscert.issuer
- del(nsscert)
- return issuer
+ Return a list of python-cryptography ``Certificate`` objects.
-def get_serial_number(certificate, datatype=PEM, dbdir=None):
"""
- Return the decimal value of the serial number.
- """
- nsscert = load_certificate(certificate, datatype, dbdir)
- serial_number = nsscert.serial_number
- del(nsscert)
- return serial_number
+ with open(filename) as f:
+ return load_certificate_list(f.read())
+
-def is_self_signed(certificate, datatype=PEM, dbdir=None):
- nsscert = load_certificate(certificate, datatype, dbdir)
- self_signed = (nsscert.issuer == nsscert.subject)
- del nsscert
- return self_signed
+def is_self_signed(certificate, datatype=PEM):
+ cert = load_certificate(certificate, datatype)
+ return cert.issuer == cert.subject
def _get_der_field(cert, datatype, dbdir, field):
- cert = load_certificate(cert, datatype, dbdir)
- cert = cert.der_data
+ cert = normalize_certificate(cert)
cert = decoder.decode(cert, rfc2459.Certificate())[0]
field = cert['tbsCertificate'][field]
field = encoder.encode(field)
@@ -222,20 +170,17 @@ def get_der_serial_number(cert, datatype=PEM, dbdir=None):
def get_der_public_key_info(cert, datatype=PEM, dbdir=None):
return _get_der_field(cert, datatype, dbdir, 'subjectPublicKeyInfo')
-def get_ext_key_usage(certificate, datatype=PEM, dbdir=None):
- nsscert = load_certificate(certificate, datatype, dbdir)
- if not nsscert.extensions:
- return None
- for ext in nsscert.extensions:
- if ext.oid_tag == nss.SEC_OID_X509_EXT_KEY_USAGE:
- break
- else:
+def get_ext_key_usage(certificate, datatype=PEM):
+ cert = load_certificate(certificate, datatype)
+ try:
+ eku = cert.extensions.get_extension_for_oid(
+ cryptography.x509.oid.ExtensionOID.EXTENDED_KEY_USAGE).value
+ except cryptography.x509.ExtensionNotFound:
return None
- eku = nss.x509_ext_key_usage(ext.value, nss.AsDottedDecimal)
- eku = set(o[4:] for o in eku)
- return eku
+ return set(oid.dotted_string for oid in eku)
+
def make_pem(data):
"""
@@ -270,27 +215,21 @@ def normalize_certificate(rawcert):
else:
dercert = rawcert
- # At this point we should have a certificate, either because the data
- # was base64-encoded and now its not or it came in as DER format.
- # Let's decode it and see. Fetching the serial number will pass the
- # certificate through the NSS DER parser.
+ # At this point we should have a DER certificate.
+ # Attempt to decode it.
validate_certificate(dercert, datatype=DER)
return dercert
-def validate_certificate(cert, datatype=PEM, dbdir=None):
+def validate_certificate(cert, datatype=PEM):
"""
- Perform certificate validation by trying to load it into NSS database
+ Perform cert validation by trying to load it via python-cryptography.
"""
try:
- load_certificate(cert, datatype=datatype, dbdir=dbdir)
- except NSPRError as nsprerr:
- if nsprerr.errno == -8183: # SEC_ERROR_BAD_DER
- raise errors.CertificateFormatError(
- error=_('improperly formatted DER-encoded certificate'))
- else:
- raise errors.CertificateFormatError(error=str(nsprerr))
+ load_certificate(cert, datatype=datatype)
+ except ValueError as e:
+ raise errors.CertificateFormatError(error=str(e))
def write_certificate(rawcert, filename):
@@ -379,56 +318,6 @@ def _decode_krb5principalname(data):
return name
-GeneralNameInfo = collections.namedtuple(
- 'GeneralNameInfo', ('type', 'desc', 'value', 'der_value'))
-
-
-def decode_generalnames(secitem):
- """
- Decode a GeneralNames object (this the data for the Subject
- Alt Name and Issuer Alt Name extensions, among others).
-
- ``secitem``
- The input is the DER-encoded extension data, without the
- OCTET STRING header, as an nss SecItem object.
-
- Return a list of ``GeneralNameInfo`` namedtuples. The
- ``der_value`` field is set for otherNames, otherwise it is
- ``None``.
-
- """
- nss_names = nss.x509_alt_name(secitem, repr_kind=nss.AsObject)
- asn1_names = decoder.decode(
- secitem.data, asn1Spec=rfc2459.SubjectAltName())[0]
- names = []
- for nss_name, asn1_name in zip(nss_names, asn1_names):
- # NOTE: we use the NSS enum to identify the name type.
- # (For otherName we also tuple it up with the type-id OID).
- # The enum does not correspond exactly to the ASN.1 tags.
- # If we ever want to switch to using the true tag numbers,
- # the expression to get the tag is:
- #
- # asn1_name.getComponent().getTagSet()[0].asTuple()[2]
- #
- if nss_name.type_enum == nss.certOtherName:
- oid = str(asn1_name['otherName']['type-id'])
- nametype = (nss_name.type_enum, oid)
- der_value = asn1_name['otherName']['value'].asOctets()
- else:
- nametype = nss_name.type_enum
- der_value = None
-
- if nametype == (nss.certOtherName, SAN_KRB5PRINCIPALNAME):
- name = _decode_krb5principalname(asn1_name['otherName']['value'])
- else:
- name = nss_name.name
-
- gni = GeneralNameInfo(nametype, nss_name.type_string, name, der_value)
- names.append(gni)
-
- return names
-
-
class KRB5PrincipalName(cryptography.x509.general_name.OtherName):
def __init__(self, type_id, value):
super(KRB5PrincipalName, self).__init__(type_id, value)
@@ -464,6 +353,100 @@ def process_othernames(gns):
yield gn
+def get_san_general_names(cert):
+ """
+ Return SAN general names from a python-cryptography
+ certificate object. If the SAN extension is not present,
+ return an empty sequence.
+
+ Because python-cryptography does not yet provide a way to
+ handle unrecognised critical extensions (which may occur),
+ we must parse the certificate and extract the General Names.
+ For uniformity with other code, we manually construct values
+ of python-crytography GeneralName subtypes.
+
+ python-cryptography does not yet provide types for
+ ediPartyName or x400Address, so we drop these name types.
+
+ otherNames are NOT instantiated to more specific types where
+ the type is known. Use ``process_othernames`` to do that.
+
+ When python-cryptography can handle certs with unrecognised
+ critical extensions and implements ediPartyName and
+ x400Address, this function (and helpers) will be redundant
+ and should go away.
+
+ """
+ tbs = decoder.decode(
+ cert.tbs_certificate_bytes,
+ asn1Spec=rfc2459.TBSCertificate()
+ )[0]
+ OID_SAN = univ.ObjectIdentifier('2.5.29.17')
+ gns = []
+ for ext in tbs['extensions']:
+ if ext['extnID'] == OID_SAN:
+ der = decoder.decode(
+ ext['extnValue'], asn1Spec=univ.OctetString())[0]
+ gns = decoder.decode(der, asn1Spec=rfc2459.SubjectAltName())[0]
+ break
+
+ GENERAL_NAME_CONSTRUCTORS = {
+ 'rfc822Name': lambda x: cryptography.x509.RFC822Name(unicode(x)),
+ 'dNSName': lambda x: cryptography.x509.DNSName(unicode(x)),
+ 'directoryName': _pyasn1_to_cryptography_directoryname,
+ 'registeredID': _pyasn1_to_cryptography_registeredid,
+ 'iPAddress': _pyasn1_to_cryptography_ipaddress,
+ 'uniformResourceIdentifier':
+ lambda x: cryptography.x509.UniformResourceIdentifier(unicode(x)),
+ 'otherName': _pyasn1_to_cryptography_othername,
+ }
+
+ result = []
+
+ for gn in gns:
+ gn_type = gn.getName()
+ if gn_type in GENERAL_NAME_CONSTRUCTORS:
+ result.append(
+ GENERAL_NAME_CONSTRUCTORS[gn_type](gn.getComponent()))
+
+ return result
+
+
+def _pyasn1_to_cryptography_directoryname(dn):
+ attrs = []
+
+ # Name is CHOICE { RDNSequence } (only one possibility)
+ for rdn in dn.getComponent():
+ for ava in rdn:
+ attr = cryptography.x509.NameAttribute(
+ _pyasn1_to_cryptography_oid(ava['type']),
+ unicode(decoder.decode(ava['value'])[0])
+ )
+ attrs.append(attr)
+
+ return cryptography.x509.DirectoryName(cryptography.x509.Name(attrs))
+
+
+def _pyasn1_to_cryptography_registeredid(oid):
+ return cryptography.x509.RegisteredID(_pyasn1_to_cryptography_oid(oid))
+
+
+def _pyasn1_to_cryptography_ipaddress(octet_string):
+ return cryptography.x509.IPAddress(
+ ipaddress.ip_address(bytes(octet_string)))
+
+
+def _pyasn1_to_cryptography_othername(on):
+ return cryptography.x509.OtherName(
+ _pyasn1_to_cryptography_oid(on['type-id']),
+ bytes(on['value'])
+ )
+
+
+def _pyasn1_to_cryptography_oid(oid):
+ return cryptography.x509.ObjectIdentifier(str(oid))
+
+
def chunk(size, s):
"""Yield chunks of the specified size from the given string.
@@ -486,20 +469,34 @@ def to_hex_with_colons(bs):
return add_colons(binascii.hexlify(bs).decode('utf-8'))
+class UTC(datetime.tzinfo):
+ ZERO = datetime.timedelta(0)
+
+ def tzname(self, dt):
+ return "UTC"
+
+ def utcoffset(self, dt):
+ return self.ZERO
+
+ def dst(self, dt):
+ return self.ZERO
+
+
+def format_datetime(t):
+ if t.tzinfo is None:
+ t = t.replace(tzinfo=UTC())
+ return unicode(t.strftime("%a %b %d %H:%M:%S %Y %Z"))
+
+
if __name__ == '__main__':
# this can be run with:
# python ipalib/x509.py < /etc/ipa/ca.crt
- api.bootstrap()
- api.finalize()
-
- nss.nss_init_nodb()
-
- # Read PEM certs from stdin and print out its components
+ # Read PEM cert from stdin and print out its components
certlines = sys.stdin.readlines()
cert = ''.join(certlines)
- nsscert = load_certificate(cert)
+ cert = load_certificate(cert)
- print(nsscert)
+ print(cert)
diff --git a/ipapython/certdb.py b/ipapython/certdb.py
index 06666c022..c2fe599a2 100644
--- a/ipapython/certdb.py
+++ b/ipapython/certdb.py
@@ -22,10 +22,12 @@ import re
import tempfile
import shutil
import base64
+from cryptography.hazmat.primitives import serialization
from nss import nss
from nss.error import NSPRError
from ipaplatform.paths import paths
+from ipapython.dn import DN
from ipapython.ipa_log_manager import root_logger
from ipapython import ipautil
from ipalib import x509
@@ -258,7 +260,7 @@ class NSSDatabase(object):
'X.509 CERTIFICATE'):
try:
x509.load_certificate(match.group(2))
- except NSPRError as e:
+ except ValueError as e:
if label != 'CERTIFICATE':
root_logger.warning(
"Skipping certificate in %s at line %s: %s",
@@ -334,7 +336,7 @@ class NSSDatabase(object):
# Try to load the file as DER certificate
try:
x509.load_certificate(data, x509.DER)
- except NSPRError:
+ except ValueError:
pass
else:
data = x509.make_pem(base64.b64encode(data))
@@ -379,12 +381,11 @@ class NSSDatabase(object):
raise RuntimeError(
"No server certificates found in %s" % (', '.join(files)))
- nss_certs = x509.load_certificate_list(extracted_certs)
- nss_cert = None
- for nss_cert in nss_certs:
- nickname = str(nss_cert.subject)
- self.add_cert(nss_cert.der_data, nickname, ',,')
- del nss_certs, nss_cert
+ certs = x509.load_certificate_list(extracted_certs)
+ for cert in certs:
+ nickname = str(DN(cert.subject))
+ data = cert.public_bytes(serialization.Encoding.DER)
+ self.add_cert(data, nickname, ',,')
if extracted_key:
in_file = ipautil.write_tmp_file(extracted_certs + extracted_key)
diff --git a/ipaserver/install/ca.py b/ipaserver/install/ca.py
index 88ec6277f..921e49495 100644
--- a/ipaserver/install/ca.py
+++ b/ipaserver/install/ca.py
@@ -102,7 +102,7 @@ def install_check(standalone, replica_config, options):
cert = db.get_cert_from_db(nickname)
if not cert:
continue
- subject = DN(str(x509.get_subject(cert)))
+ subject = DN(x509.load_certificate(cert).subject)
if subject in (DN('CN=Certificate Authority', subject_base),
DN('CN=IPA RA', subject_base)):
raise ScriptError(
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index 1b7acef70..7b26e749e 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -554,9 +554,9 @@ class CAInstance(DogtagInstance):
config.set("CA", "pki_req_ext_data", "1E0A00530075006200430041")
elif self.external == 2:
- cert = x509.load_certificate_from_file(self.cert_file)
cert_file = tempfile.NamedTemporaryFile()
- x509.write_certificate(cert.der_data, cert_file.name)
+ with open(self.cert_file) as f:
+ x509.write_certificate(f.read(), cert_file.name)
cert_file.flush()
result = ipautil.run(
@@ -778,7 +778,7 @@ class CAInstance(DogtagInstance):
userstate=["1"],
userCertificate=[cert_data],
description=['2;%s;%s;%s' % (
- cert.serial_number,
+ cert.serial,
DN(('CN', 'Certificate Authority'), self.subject_base),
DN(('CN', 'IPA RA'), self.subject_base))])
conn.add_entry(entry)
@@ -1674,8 +1674,9 @@ def update_people_entry(dercert):
is needed when a certificate is renewed.
"""
def make_filter(dercert):
- subject = x509.get_subject(dercert, datatype=x509.DER)
- issuer = x509.get_issuer(dercert, datatype=x509.DER)
+ cert = x509.load_certificate(dercert, datatype=x509.DER)
+ subject = DN(cert.subject)
+ issuer = DN(cert.issuer)
return ldap2.ldap2.combine_filters(
[
ldap2.ldap2.make_filter({'objectClass': 'inetOrgPerson'}),
@@ -1686,9 +1687,10 @@ def update_people_entry(dercert):
ldap2.ldap2.MATCH_ALL)
def make_entry(dercert, entry):
- serial_number = x509.get_serial_number(dercert, datatype=x509.DER)
- subject = x509.get_subject(dercert, datatype=x509.DER)
- issuer = x509.get_issuer(dercert, datatype=x509.DER)
+ cert = x509.load_certificate(dercert, datatype=x509.DER)
+ serial_number = cert.serial
+ subject = DN(cert.subject)
+ issuer = DN(cert.issuer)
entry['usercertificate'].append(dercert)
entry['description'] = '2;%d;%s;%s' % (serial_number, issuer, subject)
return entry
@@ -1702,15 +1704,16 @@ def update_authority_entry(dercert):
serial number to match the given cert.
"""
def make_filter(dercert):
- subject = x509.get_subject(dercert, datatype=x509.DER)
+ cert = x509.load_certificate(dercert, datatype=x509.DER)
+ subject = str(DN(cert.subject))
return ldap2.ldap2.make_filter(
dict(objectclass='authority', authoritydn=subject),
rules=ldap2.ldap2.MATCH_ALL,
)
def make_entry(dercert, entry):
- serial_number = x509.get_serial_number(dercert, datatype=x509.DER)
- entry['authoritySerial'] = serial_number
+ cert = x509.load_certificate(dercert, datatype=x509.DER)
+ entry['authoritySerial'] = cert.serial
return entry
return __update_entry_from_cert(make_filter, make_entry, dercert)
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index 31fd36cc3..a73025099 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -60,9 +60,8 @@ def get_cert_nickname(cert):
representation of the first RDN in the subject and subject_dn
is a DN object.
"""
- nsscert = x509.load_certificate(cert)
- subject = str(nsscert.subject)
- dn = DN(subject)
+ cert_obj = x509.load_certificate(cert)
+ dn = DN(cert_obj.subject)
return (str(dn[0]), dn)
@@ -304,8 +303,8 @@ class CertDB(object):
return
cert = self.get_cert_from_db(nickname)
- nsscert = x509.load_certificate(cert, dbdir=self.secdir)
- subject = str(nsscert.subject)
+ cert_obj = x509.load_certificate(cert)
+ subject = str(DN(cert_obj.subject))
certmonger.add_principal(request_id, principal)
certmonger.add_subject(request_id, subject)
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index fb9579a07..bee501a6e 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -921,10 +921,9 @@ def load_pkcs12(cert_files, key_password, key_nickname, ca_cert_files,
if ca_cert is None:
ca_cert = cert
- nss_cert = x509.load_certificate(cert, x509.DER)
- subject = DN(str(nss_cert.subject))
- issuer = DN(str(nss_cert.issuer))
- del nss_cert
+ cert_obj = x509.load_certificate(cert, x509.DER)
+ subject = DN(cert_obj.subject)
+ issuer = DN(cert_obj.issuer)
if subject == issuer:
break
@@ -1046,10 +1045,9 @@ def load_external_cert(files, subject_base):
for nickname, _trust_flags in nssdb.list_certs():
cert = nssdb.get_cert(nickname, pem=True)
- nss_cert = x509.load_certificate(cert)
- subject = DN(str(nss_cert.subject))
- issuer = DN(str(nss_cert.issuer))
- del nss_cert
+ cert_obj = x509.load_certificate(cert)
+ subject = DN(cert_obj.subject)
+ issuer = DN(cert_obj.issuer)
cache[nickname] = (cert, subject, issuer)
if subject == ca_subject:
diff --git a/ipaserver/install/ipa_cacert_manage.py b/ipaserver/install/ipa_cacert_manage.py
index af08ba68c..0dcb70fea 100644
--- a/ipaserver/install/ipa_cacert_manage.py
+++ b/ipaserver/install/ipa_cacert_manage.py
@@ -21,8 +21,7 @@ from __future__ import print_function
import os
from optparse import OptionGroup
-from nss import nss
-from nss.error import NSPRError
+from cryptography.hazmat.primitives import serialization
import gssapi
from ipapython import admintool, certmonger, ipautil
@@ -187,7 +186,7 @@ class CACertManage(admintool.AdminTool):
"--external-cert-file=/path/to/signed_certificate "
"--external-cert-file=/path/to/external_ca_certificate")
- def renew_external_step_2(self, ca, old_cert):
+ def renew_external_step_2(self, ca, old_cert_der):
print("Importing the renewed CA certificate, please wait")
options = self.options
@@ -195,55 +194,54 @@ class CACertManage(admintool.AdminTool):
cert_file, ca_file = installutils.load_external_cert(
options.external_cert_files, x509.subject_base())
- nss_cert = None
- nss.nss_init(paths.PKI_TOMCAT_ALIAS_DIR)
- try:
- nss_cert = x509.load_certificate(old_cert, x509.DER)
- subject = nss_cert.subject
- der_subject = x509.get_der_subject(old_cert, x509.DER)
- #pylint: disable=E1101
- pkinfo = nss_cert.subject_public_key_info.format()
- #pylint: enable=E1101
-
- nss_cert = x509.load_certificate_from_file(cert_file.name)
- cert = nss_cert.der_data
- if nss_cert.subject != subject:
- raise admintool.ScriptError(
- "Subject name mismatch (visit "
- "http://www.freeipa.org/page/Troubleshooting for "
- "troubleshooting guide)")
- if x509.get_der_subject(cert, x509.DER) != der_subject:
- raise admintool.ScriptError(
- "Subject name encoding mismatch (visit "
- "http://www.freeipa.org/page/Troubleshooting for "
- "troubleshooting guide)")
- #pylint: disable=E1101
- if nss_cert.subject_public_key_info.format() != pkinfo:
- raise admintool.ScriptError(
- "Subject public key info mismatch (visit "
- "http://www.freeipa.org/page/Troubleshooting for "
- "troubleshooting guide)")
- #pylint: enable=E1101
- finally:
- del nss_cert
- nss.nss_shutdown()
+ old_cert_obj = x509.load_certificate(old_cert_der, x509.DER)
+ old_der_subject = x509.get_der_subject(old_cert_der, x509.DER)
+ old_spki = old_cert_obj.public_key().public_bytes(
+ serialization.Encoding.DER,
+ serialization.PublicFormat.SubjectPublicKeyInfo
+ )
+
+ with open(cert_file.name) as f:
+ new_cert_data = f.read()
+ new_cert_der = x509.normalize_certificate(new_cert_data)
+ new_cert_obj = x509.load_certificate(new_cert_der, x509.DER)
+ new_der_subject = x509.get_der_subject(new_cert_der, x509.DER)
+ new_spki = new_cert_obj.public_key().public_bytes(
+ serialization.Encoding.DER,
+ serialization.PublicFormat.SubjectPublicKeyInfo
+ )
+
+ if new_cert_obj.subject != old_cert_obj.subject:
+ raise admintool.ScriptError(
+ "Subject name mismatch (visit "
+ "http://www.freeipa.org/page/Troubleshooting for "
+ "troubleshooting guide)")
+ if new_der_subject != old_der_subject:
+ raise admintool.ScriptError(
+ "Subject name encoding mismatch (visit "
+ "http://www.freeipa.org/page/Troubleshooting for "
+ "troubleshooting guide)")
+ if new_spki != old_spki:
+ raise admintool.ScriptError(
+ "Subject public key info mismatch (visit "
+ "http://www.freeipa.org/page/Troubleshooting for "
+ "troubleshooting guide)")
with certs.NSSDatabase() as tmpdb:
pw = ipautil.write_tmp_file(ipautil.ipa_generate_password())
tmpdb.create_db(pw.name)
- tmpdb.add_cert(old_cert, 'IPA CA', 'C,,')
+ tmpdb.add_cert(old_cert_der, 'IPA CA', 'C,,')
try:
- tmpdb.add_cert(cert, 'IPA CA', 'C,,')
+ tmpdb.add_cert(new_cert_der, 'IPA CA', 'C,,')
except ipautil.CalledProcessError as e:
raise admintool.ScriptError(
"Not compatible with the current CA certificate: %s" % e)
ca_certs = x509.load_certificate_list_from_file(ca_file.name)
for ca_cert in ca_certs:
- tmpdb.add_cert(ca_cert.der_data, str(ca_cert.subject), 'C,,')
- del ca_certs
- del ca_cert
+ data = ca_cert.public_bytes(serialization.Encoding.DER)
+ tmpdb.add_cert(data, str(DN(ca_cert.subject)), 'C,,')
try:
tmpdb.verify_ca_cert_validity('IPA CA')
@@ -266,14 +264,14 @@ class CACertManage(admintool.AdminTool):
('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
try:
entry = conn.get_entry(dn, ['usercertificate'])
- entry['usercertificate'] = [cert]
+ entry['usercertificate'] = [new_cert_der]
conn.update_entry(entry)
except errors.NotFound:
entry = conn.make_entry(
dn,
objectclass=['top', 'pkiuser', 'nscontainer'],
cn=[self.cert_nickname],
- usercertificate=[cert])
+ usercertificate=[new_cert_der])
conn.add_entry(entry)
except errors.EmptyModlist:
pass
@@ -313,21 +311,16 @@ class CACertManage(admintool.AdminTool):
options = self.options
cert_filename = self.args[1]
- nss_cert = None
try:
- try:
- nss_cert = x509.load_certificate_from_file(cert_filename)
- except IOError as e:
- raise admintool.ScriptError(
- "Can't open \"%s\": %s" % (cert_filename, e))
- except (TypeError, NSPRError, ValueError) as e:
- raise admintool.ScriptError("Not a valid certificate: %s" % e)
- subject = nss_cert.subject
- cert = nss_cert.der_data
- finally:
- del nss_cert
+ cert_obj = x509.load_certificate_from_file(cert_filename)
+ except IOError as e:
+ raise admintool.ScriptError(
+ "Can't open \"%s\": %s" % (cert_filename, e))
+ except (TypeError, ValueError) as e:
+ raise admintool.ScriptError("Not a valid certificate: %s" % e)
+ cert = cert_obj.public_bytes(serialization.Encoding.DER)
- nickname = options.nickname or str(subject)
+ nickname = options.nickname or str(DN(cert_obj.subject))
ca_certs = certstore.get_ca_certs_nss(api.Backend.ldap2,
api.env.basedn,
diff --git a/ipaserver/install/krainstance.py b/ipaserver/install/krainstance.py
index 315057808..77f23c1c3 100644
--- a/ipaserver/install/krainstance.py
+++ b/ipaserver/install/krainstance.py
@@ -297,7 +297,7 @@ class KRAInstance(DogtagInstance):
usertype=["undefined"],
userCertificate=[cert_data],
description=['2;%s;%s;%s' % (
- cert.serial_number,
+ cert.serial,
DN(('CN', 'Certificate Authority'), self.subject_base),
DN(('CN', 'IPA RA'), self.subject_base))])
conn.add_entry(entry)
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index a534c4d26..4362d8268 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -22,11 +22,11 @@
import base64
import collections
import datetime
+from operator import attrgetter
import os
import cryptography.x509
-from nss import nss
-from nss.error import NSPRError
+from cryptography.hazmat.primitives import hashes
import six
from ipalib import Command, Str, Int, Flag
@@ -224,7 +224,7 @@ def bind_principal_can_manage_cert(cert):
"""Check that the bind principal can manage the given cert.
``cert``
- An NSS certificate object.
+ A python-cryptography ``Certificate`` object.
"""
bind_principal = kerberos.Principal(getattr(context, 'principal'))
@@ -233,9 +233,14 @@ def bind_principal_can_manage_cert(cert):
hostname = bind_principal.hostname
- # If we have a hostname we want to verify that the subject
- # of the certificate matches it.
- return hostname == cert.subject.common_name #pylint: disable=E1101
+ # Verify that hostname matches subject of cert.
+ # We check the "most-specific" CN value.
+ cns = cert.subject.get_attributes_for_oid(
+ cryptography.x509.oid.NameOID.COMMON_NAME)
+ if len(cns) == 0:
+ return False # no CN in subject
+ else:
+ return hostname == cns[-1].value
class BaseCertObject(Object):
@@ -370,30 +375,27 @@ class BaseCertObject(Object):
attribute.
"""
- cert = obj.get('certificate')
- if cert is not None:
- cert = x509.load_certificate(cert)
- obj['subject'] = DN(unicode(cert.subject))
- obj['issuer'] = DN(unicode(cert.issuer))
- obj['serial_number'] = cert.serial_number
- obj['valid_not_before'] = unicode(cert.valid_not_before_str)
- obj['valid_not_after'] = unicode(cert.valid_not_after_str)
+ if 'certificate' in obj:
+ cert = x509.load_certificate(obj['certificate'])
+ obj['subject'] = DN(cert.subject)
+ obj['issuer'] = DN(cert.issuer)
+ obj['serial_number'] = cert.serial
+ obj['valid_not_before'] = x509.format_datetime(
+ cert.not_valid_before)
+ obj['valid_not_after'] = x509.format_datetime(
+ cert.not_valid_after)
if full:
obj['md5_fingerprint'] = x509.to_hex_with_colons(
- nss.md5_digest(cert.der_data))
+ cert.fingerprint(hashes.MD5()))
obj['sha1_fingerprint'] = x509.to_hex_with_colons(
- nss.sha1_digest(cert.der_data))
+ cert.fingerprint(hashes.SHA1()))
- try:
- ext_san = cert.get_extension(nss.SEC_OID_X509_SUBJECT_ALT_NAME)
- general_names = x509.decode_generalnames(ext_san.value)
- except KeyError:
- general_names = []
+ general_names = x509.process_othernames(
+ x509.get_san_general_names(cert))
- for name_type, _desc, name, der_name in general_names:
+ for gn in general_names:
try:
- self._add_san_attribute(
- obj, full, name_type, name, der_name)
+ self._add_san_attribute(obj, full, gn)
except Exception:
# Invalid GeneralName (i.e. not a valid X.509 cert);
# don't fail but log something about it
@@ -404,45 +406,52 @@ class BaseCertObject(Object):
if serial_number is not None:
obj['serial_number_hex'] = u'0x%X' % serial_number
-
- def _add_san_attribute(
- self, obj, full, name_type, name, der_name):
+ def _add_san_attribute(self, obj, full, gn):
name_type_map = {
- nss.certRFC822Name: 'san_rfc822name',
- nss.certDNSName: 'san_dnsname',
- nss.certX400Address: 'san_x400address',
- nss.certDirectoryName: 'san_directoryname',
- nss.certEDIPartyName: 'san_edipartyname',
- nss.certURI: 'san_uri',
- nss.certIPAddress: 'san_ipaddress',
- nss.certRegisterID: 'san_oid',
- (nss.certOtherName, x509.SAN_UPN): 'san_other_upn',
- (nss.certOtherName, x509.SAN_KRB5PRINCIPALNAME): 'san_other_kpn',
+ cryptography.x509.RFC822Name:
+ ('san_rfc822name', attrgetter('value')),
+ cryptography.x509.DNSName: ('san_dnsname', attrgetter('value')),
+ # cryptography.x509.???: 'san_x400address',
+ cryptography.x509.DirectoryName:
+ ('san_directoryname', lambda x: DN(x.value)),
+ # cryptography.x509.???: 'san_edipartyname',
+ cryptography.x509.UniformResourceIdentifier:
+ ('san_uri', attrgetter('value')),
+ cryptography.x509.IPAddress:
+ ('san_ipaddress', attrgetter('value')),
+ cryptography.x509.RegisteredID:
+ ('san_oid', attrgetter('value.dotted_string')),
+ cryptography.x509.OtherName: ('san_other', _format_othername),
+ x509.UPN: ('san_other_upn', attrgetter('name')),
+ x509.KRB5PrincipalName: ('san_other_kpn', attrgetter('name')),
}
default_attrs = {
'san_rfc822name', 'san_dnsname', 'san_other_upn', 'san_other_kpn',
}
- attr_name = name_type_map.get(name_type, 'san_other')
+ if type(gn) not in name_type_map:
+ return
+
+ attr_name, format_name = name_type_map[type(gn)]
if full or attr_name in default_attrs:
- if attr_name != 'san_other':
- name_formatted = name
- else:
- # display as "OID : b64(DER)"
- name_formatted = u'{}:{}'.format(
- name_type[1], base64.b64encode(der_name))
- attr_value = self.params[attr_name].type(name_formatted)
+ attr_value = self.params[attr_name].type(format_name(gn))
obj.setdefault(attr_name, []).append(attr_value)
if full and attr_name.startswith('san_other_'):
# also include known otherName in generic otherName attribute
- name_formatted = u'{}:{}'.format(
- name_type[1], base64.b64encode(der_name))
- attr_value = self.params['san_other'].type(name_formatted)
+ attr_value = self.params['san_other'].type(_format_othername(gn))
obj.setdefault('san_other', []).append(attr_value)
+def _format_othername(on):
+ """Format a python-cryptography OtherName for display."""
+ return u'{}:{}'.format(
+ on.type_id.dotted_string,
+ base64.b64encode(on.value)
+ )
+
+
class BaseCertMethod(Method):
def get_options(self):
yield self.obj.params['cacn'].clone(query=True)
@@ -909,7 +918,7 @@ class cert_show(Retrieve, CertMethod, VirtualCommand):
raise acierr # pylint: disable=E0702
ca_obj = api.Command.ca_show(options['cacn'])['result']
- if DN(unicode(cert.issuer)) != DN(ca_obj['ipacasubjectdn'][0]):
+ if DN(cert.issuer) != DN(ca_obj['ipacasubjectdn'][0]):
# DN of cert differs from what we requested
raise errors.NotFound(
reason=_("Certificate with serial number %(serial)s "
@@ -1132,16 +1141,16 @@ class cert_find(Search, CertMethod):
def _get_cert_key(self, cert):
try:
- nss_cert = x509.load_certificate(cert, x509.DER)
- except NSPRError as e:
+ cert_obj = x509.load_certificate(cert, x509.DER)
+ except ValueError as e:
message = messages.SearchResultTruncated(
reason=_("failed to load certificate: %s") % e,
)
self.add_message(message)
- raise ValueError("failed to load certificate")
+ raise
- return (DN(unicode(nss_cert.issuer)), nss_cert.serial_number)
+ return (DN(cert_obj.issuer), cert_obj.serial)
def _get_cert_obj(self, cert, all, raw, pkey_only):
obj = {'certificate': unicode(base64.b64encode(cert))}
diff --git a/ipaserver/plugins/service.py b/ipaserver/plugins/service.py
index a39ba3249..ddae37fec 100644
--- a/ipaserver/plugins/service.py
+++ b/ipaserver/plugins/service.py
@@ -19,6 +19,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+from cryptography.hazmat.primitives import hashes
import six
from ipalib import api, errors, messages
@@ -49,8 +50,6 @@ from ipalib import output
from ipapython import kerberos
from ipapython.dn import DN
-import nss.nss as nss
-
if six.PY3:
unicode = str
@@ -268,16 +267,17 @@ def set_certificate_attrs(entry_attrs):
cert = entry_attrs['usercertificate']
cert = x509.normalize_certificate(cert)
cert = x509.load_certificate(cert, datatype=x509.DER)
- entry_attrs['subject'] = unicode(cert.subject)
- entry_attrs['serial_number'] = unicode(cert.serial_number)
- entry_attrs['serial_number_hex'] = u'0x%X' % cert.serial_number
- entry_attrs['issuer'] = unicode(cert.issuer)
- entry_attrs['valid_not_before'] = unicode(cert.valid_not_before_str)
- entry_attrs['valid_not_after'] = unicode(cert.valid_not_after_str)
+ entry_attrs['subject'] = unicode(DN(cert.subject))
+ entry_attrs['serial_number'] = unicode(cert.serial)
+ entry_attrs['serial_number_hex'] = u'0x%X' % cert.serial
+ entry_attrs['issuer'] = unicode(DN(cert.issuer))
+ entry_attrs['valid_not_before'] = x509.format_datetime(
+ cert.not_valid_before)
+ entry_attrs['valid_not_after'] = x509.format_datetime(cert.not_valid_after)
entry_attrs['md5_fingerprint'] = x509.to_hex_with_colons(
- nss.md5_digest(cert.der_data))
+ cert.fingerprint(hashes.MD5()))
entry_attrs['sha1_fingerprint'] = x509.to_hex_with_colons(
- nss.sha1_digest(cert.der_data))
+ cert.fingerprint(hashes.SHA1()))
def check_required_principal(ldap, principal):
"""
diff --git a/ipatests/test_ipalib/test_x509.py b/ipatests/test_ipalib/test_x509.py
index f765bc964..750e086e4 100644
--- a/ipatests/test_ipalib/test_x509.py
+++ b/ipatests/test_ipalib/test_x509.py
@@ -22,9 +22,9 @@ Test the `ipalib.x509` module.
"""
import base64
+import datetime
import pytest
-from nss.error import NSPRError
from ipalib import x509
from ipapython.dn import DN
@@ -57,17 +57,25 @@ class test_x509(object):
# Load a good cert
x509.load_certificate(goodcert)
+ # Should handle list/tuple
+ x509.load_certificate((goodcert,))
+ x509.load_certificate([goodcert])
+
# Load a good cert with headers
newcert = '-----BEGIN CERTIFICATE-----' + goodcert + '-----END CERTIFICATE-----'
x509.load_certificate(newcert)
+ # Should handle list/tuple
+ x509.load_certificate((newcert,))
+ x509.load_certificate([newcert])
+
# Load a good cert with bad headers
newcert = '-----BEGIN CERTIFICATE-----' + goodcert
with pytest.raises((TypeError, ValueError)):
x509.load_certificate(newcert)
# Load a bad cert
- with pytest.raises(NSPRError):
+ with pytest.raises(ValueError):
x509.load_certificate(badcert)
def test_1_load_der_cert(self):
@@ -80,53 +88,23 @@ class test_x509(object):
# Load a good cert
x509.load_certificate(der, x509.DER)
- def test_2_get_subject(self):
- """
- Test retrieving the subject
- """
- subject = x509.get_subject(goodcert)
- assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
-
- der = base64.b64decode(goodcert)
- subject = x509.get_subject(der, x509.DER)
- assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
-
- # We should be able to pass in a tuple/list of certs too
- subject = x509.get_subject((goodcert))
- assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
-
- subject = x509.get_subject([goodcert])
- assert DN(str(subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
-
- def test_2_get_serial_number(self):
- """
- Test retrieving the serial number
- """
- serial = x509.get_serial_number(goodcert)
- assert serial == 1093
-
- der = base64.b64decode(goodcert)
- serial = x509.get_serial_number(der, x509.DER)
- assert serial == 1093
-
- # We should be able to pass in a tuple/list of certs too
- serial = x509.get_serial_number((goodcert))
- assert serial == 1093
-
- serial = x509.get_serial_number([goodcert])
- assert serial == 1093
+ # Should handle list/tuple
+ x509.load_certificate((der,), x509.DER)
+ x509.load_certificate([der], x509.DER)
def test_3_cert_contents(self):
"""
Test the contents of a certificate
"""
- # Verify certificate contents. This exercises python-nss more than
- # anything but confirms our usage of it.
+ # Verify certificate contents. This exercises python-cryptography
+ # more than anything but confirms our usage of it.
+ not_before = datetime.datetime(2010, 6, 25, 13, 0, 42)
+ not_after = datetime.datetime(2015, 6, 25, 13, 0, 42)
cert = x509.load_certificate(goodcert)
- assert DN(str(cert.subject)) == DN(('CN','ipa.example.com'),('O','IPA'))
- assert DN(str(cert.issuer)) == DN(('CN','IPA Test Certificate Authority'))
- assert cert.serial_number == 1093
- assert cert.valid_not_before_str == 'Fri Jun 25 13:00:42 2010 UTC'
- assert cert.valid_not_after_str == 'Thu Jun 25 13:00:42 2015 UTC'
+ assert DN(cert.subject) == DN(('CN', 'ipa.example.com'), ('O', 'IPA'))
+ assert DN(cert.issuer) == DN(('CN', 'IPA Test Certificate Authority'))
+ assert cert.serial == 1093
+ assert cert.not_valid_before == not_before
+ assert cert.not_valid_after == not_after
diff --git a/ipatests/test_ipaserver/test_ldap.py b/ipatests/test_ipaserver/test_ldap.py
index 904c8415c..1ea995999 100644
--- a/ipatests/test_ipaserver/test_ldap.py
+++ b/ipatests/test_ipaserver/test_ldap.py
@@ -80,7 +80,7 @@ class test_ldap(object):
entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
cert = entry_attrs.get('usercertificate')
cert = cert[0]
- serial = unicode(x509.get_serial_number(cert, x509.DER))
+ serial = x509.load_certificate(cert, x509.DER).serial
assert serial is not None
def test_simple(self):
@@ -99,7 +99,7 @@ class test_ldap(object):
entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
cert = entry_attrs.get('usercertificate')
cert = cert[0]
- serial = unicode(x509.get_serial_number(cert, x509.DER))
+ serial = x509.load_certificate(cert, x509.DER).serial
assert serial is not None
def test_Backend(self):
@@ -127,7 +127,7 @@ class test_ldap(object):
entry_attrs = result['result']
cert = entry_attrs.get('usercertificate')
cert = cert[0]
- serial = unicode(x509.get_serial_number(cert, x509.DER))
+ serial = x509.load_certificate(cert, x509.DER).serial
assert serial is not None
def test_autobind(self):
@@ -143,7 +143,7 @@ class test_ldap(object):
entry_attrs = self.conn.get_entry(self.dn, ['usercertificate'])
cert = entry_attrs.get('usercertificate')
cert = cert[0]
- serial = unicode(x509.get_serial_number(cert, x509.DER))
+ serial = x509.load_certificate(cert, x509.DER).serial
assert serial is not None
diff --git a/ipatests/test_ipaserver/test_otptoken_import.py b/ipatests/test_ipaserver/test_otptoken_import.py
index f1b4331df..b885cefe0 100644
--- a/ipatests/test_ipaserver/test_otptoken_import.py
+++ b/ipatests/test_ipaserver/test_otptoken_import.py
@@ -20,7 +20,6 @@
import os
import pytest
from nss import nss
-from ipalib.x509 import initialize_nss_database
from ipaserver.install.ipa_otptoken_import import PSKCDocument, ValidationError
@@ -30,9 +29,6 @@ basename = os.path.join(os.path.dirname(__file__), "data")
@pytest.mark.tier1
class test_otptoken_import(object):
- def teardown(self):
- initialize_nss_database()
-
def test_figure3(self):
doc = PSKCDocument(os.path.join(basename, "pskc-figure3.xml"))
assert doc.keyname is None