diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cryptography/__about__.py | 2 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 614 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/asn1.py | 2 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/ec.py | 15 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/evp.py | 4 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/ssl.py | 31 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/x509.py | 24 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/x509_vfy.py | 16 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/x509name.py | 7 | ||||
-rw-r--r-- | src/cryptography/hazmat/bindings/openssl/x509v3.py | 74 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/dsa.py | 22 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/ec.py | 29 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/rsa.py | 22 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/interfaces/__init__.py | 351 | ||||
-rw-r--r-- | src/cryptography/utils.py | 3 | ||||
-rw-r--r-- | src/cryptography/x509.py | 507 |
16 files changed, 1098 insertions, 625 deletions
diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py index 0f8d4871..9c28be2e 100644 --- a/src/cryptography/__about__.py +++ b/src/cryptography/__about__.py @@ -14,7 +14,7 @@ __summary__ = ("cryptography is a package which provides cryptographic recipes" " and primitives to Python developers.") __uri__ = "https://github.com/pyca/cryptography" -__version__ = "0.9.dev1" +__version__ = "1.0.dev1" __author__ = "The cryptography developers" __email__ = "cryptography-dev@python.org" diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 42ca138d..f46dd1b7 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -1,15 +1,6 @@ -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. from __future__ import absolute_import, division, print_function @@ -25,7 +16,7 @@ from six.moves import urllib_parse from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization def _obj2txt(backend, obj): @@ -38,34 +29,57 @@ def _obj2txt(backend, obj): return backend._ffi.buffer(buf, res)[:].decode() -def _build_x509_name(backend, x509_name): +def _asn1_integer_to_int(backend, asn1_int): + bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) + assert bn != backend._ffi.NULL + bn = backend._ffi.gc(bn, backend._lib.BN_free) + return backend._bn_to_int(bn) + + +def _asn1_string_to_utf8(backend, asn1_string): + buf = backend._ffi.new("unsigned char **") + res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) + assert res >= 0 + assert buf[0] != backend._ffi.NULL + buf = backend._ffi.gc( + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) + ) + return backend._ffi.buffer(buf[0], res)[:].decode('utf8') + + +def _decode_x509_name_entry(backend, x509_name_entry): + obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry) + assert obj != backend._ffi.NULL + data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry) + assert data != backend._ffi.NULL + value = _asn1_string_to_utf8(backend, data) + oid = _obj2txt(backend, obj) + + return x509.NameAttribute(x509.ObjectIdentifier(oid), value) + + +def _decode_x509_name(backend, x509_name): count = backend._lib.X509_NAME_entry_count(x509_name) attributes = [] for x in range(count): entry = backend._lib.X509_NAME_get_entry(x509_name, x) - obj = backend._lib.X509_NAME_ENTRY_get_object(entry) - assert obj != backend._ffi.NULL - data = backend._lib.X509_NAME_ENTRY_get_data(entry) - assert data != backend._ffi.NULL - buf = backend._ffi.new("unsigned char **") - res = backend._lib.ASN1_STRING_to_UTF8(buf, data) - assert res >= 0 - assert buf[0] != backend._ffi.NULL - buf = backend._ffi.gc( - buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) - ) - value = backend._ffi.buffer(buf[0], res)[:].decode('utf8') - oid = _obj2txt(backend, obj) - attributes.append( - x509.NameAttribute( - x509.ObjectIdentifier(oid), value - ) - ) + attributes.append(_decode_x509_name_entry(backend, entry)) return x509.Name(attributes) -def _build_general_name(backend, gn): +def _decode_general_names(backend, gns): + num = backend._lib.sk_GENERAL_NAME_num(gns) + names = [] + for i in range(num): + gn = backend._lib.sk_GENERAL_NAME_value(gns, i) + assert gn != backend._ffi.NULL + names.append(_decode_general_name(backend, gn)) + + return names + + +def _decode_general_name(backend, gn): if gn.type == backend._lib.GEN_DNS: data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:] return x509.DNSName(idna.decode(data)) @@ -106,7 +120,7 @@ def _build_general_name(backend, gn): ) elif gn.type == backend._lib.GEN_DIRNAME: return x509.DirectoryName( - _build_x509_name(backend, gn.d.directoryName) + _decode_x509_name(backend, gn.d.directoryName) ) elif gn.type == backend._lib.GEN_EMAIL: data = backend._ffi.buffer( @@ -182,12 +196,7 @@ class _Certificate(object): def serial(self): asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) assert asn1_int != self._backend._ffi.NULL - bn = self._backend._lib.ASN1_INTEGER_to_BN( - asn1_int, self._backend._ffi.NULL - ) - assert bn != self._backend._ffi.NULL - bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) - return self._backend._bn_to_int(bn) + return _asn1_integer_to_int(self._backend, asn1_int) def public_key(self): pkey = self._backend._lib.X509_get_pubkey(self._x509) @@ -226,13 +235,13 @@ class _Certificate(object): def issuer(self): issuer = self._backend._lib.X509_get_issuer_name(self._x509) assert issuer != self._backend._ffi.NULL - return _build_x509_name(self._backend, issuer) + return _decode_x509_name(self._backend, issuer) @property def subject(self): subject = self._backend._lib.X509_get_subject_name(self._x509) assert subject != self._backend._ffi.NULL - return _build_x509_name(self._backend, subject) + return _decode_x509_name(self._backend, subject) @property def signature_hash_algorithm(self): @@ -260,19 +269,25 @@ class _Certificate(object): "Duplicate {0} extension found".format(oid), oid ) elif oid == x509.OID_BASIC_CONSTRAINTS: - value = self._build_basic_constraints(ext) + value = _decode_basic_constraints(self._backend, ext) elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER: - value = self._build_subject_key_identifier(ext) + value = _decode_subject_key_identifier(self._backend, ext) elif oid == x509.OID_KEY_USAGE: - value = self._build_key_usage(ext) + value = _decode_key_usage(self._backend, ext) elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME: - value = self._build_subject_alt_name(ext) + value = _decode_subject_alt_name(self._backend, ext) elif oid == x509.OID_EXTENDED_KEY_USAGE: - value = self._build_extended_key_usage(ext) + value = _decode_extended_key_usage(self._backend, ext) elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER: - value = self._build_authority_key_identifier(ext) + value = _decode_authority_key_identifier(self._backend, ext) elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS: - value = self._build_authority_information_access(ext) + value = _decode_authority_information_access( + self._backend, ext + ) + elif oid == x509.OID_CERTIFICATE_POLICIES: + value = _decode_certificate_policies(self._backend, ext) + elif oid == x509.OID_CRL_DISTRIBUTION_POINTS: + value = _decode_crl_distribution_points(self._backend, ext) elif critical: raise x509.UnsupportedExtension( "{0} is not currently supported".format(oid), oid @@ -287,168 +302,335 @@ class _Certificate(object): return x509.Extensions(extensions) - def _build_basic_constraints(self, ext): - bc_st = self._backend._lib.X509V3_EXT_d2i(ext) - assert bc_st != self._backend._ffi.NULL - basic_constraints = self._backend._ffi.cast( - "BASIC_CONSTRAINTS *", bc_st - ) - basic_constraints = self._backend._ffi.gc( - basic_constraints, self._backend._lib.BASIC_CONSTRAINTS_free - ) - # The byte representation of an ASN.1 boolean true is \xff. OpenSSL - # chooses to just map this to its ordinal value, so true is 255 and - # false is 0. - ca = basic_constraints.ca == 255 - if basic_constraints.pathlen == self._backend._ffi.NULL: - path_length = None - else: - bn = self._backend._lib.ASN1_INTEGER_to_BN( - basic_constraints.pathlen, self._backend._ffi.NULL - ) - assert bn != self._backend._ffi.NULL - bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) - path_length = self._backend._bn_to_int(bn) - - return x509.BasicConstraints(ca, path_length) - - def _build_subject_key_identifier(self, ext): - asn1_string = self._backend._lib.X509V3_EXT_d2i(ext) - assert asn1_string != self._backend._ffi.NULL - asn1_string = self._backend._ffi.cast( - "ASN1_OCTET_STRING *", asn1_string - ) - asn1_string = self._backend._ffi.gc( - asn1_string, self._backend._lib.ASN1_OCTET_STRING_free - ) - return x509.SubjectKeyIdentifier( - self._backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] - ) + def public_bytes(self, encoding): + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") - def _build_authority_key_identifier(self, ext): - akid = self._backend._lib.X509V3_EXT_d2i(ext) - assert akid != self._backend._ffi.NULL - akid = self._backend._ffi.cast("AUTHORITY_KEYID *", akid) - akid = self._backend._ffi.gc( - akid, self._backend._lib.AUTHORITY_KEYID_free + bio = self._backend._create_mem_bio() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509(bio, self._x509) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_bio(bio, self._x509) + assert res == 1 + return self._backend._read_mem_bio(bio) + + +def _decode_certificate_policies(backend, ext): + cp = backend._ffi.cast( + "Cryptography_STACK_OF_POLICYINFO *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert cp != backend._ffi.NULL + cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free) + num = backend._lib.sk_POLICYINFO_num(cp) + certificate_policies = [] + for i in range(num): + qualifiers = None + pi = backend._lib.sk_POLICYINFO_value(cp, i) + oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid)) + if pi.qualifiers != backend._ffi.NULL: + qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) + qualifiers = [] + for j in range(qnum): + pqi = backend._lib.sk_POLICYQUALINFO_value( + pi.qualifiers, j + ) + pqualid = x509.ObjectIdentifier( + _obj2txt(backend, pqi.pqualid) + ) + if pqualid == x509.OID_CPS_QUALIFIER: + cpsuri = backend._ffi.buffer( + pqi.d.cpsuri.data, pqi.d.cpsuri.length + )[:].decode('ascii') + qualifiers.append(cpsuri) + elif pqualid == x509.OID_CPS_USER_NOTICE: + user_notice = _decode_user_notice( + backend, pqi.d.usernotice + ) + qualifiers.append(user_notice) + + certificate_policies.append( + x509.PolicyInformation(oid, qualifiers) ) - key_identifier = None - authority_cert_issuer = None - authority_cert_serial_number = None - - if akid.keyid != self._backend._ffi.NULL: - key_identifier = self._backend._ffi.buffer( - akid.keyid.data, akid.keyid.length - )[:] - if akid.issuer != self._backend._ffi.NULL: - authority_cert_issuer = [] + return x509.CertificatePolicies(certificate_policies) - num = self._backend._lib.sk_GENERAL_NAME_num(akid.issuer) - for i in range(num): - gn = self._backend._lib.sk_GENERAL_NAME_value(akid.issuer, i) - assert gn != self._backend._ffi.NULL - value = _build_general_name(self._backend, gn) - authority_cert_issuer.append(value) +def _decode_user_notice(backend, un): + explicit_text = None + notice_reference = None - if akid.serial != self._backend._ffi.NULL: - bn = self._backend._lib.ASN1_INTEGER_to_BN( - akid.serial, self._backend._ffi.NULL - ) - assert bn != self._backend._ffi.NULL - bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) - authority_cert_serial_number = self._backend._bn_to_int(bn) + if un.exptext != backend._ffi.NULL: + explicit_text = _asn1_string_to_utf8(backend, un.exptext) - return x509.AuthorityKeyIdentifier( - key_identifier, authority_cert_issuer, authority_cert_serial_number + if un.noticeref != backend._ffi.NULL: + organization = _asn1_string_to_utf8( + backend, un.noticeref.organization ) - def _build_authority_information_access(self, ext): - aia = self._backend._lib.X509V3_EXT_d2i(ext) - assert aia != self._backend._ffi.NULL - aia = self._backend._ffi.cast( - "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia - ) - aia = self._backend._ffi.gc( - aia, self._backend._lib.sk_ACCESS_DESCRIPTION_free + num = backend._lib.sk_ASN1_INTEGER_num( + un.noticeref.noticenos ) - num = self._backend._lib.sk_ACCESS_DESCRIPTION_num(aia) - access_descriptions = [] + notice_numbers = [] for i in range(num): - ad = self._backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) - assert ad.method != self._backend._ffi.NULL - oid = x509.ObjectIdentifier(_obj2txt(self._backend, ad.method)) - assert ad.location != self._backend._ffi.NULL - gn = _build_general_name(self._backend, ad.location) - access_descriptions.append(x509.AccessDescription(oid, gn)) - - return x509.AuthorityInformationAccess(access_descriptions) - - def _build_key_usage(self, ext): - bit_string = self._backend._lib.X509V3_EXT_d2i(ext) - assert bit_string != self._backend._ffi.NULL - bit_string = self._backend._ffi.cast("ASN1_BIT_STRING *", bit_string) - bit_string = self._backend._ffi.gc( - bit_string, self._backend._lib.ASN1_BIT_STRING_free - ) - get_bit = self._backend._lib.ASN1_BIT_STRING_get_bit - digital_signature = get_bit(bit_string, 0) == 1 - content_commitment = get_bit(bit_string, 1) == 1 - key_encipherment = get_bit(bit_string, 2) == 1 - data_encipherment = get_bit(bit_string, 3) == 1 - key_agreement = get_bit(bit_string, 4) == 1 - key_cert_sign = get_bit(bit_string, 5) == 1 - crl_sign = get_bit(bit_string, 6) == 1 - encipher_only = get_bit(bit_string, 7) == 1 - decipher_only = get_bit(bit_string, 8) == 1 - return x509.KeyUsage( - digital_signature, - content_commitment, - key_encipherment, - data_encipherment, - key_agreement, - key_cert_sign, - crl_sign, - encipher_only, - decipher_only - ) + asn1_int = backend._lib.sk_ASN1_INTEGER_value( + un.noticeref.noticenos, i + ) + notice_num = _asn1_integer_to_int( + backend, asn1_int + ) + notice_numbers.append(notice_num) - def _build_subject_alt_name(self, ext): - gns = self._backend._ffi.cast( - "GENERAL_NAMES *", self._backend._lib.X509V3_EXT_d2i(ext) + notice_reference = x509.NoticeReference( + organization, notice_numbers ) - assert gns != self._backend._ffi.NULL - gns = self._backend._ffi.gc(gns, self._backend._lib.GENERAL_NAMES_free) - num = self._backend._lib.sk_GENERAL_NAME_num(gns) - general_names = [] - - for i in range(num): - gn = self._backend._lib.sk_GENERAL_NAME_value(gns, i) - assert gn != self._backend._ffi.NULL - value = _build_general_name(self._backend, gn) - general_names.append(value) + return x509.UserNotice(notice_reference, explicit_text) + + +def _decode_basic_constraints(backend, ext): + bc_st = backend._lib.X509V3_EXT_d2i(ext) + assert bc_st != backend._ffi.NULL + basic_constraints = backend._ffi.cast( + "BASIC_CONSTRAINTS *", bc_st + ) + basic_constraints = backend._ffi.gc( + basic_constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + # The byte representation of an ASN.1 boolean true is \xff. OpenSSL + # chooses to just map this to its ordinal value, so true is 255 and + # false is 0. + ca = basic_constraints.ca == 255 + if basic_constraints.pathlen == backend._ffi.NULL: + path_length = None + else: + path_length = _asn1_integer_to_int( + backend, basic_constraints.pathlen + ) - return x509.SubjectAlternativeName(general_names) + return x509.BasicConstraints(ca, path_length) + + +def _decode_subject_key_identifier(backend, ext): + asn1_string = backend._lib.X509V3_EXT_d2i(ext) + assert asn1_string != backend._ffi.NULL + asn1_string = backend._ffi.cast( + "ASN1_OCTET_STRING *", asn1_string + ) + asn1_string = backend._ffi.gc( + asn1_string, backend._lib.ASN1_OCTET_STRING_free + ) + return x509.SubjectKeyIdentifier( + backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + ) + + +def _decode_authority_key_identifier(backend, ext): + akid = backend._lib.X509V3_EXT_d2i(ext) + assert akid != backend._ffi.NULL + akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) + akid = backend._ffi.gc( + akid, backend._lib.AUTHORITY_KEYID_free + ) + key_identifier = None + authority_cert_issuer = None + authority_cert_serial_number = None + + if akid.keyid != backend._ffi.NULL: + key_identifier = backend._ffi.buffer( + akid.keyid.data, akid.keyid.length + )[:] + + if akid.issuer != backend._ffi.NULL: + authority_cert_issuer = _decode_general_names( + backend, akid.issuer + ) - def _build_extended_key_usage(self, ext): - sk = self._backend._ffi.cast( - "Cryptography_STACK_OF_ASN1_OBJECT *", - self._backend._lib.X509V3_EXT_d2i(ext) + if akid.serial != backend._ffi.NULL: + authority_cert_serial_number = _asn1_integer_to_int( + backend, akid.serial ) - assert sk != self._backend._ffi.NULL - sk = self._backend._ffi.gc(sk, self._backend._lib.sk_ASN1_OBJECT_free) - num = self._backend._lib.sk_ASN1_OBJECT_num(sk) - ekus = [] - for i in range(num): - obj = self._backend._lib.sk_ASN1_OBJECT_value(sk, i) - assert obj != self._backend._ffi.NULL - oid = x509.ObjectIdentifier(_obj2txt(self._backend, obj)) - ekus.append(oid) + return x509.AuthorityKeyIdentifier( + key_identifier, authority_cert_issuer, authority_cert_serial_number + ) + + +def _decode_authority_information_access(backend, ext): + aia = backend._lib.X509V3_EXT_d2i(ext) + assert aia != backend._ffi.NULL + aia = backend._ffi.cast( + "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia + ) + aia = backend._ffi.gc( + aia, backend._lib.sk_ACCESS_DESCRIPTION_free + ) + num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia) + access_descriptions = [] + for i in range(num): + ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i) + assert ad.method != backend._ffi.NULL + oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) + assert ad.location != backend._ffi.NULL + gn = _decode_general_name(backend, ad.location) + access_descriptions.append(x509.AccessDescription(oid, gn)) + + return x509.AuthorityInformationAccess(access_descriptions) + + +def _decode_key_usage(backend, ext): + bit_string = backend._lib.X509V3_EXT_d2i(ext) + assert bit_string != backend._ffi.NULL + bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) + bit_string = backend._ffi.gc( + bit_string, backend._lib.ASN1_BIT_STRING_free + ) + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + digital_signature = get_bit(bit_string, 0) == 1 + content_commitment = get_bit(bit_string, 1) == 1 + key_encipherment = get_bit(bit_string, 2) == 1 + data_encipherment = get_bit(bit_string, 3) == 1 + key_agreement = get_bit(bit_string, 4) == 1 + key_cert_sign = get_bit(bit_string, 5) == 1 + crl_sign = get_bit(bit_string, 6) == 1 + encipher_only = get_bit(bit_string, 7) == 1 + decipher_only = get_bit(bit_string, 8) == 1 + return x509.KeyUsage( + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only + ) + + +def _decode_subject_alt_name(backend, ext): + gns = backend._ffi.cast( + "GENERAL_NAMES *", backend._lib.X509V3_EXT_d2i(ext) + ) + assert gns != backend._ffi.NULL + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) + + return x509.SubjectAlternativeName(general_names) + + +def _decode_extended_key_usage(backend, ext): + sk = backend._ffi.cast( + "Cryptography_STACK_OF_ASN1_OBJECT *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert sk != backend._ffi.NULL + sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free) + num = backend._lib.sk_ASN1_OBJECT_num(sk) + ekus = [] + + for i in range(num): + obj = backend._lib.sk_ASN1_OBJECT_value(sk, i) + assert obj != backend._ffi.NULL + oid = x509.ObjectIdentifier(_obj2txt(backend, obj)) + ekus.append(oid) + + return x509.ExtendedKeyUsage(ekus) + + +def _decode_crl_distribution_points(backend, ext): + cdps = backend._ffi.cast( + "Cryptography_STACK_OF_DIST_POINT *", + backend._lib.X509V3_EXT_d2i(ext) + ) + assert cdps != backend._ffi.NULL + cdps = backend._ffi.gc( + cdps, backend._lib.sk_DIST_POINT_free) + num = backend._lib.sk_DIST_POINT_num(cdps) + + dist_points = [] + for i in range(num): + full_name = None + relative_name = None + crl_issuer = None + reasons = None + cdp = backend._lib.sk_DIST_POINT_value(cdps, i) + if cdp.reasons != backend._ffi.NULL: + # We will check each bit from RFC 5280 + # ReasonFlags ::= BIT STRING { + # unused (0), + # keyCompromise (1), + # cACompromise (2), + # affiliationChanged (3), + # superseded (4), + # cessationOfOperation (5), + # certificateHold (6), + # privilegeWithdrawn (7), + # aACompromise (8) } + reasons = [] + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + if get_bit(cdp.reasons, 1): + reasons.append(x509.ReasonFlags.key_compromise) + + if get_bit(cdp.reasons, 2): + reasons.append(x509.ReasonFlags.ca_compromise) + + if get_bit(cdp.reasons, 3): + reasons.append(x509.ReasonFlags.affiliation_changed) + + if get_bit(cdp.reasons, 4): + reasons.append(x509.ReasonFlags.superseded) + + if get_bit(cdp.reasons, 5): + reasons.append(x509.ReasonFlags.cessation_of_operation) + + if get_bit(cdp.reasons, 6): + reasons.append(x509.ReasonFlags.certificate_hold) + + if get_bit(cdp.reasons, 7): + reasons.append(x509.ReasonFlags.privilege_withdrawn) + + if get_bit(cdp.reasons, 8): + reasons.append(x509.ReasonFlags.aa_compromise) + + reasons = frozenset(reasons) + + if cdp.CRLissuer != backend._ffi.NULL: + crl_issuer = _decode_general_names(backend, cdp.CRLissuer) + + # Certificates may have a crl_issuer/reasons and no distribution + # point so make sure it's not null. + if cdp.distpoint != backend._ffi.NULL: + # Type 0 is fullName, there is no #define for it in the code. + if cdp.distpoint.type == 0: + full_name = _decode_general_names( + backend, cdp.distpoint.name.fullname + ) + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. + else: + rns = cdp.distpoint.name.relativename + rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = [] + for i in range(rnum): + rn = backend._lib.sk_X509_NAME_ENTRY_value( + rns, i + ) + assert rn != backend._ffi.NULL + attributes.append( + _decode_x509_name_entry(backend, rn) + ) + + relative_name = x509.Name(attributes) + + dist_points.append( + x509.DistributionPoint( + full_name, relative_name, reasons, crl_issuer + ) + ) - return x509.ExtendedKeyUsage(ekus) + return x509.CRLDistributionPoints(dist_points) @utils.register_interface(x509.CertificateSigningRequest) @@ -467,7 +649,7 @@ class _CertificateSigningRequest(object): def subject(self): subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req) assert subject != self._backend._ffi.NULL - return _build_x509_name(self._backend, subject) + return _decode_x509_name(self._backend, subject) @property def signature_hash_algorithm(self): @@ -478,3 +660,49 @@ class _CertificateSigningRequest(object): raise UnsupportedAlgorithm( "Signature algorithm OID:{0} not recognized".format(oid) ) + + @property + def extensions(self): + extensions = [] + seen_oids = set() + x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) + extcount = self._backend._lib.sk_X509_EXTENSION_num(x509_exts) + for i in range(0, extcount): + ext = self._backend._lib.sk_X509_EXTENSION_value(x509_exts, i) + assert ext != self._backend._ffi.NULL + crit = self._backend._lib.X509_EXTENSION_get_critical(ext) + critical = crit == 1 + oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object)) + if oid in seen_oids: + raise x509.DuplicateExtension( + "Duplicate {0} extension found".format(oid), oid + ) + elif oid == x509.OID_BASIC_CONSTRAINTS: + value = _decode_basic_constraints(self._backend, ext) + elif critical: + raise x509.UnsupportedExtension( + "{0} is not currently supported".format(oid), oid + ) + else: + # Unsupported non-critical extension, silently skipping for now + seen_oids.add(oid) + continue + + seen_oids.add(oid) + extensions.append(x509.Extension(oid, critical, value)) + + return x509.Extensions(extensions) + + def public_bytes(self, encoding): + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._backend._create_mem_bio() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509_REQ( + bio, self._x509_req + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req) + assert res == 1 + return self._backend._read_mem_bio(bio) diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index 475bd052..c18708c5 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -98,6 +98,7 @@ ASN1_TIME *ASN1_TIME_new(void); void ASN1_TIME_free(ASN1_TIME *); ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, ASN1_GENERALIZEDTIME **); +ASN1_TIME *ASN1_TIME_set(ASN1_TIME *, time_t); /* ASN1 UTCTIME */ ASN1_UTCTIME *ASN1_UTCTIME_new(void); @@ -113,6 +114,7 @@ void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *); ASN1_ENUMERATED *ASN1_ENUMERATED_new(void); void ASN1_ENUMERATED_free(ASN1_ENUMERATED *); int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long); +long ASN1_ENUMERATED_get(ASN1_ENUMERATED *); ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long, const ASN1_ITEM *); diff --git a/src/cryptography/hazmat/bindings/openssl/ec.py b/src/cryptography/hazmat/bindings/openssl/ec.py index 84a596eb..c5052d36 100644 --- a/src/cryptography/hazmat/bindings/openssl/ec.py +++ b/src/cryptography/hazmat/bindings/openssl/ec.py @@ -17,6 +17,7 @@ static const int Cryptography_HAS_EC; static const int Cryptography_HAS_EC_1_0_1; static const int Cryptography_HAS_EC_NISTP_64_GCC_128; static const int Cryptography_HAS_EC2M; +static const int Cryptography_HAS_EC_1_0_2; static const int OPENSSL_EC_NAMED_CURVE; @@ -188,6 +189,8 @@ const EC_METHOD *EC_GFp_nistp521_method(); const EC_METHOD *EC_GF2m_simple_method(); int EC_METHOD_get_field_type(const EC_METHOD *); + +const char *EC_curve_nid2nist(int); """ CUSTOMIZATIONS = """ @@ -385,6 +388,14 @@ EC_GROUP *(*EC_GROUP_new_curve_GF2m)( #else static const long Cryptography_HAS_EC2M = 1; #endif + +#if defined(OPENSSL_NO_EC) || OPENSSL_VERSION_NUMBER < 0x1000200f || \ + defined(LIBRESSL_VERSION_NUMBER) +static const long Cryptography_HAS_EC_1_0_2 = 0; +const char *(*EC_curve_nid2nist)(int) = NULL; +#else +static const long Cryptography_HAS_EC_1_0_2 = 1; +#endif """ CONDITIONAL_NAMES = { @@ -478,4 +489,8 @@ CONDITIONAL_NAMES = { "EC_GROUP_get_curve_GF2m", "EC_GROUP_new_curve_GF2m", ], + + "Cryptography_HAS_EC_1_0_2": [ + "EC_curve_nid2nist", + ], } diff --git a/src/cryptography/hazmat/bindings/openssl/evp.py b/src/cryptography/hazmat/bindings/openssl/evp.py index 780ce900..93aa83de 100644 --- a/src/cryptography/hazmat/bindings/openssl/evp.py +++ b/src/cryptography/hazmat/bindings/openssl/evp.py @@ -28,6 +28,7 @@ typedef struct evp_pkey_st { typedef ... EVP_PKEY_CTX; static const int EVP_PKEY_RSA; static const int EVP_PKEY_DSA; +static const int EVP_PKEY_DH; static const int EVP_PKEY_EC; static const int EVP_MAX_MD_SIZE; static const int EVP_CTRL_GCM_SET_IVLEN; @@ -154,6 +155,7 @@ int EVP_PKEY_verify(EVP_PKEY_CTX *, const unsigned char *, size_t, const unsigned char *, size_t); int EVP_PKEY_encrypt_init(EVP_PKEY_CTX *); int EVP_PKEY_decrypt_init(EVP_PKEY_CTX *); +int EVP_PKEY_id(const EVP_PKEY *); /* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5 we should move these back to FUNCTIONS. */ @@ -221,6 +223,7 @@ int (*Cryptography_EVP_PKEY_encrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *, const unsigned char *, size_t) = NULL; int (*Cryptography_EVP_PKEY_decrypt)(EVP_PKEY_CTX *, unsigned char *, size_t *, const unsigned char *, size_t) = NULL; +int (*EVP_PKEY_id)(const EVP_PKEY *) = NULL; #endif #ifdef OPENSSL_NO_EC int (*EVP_PKEY_assign_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL; @@ -252,6 +255,7 @@ CONDITIONAL_NAMES = { "Cryptography_EVP_PKEY_decrypt", "EVP_PKEY_decrypt_init", "EVP_PKEY_CTX_set_signature_md", + "EVP_PKEY_id", ], "Cryptography_HAS_EC": [ "EVP_PKEY_assign_EC_KEY", diff --git a/src/cryptography/hazmat/bindings/openssl/ssl.py b/src/cryptography/hazmat/bindings/openssl/ssl.py index 22ff9bf0..3754773b 100644 --- a/src/cryptography/hazmat/bindings/openssl/ssl.py +++ b/src/cryptography/hazmat/bindings/openssl/ssl.py @@ -23,6 +23,7 @@ static const long Cryptography_HAS_COMPRESSION; static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB; static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP; static const long Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE; +static const long Cryptography_HAS_GET_SERVER_TMP_KEY; /* Internally invented symbol to tell us if SNI is supported */ static const long Cryptography_HAS_TLSEXT_HOSTNAME; @@ -123,12 +124,9 @@ static const long SSL_MODE_ENABLE_PARTIAL_WRITE; static const long SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER; static const long SSL_MODE_AUTO_RETRY; static const long SSL3_RANDOM_SIZE; + typedef ... SSL_METHOD; -typedef struct ssl_st { - int version; - int type; - ...; -} SSL_CTX; +typedef ... SSL_CTX; typedef struct { int master_key_length; @@ -143,9 +141,10 @@ typedef struct { } SSL3_STATE; typedef struct { + int version; + int type; SSL3_STATE *s3; SSL_SESSION *session; - int type; ...; } SSL; @@ -165,6 +164,7 @@ const char *SSL_state_string_long(const SSL *); SSL_SESSION *SSL_get1_session(SSL *); int SSL_set_session(SSL *, SSL_SESSION *); int SSL_get_verify_mode(const SSL *); +void SSL_set_verify(SSL *, int, int (*)(int, X509_STORE_CTX *)); void SSL_set_verify_depth(SSL *, int); int SSL_get_verify_depth(const SSL *); int (*SSL_get_verify_callback(const SSL *))(int, X509_STORE_CTX *); @@ -329,6 +329,7 @@ long SSL_set_tlsext_status_ocsp_resp(SSL *, unsigned char *, int); long SSL_get_tlsext_status_ocsp_resp(SSL *, const unsigned char **); long SSL_set_tlsext_status_type(SSL *, long); long SSL_CTX_set_tlsext_status_cb(SSL_CTX *, int(*)(SSL *, void *)); +long SSL_CTX_set_tlsext_status_arg(SSL_CTX *, void *); long SSL_session_reused(SSL *); @@ -382,6 +383,8 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *, void *), void *); void SSL_get0_alpn_selected(const SSL *, const unsigned char **, unsigned *); + +long SSL_get_server_tmp_key(SSL *, EVP_PKEY **); """ CUSTOMIZATIONS = """ @@ -430,6 +433,7 @@ static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 1; #else static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 0; long (*SSL_CTX_set_tlsext_status_cb)(SSL_CTX *, int(*)(SSL *, void *)) = NULL; +long (*SSL_CTX_set_tlsext_status_arg)(SSL_CTX *, void *) = NULL; #endif #ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP @@ -583,6 +587,7 @@ static const long Cryptography_HAS_ALPN = 0; #else static const long Cryptography_HAS_ALPN = 1; #endif + #if defined(OPENSSL_NO_COMP) || defined(LIBRESSL_VERSION_NUMBER) static const long Cryptography_HAS_COMPRESSION = 0; typedef void COMP_METHOD; @@ -590,6 +595,13 @@ typedef void COMP_METHOD; static const long Cryptography_HAS_COMPRESSION = 1; #endif +#if defined(SSL_CTRL_GET_SERVER_TMP_KEY) +static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 1; +#else +static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 0; +long (*SSL_get_server_tmp_key)(SSL *, EVP_PKEY **) = NULL; +#endif + """ CONDITIONAL_NAMES = { @@ -627,6 +639,7 @@ CONDITIONAL_NAMES = { "Cryptography_HAS_TLSEXT_STATUS_REQ_CB": [ "SSL_CTX_set_tlsext_status_cb", + "SSL_CTX_set_tlsext_status_arg" ], "Cryptography_HAS_STATUS_REQ_OCSP_RESP": [ @@ -691,5 +704,9 @@ CONDITIONAL_NAMES = { "SSL_get_current_compression", "SSL_get_current_expansion", "SSL_COMP_get_name", - ] + ], + + "Cryptography_HAS_GET_SERVER_TMP_KEY": [ + "SSL_get_server_tmp_key", + ], } diff --git a/src/cryptography/hazmat/bindings/openssl/x509.py b/src/cryptography/hazmat/bindings/openssl/x509.py index fa6a16b3..e0f42fbb 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509.py +++ b/src/cryptography/hazmat/bindings/openssl/x509.py @@ -64,6 +64,7 @@ typedef struct { typedef struct { X509_CRL_INFO *crl; + X509_ALGOR *sig_alg; ...; } X509_CRL; @@ -145,9 +146,13 @@ X509_EXTENSION *X509_delete_ext(X509 *, int); X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *); X509_EXTENSION *X509_get_ext(X509 *, int); int X509_get_ext_by_NID(X509 *, int, int); + int X509_EXTENSION_get_critical(X509_EXTENSION *); ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *); void X509_EXTENSION_free(X509_EXTENSION *); +X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **, + ASN1_OBJECT *, int, + ASN1_OCTET_STRING *); int i2d_X509(X509 *, unsigned char **); @@ -155,11 +160,13 @@ int X509_REQ_set_version(X509_REQ *, long); X509_REQ *X509_REQ_new(void); void X509_REQ_free(X509_REQ *); int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *); +int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *); int X509_REQ_sign(X509_REQ *, EVP_PKEY *, const EVP_MD *); int X509_REQ_verify(X509_REQ *, EVP_PKEY *); int X509_REQ_digest(const X509_REQ *, const EVP_MD *, unsigned char *, unsigned int *); EVP_PKEY *X509_REQ_get_pubkey(X509_REQ *); +int X509_REQ_print(BIO *, X509_REQ *); int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long); int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int); @@ -183,9 +190,11 @@ int i2d_X509_CRL_bio(BIO *, X509_CRL *); int X509_CRL_print(BIO *, X509_CRL *); int X509_CRL_set_issuer_name(X509_CRL *, X509_NAME *); int X509_CRL_sign(X509_CRL *, EVP_PKEY *, const EVP_MD *); +int X509_CRL_verify(X509_CRL *, EVP_PKEY *); int X509_CRL_get_ext_count(X509_CRL *); X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int); int X509_CRL_add_ext(X509_CRL *, X509_EXTENSION *, int); +int X509_CRL_cmp(const X509_CRL *, const X509_CRL *); int NETSCAPE_SPKI_verify(NETSCAPE_SPKI *, EVP_PKEY *); int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *, EVP_PKEY *, const EVP_MD *); @@ -285,6 +294,7 @@ int X509_CRL_get_version(X509_CRL *); ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *); ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *); X509_NAME *X509_CRL_get_issuer(X509_CRL *); +Cryptography_STACK_OF_X509_REVOKED *X509_CRL_get_REVOKED(X509_CRL *); /* These aren't macros these arguments are all const X on openssl > 1.0.x */ int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *); @@ -301,9 +311,14 @@ int i2d_EC_PUBKEY(EC_KEY *, unsigned char **); EC_KEY *d2i_EC_PUBKEY(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_EC_PUBKEY_bio(BIO *, EC_KEY **); int i2d_EC_PUBKEY_bio(BIO *, EC_KEY *); +EC_KEY *d2i_ECPrivateKey(EC_KEY **, const unsigned char **, long); EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **); +int i2d_ECPrivateKey(EC_KEY *, unsigned char **); int i2d_ECPrivateKey_bio(BIO *, EC_KEY *); +EC_KEY *o2i_ECPublicKey(EC_KEY **, const unsigned char **, long); +int i2o_ECPublicKey(EC_KEY *, unsigned char **); + // declared in safestack int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *); ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int); @@ -320,8 +335,13 @@ int (*i2d_EC_PUBKEY)(EC_KEY *, unsigned char **) = NULL; EC_KEY *(*d2i_EC_PUBKEY)(EC_KEY **, const unsigned char **, long) = NULL; EC_KEY *(*d2i_EC_PUBKEY_bio)(BIO *, EC_KEY **) = NULL; int (*i2d_EC_PUBKEY_bio)(BIO *, EC_KEY *) = NULL; +EC_KEY *(*d2i_ECPrivateKey)(EC_KEY **, const unsigned char **, long) = NULL; EC_KEY *(*d2i_ECPrivateKey_bio)(BIO *, EC_KEY **) = NULL; +int (*i2d_ECPrivateKey)(EC_KEY *, unsigned char **) = NULL; int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL; + +EC_KEY *(*o2i_ECPublicKey)(EC_KEY **, const unsigned char **, long) = NULL; +int (*i2o_ECPublicKey)(EC_KEY *, unsigned char **) = NULL; #endif """ @@ -331,7 +351,11 @@ CONDITIONAL_NAMES = { "d2i_EC_PUBKEY", "d2i_EC_PUBKEY_bio", "i2d_EC_PUBKEY_bio", + "d2i_ECPrivateKey", "d2i_ECPrivateKey_bio", + "i2d_ECPrivateKey", "i2d_ECPrivateKey_bio", + "i2o_ECPublicKey", + "o2i_ECPublicKey", ] } diff --git a/src/cryptography/hazmat/bindings/openssl/x509_vfy.py b/src/cryptography/hazmat/bindings/openssl/x509_vfy.py index 1f75b86f..02631409 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509_vfy.py +++ b/src/cryptography/hazmat/bindings/openssl/x509_vfy.py @@ -29,9 +29,23 @@ static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE; typedef ... Cryptography_STACK_OF_ASN1_OBJECT; typedef ... X509_STORE; -typedef ... X509_STORE_CTX; typedef ... X509_VERIFY_PARAM; +typedef struct x509_store_ctx_st X509_STORE_CTX; +struct x509_store_ctx_st { + X509_STORE *ctx; + int current_method; + X509 *cert; + Cryptography_STACK_OF_X509 *untrusted; + Cryptography_STACK_OF_X509_CRL *crls; + X509_VERIFY_PARAM *param; + void *other_ctx; + int (*verify)(X509_STORE_CTX *); + int (*verify_cb)(int, X509_STORE_CTX *); + int (*get_issuer)(X509 **, X509_STORE_CTX *, X509 *); + ...; +}; + /* While these are defined in the source as ints, they're tagged here as longs, just in case they ever grow to large, such as what we saw with OP_ALL. */ diff --git a/src/cryptography/hazmat/bindings/openssl/x509name.py b/src/cryptography/hazmat/bindings/openssl/x509name.py index bda92eb7..be5b3a75 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509name.py +++ b/src/cryptography/hazmat/bindings/openssl/x509name.py @@ -11,12 +11,14 @@ INCLUDES = """ * See the comment above Cryptography_STACK_OF_X509 in x509.py */ typedef STACK_OF(X509_NAME) Cryptography_STACK_OF_X509_NAME; +typedef STACK_OF(X509_NAME_ENTRY) Cryptography_STACK_OF_X509_NAME_ENTRY; """ TYPES = """ typedef ... X509_NAME; typedef ... X509_NAME_ENTRY; typedef ... Cryptography_STACK_OF_X509_NAME; +typedef ... Cryptography_STACK_OF_X509_NAME_ENTRY; """ FUNCTIONS = """ @@ -32,6 +34,8 @@ unsigned long X509_NAME_hash(X509_NAME *); int i2d_X509_NAME(X509_NAME *, unsigned char **); int X509_NAME_add_entry_by_txt(X509_NAME *, const char *, int, const unsigned char *, int, int, int); +int X509_NAME_add_entry_by_OBJ(X509_NAME *, ASN1_OBJECT *, int, + unsigned char *, int, int, int); int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *, int, int, int); X509_NAME_ENTRY *X509_NAME_delete_entry(X509_NAME *, int); @@ -48,6 +52,9 @@ int sk_X509_NAME_num(Cryptography_STACK_OF_X509_NAME *); int sk_X509_NAME_push(Cryptography_STACK_OF_X509_NAME *, X509_NAME *); X509_NAME *sk_X509_NAME_value(Cryptography_STACK_OF_X509_NAME *, int); void sk_X509_NAME_free(Cryptography_STACK_OF_X509_NAME *); +int sk_X509_NAME_ENTRY_num(Cryptography_STACK_OF_X509_NAME_ENTRY *); +X509_NAME_ENTRY *sk_X509_NAME_ENTRY_value( + Cryptography_STACK_OF_X509_NAME_ENTRY *, int); """ CUSTOMIZATIONS = """ diff --git a/src/cryptography/hazmat/bindings/openssl/x509v3.py b/src/cryptography/hazmat/bindings/openssl/x509v3.py index c2b6860f..e9bc461a 100644 --- a/src/cryptography/hazmat/bindings/openssl/x509v3.py +++ b/src/cryptography/hazmat/bindings/openssl/x509v3.py @@ -20,10 +20,17 @@ typedef LHASH_OF(CONF_VALUE) Cryptography_LHASH_OF_CONF_VALUE; typedef LHASH Cryptography_LHASH_OF_CONF_VALUE; #endif typedef STACK_OF(ACCESS_DESCRIPTION) Cryptography_STACK_OF_ACCESS_DESCRIPTION; +typedef STACK_OF(DIST_POINT) Cryptography_STACK_OF_DIST_POINT; +typedef STACK_OF(POLICYQUALINFO) Cryptography_STACK_OF_POLICYQUALINFO; +typedef STACK_OF(POLICYINFO) Cryptography_STACK_OF_POLICYINFO; +typedef STACK_OF(ASN1_INTEGER) Cryptography_STACK_OF_ASN1_INTEGER; """ TYPES = """ typedef ... Cryptography_STACK_OF_ACCESS_DESCRIPTION; +typedef ... Cryptography_STACK_OF_POLICYQUALINFO; +typedef ... Cryptography_STACK_OF_POLICYINFO; +typedef ... Cryptography_STACK_OF_ASN1_INTEGER; typedef struct { X509 *issuer_cert; @@ -101,6 +108,49 @@ typedef struct { } ACCESS_DESCRIPTION; typedef ... Cryptography_LHASH_OF_CONF_VALUE; + + +typedef ... Cryptography_STACK_OF_DIST_POINT; + +typedef struct { + int type; + union { + GENERAL_NAMES *fullname; + Cryptography_STACK_OF_X509_NAME_ENTRY *relativename; + } name; + ...; +} DIST_POINT_NAME; + +typedef struct { + DIST_POINT_NAME *distpoint; + ASN1_BIT_STRING *reasons; + GENERAL_NAMES *CRLissuer; + ...; +} DIST_POINT; + +typedef struct { + ASN1_STRING *organization; + Cryptography_STACK_OF_ASN1_INTEGER *noticenos; +} NOTICEREF; + +typedef struct { + NOTICEREF *noticeref; + ASN1_STRING *exptext; +} USERNOTICE; + +typedef struct { + ASN1_OBJECT *pqualid; + union { + ASN1_IA5STRING *cpsuri; + USERNOTICE *usernotice; + ASN1_TYPE *other; + } d; +} POLICYQUALINFO; + +typedef struct { + ASN1_OBJECT *policyid; + Cryptography_STACK_OF_POLICYQUALINFO *qualifiers; +} POLICYINFO; """ @@ -116,20 +166,26 @@ void *X509V3_EXT_d2i(X509_EXTENSION *); MACROS = """ /* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the x509v3.h header. */ +int i2d_BASIC_CONSTRAINTS(BASIC_CONSTRAINTS *, unsigned char **); +BASIC_CONSTRAINTS *BASIC_CONSTRAINTS_new(void); void BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *); /* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the x509v3.h header. */ void AUTHORITY_KEYID_free(AUTHORITY_KEYID *); + void *X509V3_set_ctx_nodb(X509V3_CTX *); int sk_GENERAL_NAME_num(struct stack_st_GENERAL_NAME *); int sk_GENERAL_NAME_push(struct stack_st_GENERAL_NAME *, GENERAL_NAME *); GENERAL_NAME *sk_GENERAL_NAME_value(struct stack_st_GENERAL_NAME *, int); +Cryptography_STACK_OF_ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_new_null(void); int sk_ACCESS_DESCRIPTION_num(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_value( Cryptography_STACK_OF_ACCESS_DESCRIPTION *, int ); void sk_ACCESS_DESCRIPTION_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *); +int sk_ACCESS_DESCRIPTION_push(Cryptography_STACK_OF_ACCESS_DESCRIPTION *, + ACCESS_DESCRIPTION *); X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *, X509V3_CTX *, int, char *); @@ -138,6 +194,24 @@ X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *, const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *); const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int); +void sk_DIST_POINT_free(Cryptography_STACK_OF_DIST_POINT *); +int sk_DIST_POINT_num(Cryptography_STACK_OF_DIST_POINT *); +DIST_POINT *sk_DIST_POINT_value(Cryptography_STACK_OF_DIST_POINT *, int); + +void sk_POLICYINFO_free(Cryptography_STACK_OF_POLICYINFO *); +int sk_POLICYINFO_num(Cryptography_STACK_OF_POLICYINFO *); +POLICYINFO *sk_POLICYINFO_value(Cryptography_STACK_OF_POLICYINFO *, int); + +void sk_POLICYQUALINFO_free(Cryptography_STACK_OF_POLICYQUALINFO *); +int sk_POLICYQUALINFO_num(Cryptography_STACK_OF_POLICYQUALINFO *); +POLICYQUALINFO *sk_POLICYQUALINFO_value(Cryptography_STACK_OF_POLICYQUALINFO *, + int); + +void sk_ASN1_INTEGER_free(Cryptography_STACK_OF_ASN1_INTEGER *); +int sk_ASN1_INTEGER_num(Cryptography_STACK_OF_ASN1_INTEGER *); +ASN1_INTEGER *sk_ASN1_INTEGER_value(Cryptography_STACK_OF_ASN1_INTEGER *, int); + +X509_EXTENSION *X509V3_EXT_i2d(int, int, void *); """ CUSTOMIZATIONS = """ diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index 4d332f2a..733a967c 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -71,17 +71,6 @@ class DSAPrivateKeyWithSerialization(DSAPrivateKey): """ -DSAPrivateKeyWithNumbers = utils.deprecated( - DSAPrivateKeyWithSerialization, - __name__, - ( - "The DSAPrivateKeyWithNumbers interface has been renamed to " - "DSAPrivateKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - @six.add_metaclass(abc.ABCMeta) class DSAPublicKey(object): @abc.abstractproperty @@ -118,17 +107,6 @@ class DSAPublicKeyWithSerialization(DSAPublicKey): """ -DSAPublicKeyWithNumbers = utils.deprecated( - DSAPublicKeyWithSerialization, - __name__, - ( - "The DSAPublicKeyWithNumbers interface has been renamed to " - "DSAPublicKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - def generate_parameters(key_size, backend): return backend.generate_dsa_parameters(key_size) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index bf1705db..631fcbf7 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -71,17 +71,6 @@ class EllipticCurvePrivateKeyWithSerialization(EllipticCurvePrivateKey): """ -EllipticCurvePrivateKeyWithNumbers = utils.deprecated( - EllipticCurvePrivateKeyWithSerialization, - __name__, - ( - "The EllipticCurvePrivateKeyWithNumbers interface has been renamed to " - "EllipticCurvePrivateKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - @six.add_metaclass(abc.ABCMeta) class EllipticCurvePublicKey(object): @abc.abstractmethod @@ -112,17 +101,6 @@ class EllipticCurvePublicKeyWithSerialization(EllipticCurvePublicKey): """ -EllipticCurvePublicKeyWithNumbers = utils.deprecated( - EllipticCurvePublicKeyWithSerialization, - __name__, - ( - "The EllipticCurvePublicKeyWithNumbers interface has been renamed to " - "EllipticCurvePublicKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - @utils.register_interface(EllipticCurve) class SECT571R1(object): name = "sect571r1" @@ -202,6 +180,12 @@ class SECP256R1(object): @utils.register_interface(EllipticCurve) +class SECP256K1(object): + name = "secp256k1" + key_size = 256 + + +@utils.register_interface(EllipticCurve) class SECP224R1(object): name = "secp224r1" key_size = 224 @@ -222,6 +206,7 @@ _CURVE_TYPES = { "secp256r1": SECP256R1, "secp384r1": SECP384R1, "secp521r1": SECP521R1, + "secp256k1": SECP256K1, "sect163k1": SECT163K1, "sect233k1": SECT233K1, diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py index ae00184f..772473fd 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py @@ -56,17 +56,6 @@ class RSAPrivateKeyWithSerialization(RSAPrivateKey): """ -RSAPrivateKeyWithNumbers = utils.deprecated( - RSAPrivateKeyWithSerialization, - __name__, - ( - "The RSAPrivateKeyWithNumbers interface has been renamed to " - "RSAPrivateKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - @six.add_metaclass(abc.ABCMeta) class RSAPublicKey(object): @abc.abstractmethod @@ -103,17 +92,6 @@ class RSAPublicKeyWithSerialization(RSAPublicKey): """ -RSAPublicKeyWithNumbers = utils.deprecated( - RSAPublicKeyWithSerialization, - __name__, - ( - "The RSAPublicKeyWithNumbers interface has been renamed to " - "RSAPublicKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - - def generate_private_key(public_exponent, key_size, backend): if not isinstance(backend, RSABackend): raise UnsupportedAlgorithm( diff --git a/src/cryptography/hazmat/primitives/interfaces/__init__.py b/src/cryptography/hazmat/primitives/interfaces/__init__.py index c980e5a5..4c95190b 100644 --- a/src/cryptography/hazmat/primitives/interfaces/__init__.py +++ b/src/cryptography/hazmat/primitives/interfaces/__init__.py @@ -8,357 +8,6 @@ import abc import six -from cryptography import utils -from cryptography.hazmat.primitives import ciphers, hashes -from cryptography.hazmat.primitives.asymmetric import ( - AsymmetricSignatureContext, AsymmetricVerificationContext, dsa, ec, - padding, rsa -) -from cryptography.hazmat.primitives.ciphers import modes -from cryptography.hazmat.primitives.kdf import KeyDerivationFunction -from cryptography.hazmat.primitives.padding import PaddingContext - - -BlockCipherAlgorithm = utils.deprecated( - ciphers.BlockCipherAlgorithm, - __name__, - ( - "The BlockCipherAlgorithm interface has moved to the " - "cryptography.hazmat.primitives.ciphers module" - ), - utils.DeprecatedIn08 -) - - -CipherAlgorithm = utils.deprecated( - ciphers.CipherAlgorithm, - __name__, - ( - "The CipherAlgorithm interface has moved to the " - "cryptography.hazmat.primitives.ciphers module" - ), - utils.DeprecatedIn08 -) - - -Mode = utils.deprecated( - modes.Mode, - __name__, - ( - "The Mode interface has moved to the " - "cryptography.hazmat.primitives.ciphers.modes module" - ), - utils.DeprecatedIn08 -) - - -ModeWithAuthenticationTag = utils.deprecated( - modes.ModeWithAuthenticationTag, - __name__, - ( - "The ModeWithAuthenticationTag interface has moved to the " - "cryptography.hazmat.primitives.ciphers.modes module" - ), - utils.DeprecatedIn08 -) - - -ModeWithInitializationVector = utils.deprecated( - modes.ModeWithInitializationVector, - __name__, - ( - "The ModeWithInitializationVector interface has moved to the " - "cryptography.hazmat.primitives.ciphers.modes module" - ), - utils.DeprecatedIn08 -) - - -ModeWithNonce = utils.deprecated( - modes.ModeWithNonce, - __name__, - ( - "The ModeWithNonce interface has moved to the " - "cryptography.hazmat.primitives.ciphers.modes module" - ), - utils.DeprecatedIn08 -) - - -CipherContext = utils.deprecated( - ciphers.CipherContext, - __name__, - ( - "The CipherContext interface has moved to the " - "cryptography.hazmat.primitives.ciphers module" - ), - utils.DeprecatedIn08 -) - - -AEADCipherContext = utils.deprecated( - ciphers.AEADCipherContext, - __name__, - ( - "The AEADCipherContext interface has moved to the " - "cryptography.hazmat.primitives.ciphers module" - ), - utils.DeprecatedIn08 -) - - -AEADEncryptionContext = utils.deprecated( - ciphers.AEADEncryptionContext, - __name__, - ( - "The AEADEncryptionContext interface has moved to the " - "cryptography.hazmat.primitives.ciphers module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurve = utils.deprecated( - ec.EllipticCurve, - __name__, - ( - "The EllipticCurve interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurvePrivateKey = utils.deprecated( - ec.EllipticCurvePrivateKey, - __name__, - ( - "The EllipticCurvePrivateKey interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurvePrivateKeyWithNumbers = utils.deprecated( - ec.EllipticCurvePrivateKeyWithSerialization, - __name__, - ( - "The EllipticCurvePrivateKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurvePublicKey = utils.deprecated( - ec.EllipticCurvePublicKey, - __name__, - ( - "The EllipticCurvePublicKey interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurvePublicKeyWithNumbers = utils.deprecated( - ec.EllipticCurvePublicKeyWithSerialization, - __name__, - ( - "The EllipticCurvePublicKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -EllipticCurveSignatureAlgorithm = utils.deprecated( - ec.EllipticCurveSignatureAlgorithm, - __name__, - ( - "The EllipticCurveSignatureAlgorithm interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.ec module" - ), - utils.DeprecatedIn08 -) - - -DSAParameters = utils.deprecated( - dsa.DSAParameters, - __name__, - ( - "The DSAParameters interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - -DSAParametersWithNumbers = utils.deprecated( - dsa.DSAParametersWithNumbers, - __name__, - ( - "The DSAParametersWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - -DSAPrivateKey = utils.deprecated( - dsa.DSAPrivateKey, - __name__, - ( - "The DSAPrivateKey interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - -DSAPrivateKeyWithNumbers = utils.deprecated( - dsa.DSAPrivateKeyWithSerialization, - __name__, - ( - "The DSAPrivateKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - -DSAPublicKey = utils.deprecated( - dsa.DSAPublicKey, - __name__, - ( - "The DSAPublicKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - -DSAPublicKeyWithNumbers = utils.deprecated( - dsa.DSAPublicKeyWithSerialization, - __name__, - ( - "The DSAPublicKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.dsa.module" - ), - utils.DeprecatedIn08 -) - - -PaddingContext = utils.deprecated( - PaddingContext, - __name__, - ( - "The PaddingContext interface has moved to the " - "cryptography.hazmat.primitives.padding module" - ), - utils.DeprecatedIn08 -) - - -HashContext = utils.deprecated( - hashes.HashContext, - __name__, - ( - "The HashContext interface has moved to the " - "cryptography.hazmat.primitives.hashes module" - ), - utils.DeprecatedIn08 -) - - -HashAlgorithm = utils.deprecated( - hashes.HashAlgorithm, - __name__, - ( - "The HashAlgorithm interface has moved to the " - "cryptography.hazmat.primitives.hashes module" - ), - utils.DeprecatedIn08 -) - - -RSAPrivateKey = utils.deprecated( - rsa.RSAPrivateKey, - __name__, - ( - "The RSAPrivateKey interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.rsa module" - ), - utils.DeprecatedIn08 -) - -RSAPrivateKeyWithNumbers = utils.deprecated( - rsa.RSAPrivateKeyWithSerialization, - __name__, - ( - "The RSAPrivateKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.rsa module and has been " - "renamed RSAPrivateKeyWithSerialization" - ), - utils.DeprecatedIn08 -) - -RSAPublicKey = utils.deprecated( - rsa.RSAPublicKey, - __name__, - ( - "The RSAPublicKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.rsa module" - ), - utils.DeprecatedIn08 -) - -RSAPublicKeyWithNumbers = utils.deprecated( - rsa.RSAPublicKeyWithSerialization, - __name__, - ( - "The RSAPublicKeyWithNumbers interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.rsa module" - ), - utils.DeprecatedIn08 -) - -AsymmetricPadding = utils.deprecated( - padding.AsymmetricPadding, - __name__, - ( - "The AsymmetricPadding interface has moved to the " - "cryptography.hazmat.primitives.asymmetric.padding module" - ), - utils.DeprecatedIn08 -) - -AsymmetricSignatureContext = utils.deprecated( - AsymmetricSignatureContext, - __name__, - ( - "The AsymmetricPadding interface has moved to the " - "cryptography.hazmat.primitives.asymmetric module" - ), - utils.DeprecatedIn08 -) - -AsymmetricVerificationContext = utils.deprecated( - AsymmetricVerificationContext, - __name__, - ( - "The AsymmetricVerificationContext interface has moved to the " - "cryptography.hazmat.primitives.asymmetric module" - ), - utils.DeprecatedIn08 -) - -KeyDerivationFunction = utils.deprecated( - KeyDerivationFunction, - __name__, - ( - "The KeyDerivationFunction interface has moved to the " - "cryptography.hazmat.primitives.kdf module" - ), - utils.DeprecatedIn08 -) - @six.add_metaclass(abc.ABCMeta) class MACContext(object): diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py index 445554ec..0bf8c0ea 100644 --- a/src/cryptography/utils.py +++ b/src/cryptography/utils.py @@ -10,8 +10,7 @@ import sys import warnings -DeprecatedIn08 = DeprecationWarning -DeprecatedIn09 = PendingDeprecationWarning +DeprecatedIn09 = DeprecationWarning def read_only_property(name): diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 0d87cd51..6592684b 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -55,6 +55,9 @@ _OID_NAMES = { "2.5.29.17": "subjectAltName", "2.5.29.18": "issuerAltName", "2.5.29.19": "basicConstraints", + "2.5.29.21": "cRLReason", + "2.5.29.24": "invalidityDate", + "2.5.29.29": "certificateIssuer", "2.5.29.30": "nameConstraints", "2.5.29.31": "cRLDistributionPoints", "2.5.29.32": "certificatePolicies", @@ -69,6 +72,8 @@ _OID_NAMES = { "1.3.6.1.5.5.7.48.1.5": "OCSPNoCheck", "1.3.6.1.5.5.7.48.1": "OCSP", "1.3.6.1.5.5.7.48.2": "caIssuers", + "1.3.6.1.5.5.7.2.1": "id-qt-cps", + "1.3.6.1.5.5.7.2.2": "id-qt-unotice", } @@ -222,6 +227,9 @@ OID_KEY_USAGE = ObjectIdentifier("2.5.29.15") OID_SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17") OID_ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18") OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19") +OID_CRL_REASON = ObjectIdentifier("2.5.29.21") +OID_INVALIDITY_DATE = ObjectIdentifier("2.5.29.24") +OID_CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29") OID_NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30") OID_CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31") OID_CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32") @@ -276,6 +284,19 @@ class Extension(object): return ("<Extension(oid={0.oid}, critical={0.critical}, " "value={0.value})>").format(self) + def __eq__(self, other): + if not isinstance(other, Extension): + return NotImplemented + + return ( + self.oid == other.oid and + self.critical == other.critical and + self.value == other.value + ) + + def __ne__(self, other): + return not self == other + class ExtendedKeyUsage(object): def __init__(self, usages): @@ -305,6 +326,10 @@ class ExtendedKeyUsage(object): return not self == other +class OCSPNoCheck(object): + pass + + class BasicConstraints(object): def __init__(self, ca, path_length): if not isinstance(ca, bool): @@ -331,6 +356,15 @@ class BasicConstraints(object): return ("<BasicConstraints(ca={0.ca}, " "path_length={0.path_length})>").format(self) + def __eq__(self, other): + if not isinstance(other, BasicConstraints): + return NotImplemented + + return self.ca == other.ca and self.path_length == other.path_length + + def __ne__(self, other): + return not self == other + class KeyUsage(object): def __init__(self, digital_signature, content_commitment, key_encipherment, @@ -395,6 +429,25 @@ class KeyUsage(object): "encipher_only={1}, decipher_only={2})>").format( self, encipher_only, decipher_only) + def __eq__(self, other): + if not isinstance(other, KeyUsage): + return NotImplemented + + return ( + self.digital_signature == other.digital_signature and + self.content_commitment == other.content_commitment and + self.key_encipherment == other.key_encipherment and + self.data_encipherment == other.data_encipherment and + self.key_agreement == other.key_agreement and + self.key_cert_sign == other.key_cert_sign and + self.crl_sign == other.crl_sign and + self._encipher_only == other._encipher_only and + self._decipher_only == other._decipher_only + ) + + def __ne__(self, other): + return not self == other + class AuthorityInformationAccess(object): def __init__(self, descriptions): @@ -460,6 +513,143 @@ class AccessDescription(object): access_location = utils.read_only_property("_access_location") +class CertificatePolicies(object): + def __init__(self, policies): + if not all(isinstance(x, PolicyInformation) for x in policies): + raise TypeError( + "Every item in the policies list must be a " + "PolicyInformation" + ) + + self._policies = policies + + def __iter__(self): + return iter(self._policies) + + def __len__(self): + return len(self._policies) + + def __repr__(self): + return "<CertificatePolicies({0})>".format(self._policies) + + def __eq__(self, other): + if not isinstance(other, CertificatePolicies): + return NotImplemented + + return self._policies == other._policies + + def __ne__(self, other): + return not self == other + + +class PolicyInformation(object): + def __init__(self, policy_identifier, policy_qualifiers): + if not isinstance(policy_identifier, ObjectIdentifier): + raise TypeError("policy_identifier must be an ObjectIdentifier") + + self._policy_identifier = policy_identifier + if policy_qualifiers and not all( + isinstance( + x, (six.text_type, UserNotice) + ) for x in policy_qualifiers + ): + raise TypeError( + "policy_qualifiers must be a list of strings and/or UserNotice" + " objects or None" + ) + + self._policy_qualifiers = policy_qualifiers + + def __repr__(self): + return ( + "<PolicyInformation(policy_identifier={0.policy_identifier}, polic" + "y_qualifiers={0.policy_qualifiers})>".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, PolicyInformation): + return NotImplemented + + return ( + self.policy_identifier == other.policy_identifier and + self.policy_qualifiers == other.policy_qualifiers + ) + + def __ne__(self, other): + return not self == other + + policy_identifier = utils.read_only_property("_policy_identifier") + policy_qualifiers = utils.read_only_property("_policy_qualifiers") + + +class UserNotice(object): + def __init__(self, notice_reference, explicit_text): + if notice_reference and not isinstance( + notice_reference, NoticeReference + ): + raise TypeError( + "notice_reference must be None or a NoticeReference" + ) + + self._notice_reference = notice_reference + self._explicit_text = explicit_text + + def __repr__(self): + return ( + "<UserNotice(notice_reference={0.notice_reference}, explicit_text=" + "{0.explicit_text!r})>".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, UserNotice): + return NotImplemented + + return ( + self.notice_reference == other.notice_reference and + self.explicit_text == other.explicit_text + ) + + def __ne__(self, other): + return not self == other + + notice_reference = utils.read_only_property("_notice_reference") + explicit_text = utils.read_only_property("_explicit_text") + + +class NoticeReference(object): + def __init__(self, organization, notice_numbers): + self._organization = organization + if not isinstance(notice_numbers, list) or not all( + isinstance(x, int) for x in notice_numbers + ): + raise TypeError( + "notice_numbers must be a list of integers" + ) + + self._notice_numbers = notice_numbers + + def __repr__(self): + return ( + "<NoticeReference(organization={0.organization!r}, notice_numbers=" + "{0.notice_numbers})>".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, NoticeReference): + return NotImplemented + + return ( + self.organization == other.organization and + self.notice_numbers == other.notice_numbers + ) + + def __ne__(self, other): + return not self == other + + organization = utils.read_only_property("_organization") + notice_numbers = utils.read_only_property("_notice_numbers") + + class SubjectKeyIdentifier(object): def __init__(self, digest): self._digest = digest @@ -481,6 +671,151 @@ class SubjectKeyIdentifier(object): return not self == other +class CRLDistributionPoints(object): + def __init__(self, distribution_points): + if not all( + isinstance(x, DistributionPoint) for x in distribution_points + ): + raise TypeError( + "distribution_points must be a list of DistributionPoint " + "objects" + ) + + self._distribution_points = distribution_points + + def __iter__(self): + return iter(self._distribution_points) + + def __len__(self): + return len(self._distribution_points) + + def __repr__(self): + return "<CRLDistributionPoints({0})>".format(self._distribution_points) + + def __eq__(self, other): + if not isinstance(other, CRLDistributionPoints): + return NotImplemented + + return self._distribution_points == other._distribution_points + + def __ne__(self, other): + return not self == other + + +class DistributionPoint(object): + def __init__(self, full_name, relative_name, reasons, crl_issuer): + if full_name and relative_name: + raise ValueError( + "At least one of full_name and relative_name must be None" + ) + + if full_name and not all( + isinstance(x, GeneralName) for x in full_name + ): + raise TypeError( + "full_name must be a list of GeneralName objects" + ) + + if relative_name and not isinstance(relative_name, Name): + raise TypeError("relative_name must be a Name") + + if crl_issuer and not all( + isinstance(x, GeneralName) for x in crl_issuer + ): + raise TypeError( + "crl_issuer must be None or a list of general names" + ) + + if reasons and (not isinstance(reasons, frozenset) or not all( + isinstance(x, ReasonFlags) for x in reasons + )): + raise TypeError("reasons must be None or frozenset of ReasonFlags") + + if reasons and ( + ReasonFlags.unspecified in reasons or + ReasonFlags.remove_from_crl in reasons + ): + raise ValueError( + "unspecified and remove_from_crl are not valid reasons in a " + "DistributionPoint" + ) + + if reasons and not crl_issuer and not (full_name or relative_name): + raise ValueError( + "You must supply crl_issuer, full_name, or relative_name when " + "reasons is not None" + ) + + self._full_name = full_name + self._relative_name = relative_name + self._reasons = reasons + self._crl_issuer = crl_issuer + + def __repr__(self): + return ( + "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela" + "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_is" + "suer})>".format(self) + ) + + def __eq__(self, other): + if not isinstance(other, DistributionPoint): + return NotImplemented + + return ( + self.full_name == other.full_name and + self.relative_name == other.relative_name and + self.reasons == other.reasons and + self.crl_issuer == other.crl_issuer + ) + + def __ne__(self, other): + return not self == other + + full_name = utils.read_only_property("_full_name") + relative_name = utils.read_only_property("_relative_name") + reasons = utils.read_only_property("_reasons") + crl_issuer = utils.read_only_property("_crl_issuer") + + +class ReasonFlags(Enum): + unspecified = "unspecified" + key_compromise = "keyCompromise" + ca_compromise = "cACompromise" + affiliation_changed = "affiliationChanged" + superseded = "superseded" + cessation_of_operation = "cessationOfOperation" + certificate_hold = "certificateHold" + privilege_withdrawn = "privilegeWithdrawn" + aa_compromise = "aACompromise" + remove_from_crl = "removeFromCRL" + + +class InhibitAnyPolicy(object): + def __init__(self, skip_certs): + if not isinstance(skip_certs, six.integer_types): + raise TypeError("skip_certs must be an integer") + + if skip_certs < 0: + raise ValueError("skip_certs must be a non-negative integer") + + self._skip_certs = skip_certs + + def __repr__(self): + return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self) + + def __eq__(self, other): + if not isinstance(other, InhibitAnyPolicy): + return NotImplemented + + return self.skip_certs == other.skip_certs + + def __ne__(self, other): + return not self == other + + skip_certs = utils.read_only_property("_skip_certs") + + @six.add_metaclass(abc.ABCMeta) class GeneralName(object): @abc.abstractproperty @@ -609,11 +944,18 @@ class RegisteredID(object): class IPAddress(object): def __init__(self, value): if not isinstance( - value, (ipaddress.IPv4Address, ipaddress.IPv6Address) + value, + ( + ipaddress.IPv4Address, + ipaddress.IPv6Address, + ipaddress.IPv4Network, + ipaddress.IPv6Network + ) ): raise TypeError( - "value must be an instance of ipaddress.IPv4Address or " - "ipaddress.IPv6Address" + "value must be an instance of ipaddress.IPv4Address, " + "ipaddress.IPv6Address, ipaddress.IPv4Network, or " + "ipaddress.IPv6Network" ) self._value = value @@ -633,7 +975,7 @@ class IPAddress(object): return not self == other -class SubjectAlternativeName(object): +class GeneralNames(object): def __init__(self, general_names): if not all(isinstance(x, GeneralName) for x in general_names): raise TypeError( @@ -653,8 +995,43 @@ class SubjectAlternativeName(object): return [i.value for i in self if isinstance(i, type)] def __repr__(self): + return "<GeneralNames({0})>".format(self._general_names) + + def __eq__(self, other): + if not isinstance(other, GeneralNames): + return NotImplemented + + return self._general_names == other._general_names + + def __ne__(self, other): + return not self == other + + +class SubjectAlternativeName(object): + def __init__(self, general_names): + self._general_names = GeneralNames(general_names) + + def __iter__(self): + return iter(self._general_names) + + def __len__(self): + return len(self._general_names) + + def get_values_for_type(self, type): + return self._general_names.get_values_for_type(type) + + def __repr__(self): return "<SubjectAlternativeName({0})>".format(self._general_names) + def __eq__(self, other): + if not isinstance(other, SubjectAlternativeName): + return NotImplemented + + return self._general_names == other._general_names + + def __ne__(self, other): + return not self == other + class AuthorityKeyIdentifier(object): def __init__(self, key_identifier, authority_cert_issuer, @@ -691,6 +1068,20 @@ class AuthorityKeyIdentifier(object): ")>".format(self) ) + def __eq__(self, other): + if not isinstance(other, AuthorityKeyIdentifier): + return NotImplemented + + return ( + self.key_identifier == other.key_identifier and + self.authority_cert_issuer == other.authority_cert_issuer and + self.authority_cert_serial_number == + other.authority_cert_serial_number + ) + + def __ne__(self, other): + return not self == other + key_identifier = utils.read_only_property("_key_identifier") authority_cert_issuer = utils.read_only_property("_authority_cert_issuer") authority_cert_serial_number = utils.read_only_property( @@ -754,6 +1145,10 @@ OID_OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9") OID_CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2") OID_OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1") +OID_CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1") +OID_CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2") +OID_ANY_POLICY = ObjectIdentifier("2.5.29.32.0") + @six.add_metaclass(abc.ABCMeta) class Certificate(object): @@ -812,6 +1207,77 @@ class Certificate(object): in the certificate. """ + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Checks equality. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Checks not equal. + """ + + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Serializes the certificate to PEM or DER format. + """ + + +@six.add_metaclass(abc.ABCMeta) +class CertificateRevocationList(object): + + @abc.abstractmethod + def fingerprint(self, algorithm): + """ + Returns bytes using digest passed. + """ + + @abc.abstractproperty + def signature_hash_algorithm(self): + """ + Returns a HashAlgorithm corresponding to the type of the digest signed + in the certificate. + """ + + @abc.abstractproperty + def issuer(self): + """ + Returns the X509Name with the issuer of this CRL. + """ + + @abc.abstractproperty + def next_update(self): + """ + Returns the date of next update for this CRL. + """ + + @abc.abstractproperty + def last_update(self): + """ + Returns the date of last update for this CRL. + """ + + @abc.abstractproperty + def revoked_certificates(self): + """ + Returns a list of RevokedCertificate objects for this CRL. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object containing a list of CRL extensions. + """ + @abc.abstractmethod def __eq__(self, other): """ @@ -845,3 +1311,36 @@ class CertificateSigningRequest(object): Returns a HashAlgorithm corresponding to the type of the digest signed in the certificate. """ + + @abc.abstractproperty + def extensions(self): + """ + Returns the extensions in the signing request. + """ + + @abc.abstractmethod + def public_bytes(self, encoding): + """ + Encodes the request to PEM or DER format. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RevokedCertificate(object): + @abc.abstractproperty + def serial_number(self): + """ + Returns the serial number of the revoked certificate. + """ + + @abc.abstractproperty + def revocation_date(self): + """ + Returns the date of when this certificate was revoked. + """ + + @abc.abstractproperty + def extensions(self): + """ + Returns an Extensions object containing a list of Revoked extensions. + """ |