diff options
Diffstat (limited to 'src/cryptography/hazmat/backends/openssl/x509.py')
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 157 |
1 files changed, 94 insertions, 63 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index ac1838c6d..4d0dac764 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -6,31 +6,43 @@ from __future__ import absolute_import, division, print_function import datetime import operator -import warnings from cryptography import utils, x509 from cryptography.exceptions import UnsupportedAlgorithm from cryptography.hazmat.backends.openssl.decode_asn1 import ( - _CERTIFICATE_EXTENSION_PARSER, _CERTIFICATE_EXTENSION_PARSER_NO_SCT, - _CRL_EXTENSION_PARSER, _CSR_EXTENSION_PARSER, - _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int, - _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time + _asn1_integer_to_int, + _asn1_string_to_bytes, + _decode_x509_name, + _obj2txt, + _parse_asn1_time, ) from cryptography.hazmat.backends.openssl.encode_asn1 import ( - _encode_asn1_int_gc + _encode_asn1_int_gc, + _txt2obj_gc, ) from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.x509.name import _ASN1Type @utils.register_interface(x509.Certificate) class _Certificate(object): - def __init__(self, backend, x509): + def __init__(self, backend, x509_cert): self._backend = backend - self._x509 = x509 + self._x509 = x509_cert + + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + self._version = x509.Version.v1 + elif version == 2: + self._version = x509.Version.v3 + else: + raise x509.InvalidVersion( + "{} is not a valid X509 version".format(version), version + ) def __repr__(self): - return "<Certificate(subject={0}, ...)>".format(self.subject) + return "<Certificate(subject={}, ...)>".format(self.subject) def __eq__(self, other): if not isinstance(other, x509.Certificate): @@ -45,31 +57,15 @@ class _Certificate(object): def __hash__(self): return hash(self.public_bytes(serialization.Encoding.DER)) + def __deepcopy__(self, memo): + return self + def fingerprint(self, algorithm): h = hashes.Hash(algorithm, self._backend) h.update(self.public_bytes(serialization.Encoding.DER)) return h.finalize() - @property - def version(self): - version = self._backend._lib.X509_get_version(self._x509) - if version == 0: - return x509.Version.v1 - elif version == 2: - return x509.Version.v3 - else: - raise x509.InvalidVersion( - "{0} is not a valid X509 version".format(version), version - ) - - @property - def serial(self): - warnings.warn( - "Certificate serial is deprecated, use serial_number instead.", - utils.PersistentlyDeprecated, - stacklevel=2 - ) - return self.serial_number + version = utils.read_only_property("_version") @property def serial_number(self): @@ -90,12 +86,12 @@ class _Certificate(object): @property def not_valid_before(self): - asn1_time = self._backend._lib.X509_get_notBefore(self._x509) + asn1_time = self._backend._lib.X509_getm_notBefore(self._x509) return _parse_asn1_time(self._backend, asn1_time) @property def not_valid_after(self): - asn1_time = self._backend._lib.X509_get_notAfter(self._x509) + asn1_time = self._backend._lib.X509_getm_notAfter(self._x509) return _parse_asn1_time(self._backend, asn1_time) @property @@ -117,7 +113,7 @@ class _Certificate(object): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -132,14 +128,7 @@ class _Certificate(object): @utils.cached_property def extensions(self): - if self._backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER: - return _CERTIFICATE_EXTENSION_PARSER.parse( - self._backend, self._x509 - ) - else: - return _CERTIFICATE_EXTENSION_PARSER_NO_SCT.parse( - self._backend, self._x509 - ) + return self._backend._certificate_extension_parser.parse(self._x509) @property def signature(self): @@ -201,13 +190,13 @@ class _RevokedCertificate(object): self._backend, self._backend._lib.X509_REVOKED_get0_revocationDate( self._x509_revoked - ) + ), ) @utils.cached_property def extensions(self): - return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse( - self._backend, self._x509_revoked + return self._backend._revoked_cert_extension_parser.parse( + self._x509_revoked ) @@ -230,9 +219,7 @@ class _CertificateRevocationList(object): def fingerprint(self, algorithm): h = hashes.Hash(algorithm, self._backend) bio = self._backend._create_mem_bio_gc() - res = self._backend._lib.i2d_X509_CRL_bio( - bio, self._x509_crl - ) + res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) self._backend.openssl_assert(res == 1) der = self._backend._read_mem_bio(bio) h.update(der) @@ -257,9 +244,7 @@ class _CertificateRevocationList(object): if res == 0: return None else: - self._backend.openssl_assert( - revoked[0] != self._backend._ffi.NULL - ) + self._backend.openssl_assert(revoked[0] != self._backend._ffi.NULL) return _RevokedCertificate( self._backend, self._sorted_crl, revoked[0] ) @@ -271,7 +256,7 @@ class _CertificateRevocationList(object): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -366,13 +351,17 @@ class _CertificateRevocationList(object): @utils.cached_property def extensions(self): - return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl) + return self._backend._crl_extension_parser.parse(self._x509_crl) def is_signature_valid(self, public_key): - if not isinstance(public_key, (dsa.DSAPublicKey, rsa.RSAPublicKey, - ec.EllipticCurvePublicKey)): - raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,' - ' or EllipticCurvePublicKey.') + if not isinstance( + public_key, + (dsa.DSAPublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " or EllipticCurvePublicKey." + ) res = self._backend._lib.X509_CRL_verify( self._x509_crl, public_key._evp_pkey ) @@ -423,7 +412,7 @@ class _CertificateSigningRequest(object): return x509._SIG_OIDS_TO_HASH[oid] except KeyError: raise UnsupportedAlgorithm( - "Signature algorithm OID:{0} not recognized".format(oid) + "Signature algorithm OID:{} not recognized".format(oid) ) @property @@ -442,12 +431,13 @@ class _CertificateSigningRequest(object): x509_exts = self._backend._ffi.gc( x509_exts, lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free( - x, self._backend._ffi.addressof( + x, + self._backend._ffi.addressof( self._backend._lib._original_lib, "X509_EXTENSION_free" - ) - ) + ), + ), ) - return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts) + return self._backend._csr_extension_parser.parse(x509_exts) def public_bytes(self, encoding): bio = self._backend._create_mem_bio_gc() @@ -495,6 +485,47 @@ class _CertificateSigningRequest(object): return True + def get_attribute_for_oid(self, oid): + obj = _txt2obj_gc(self._backend, oid.dotted_string) + pos = self._backend._lib.X509_REQ_get_attr_by_OBJ( + self._x509_req, obj, -1 + ) + if pos == -1: + raise x509.AttributeNotFound( + "No {} attribute was found".format(oid), oid + ) + + attr = self._backend._lib.X509_REQ_get_attr(self._x509_req, pos) + self._backend.openssl_assert(attr != self._backend._ffi.NULL) + # We don't support multiple valued attributes for now. + self._backend.openssl_assert( + self._backend._lib.X509_ATTRIBUTE_count(attr) == 1 + ) + asn1_type = self._backend._lib.X509_ATTRIBUTE_get0_type(attr, 0) + self._backend.openssl_assert(asn1_type != self._backend._ffi.NULL) + # We need this to ensure that our C type cast is safe. + # Also this should always be a sane string type, but we'll see if + # that is true in the real world... + if asn1_type.type not in ( + _ASN1Type.UTF8String.value, + _ASN1Type.PrintableString.value, + _ASN1Type.IA5String.value, + ): + raise ValueError( + "OID {} has a disallowed ASN.1 type: {}".format( + oid, asn1_type.type + ) + ) + + data = self._backend._lib.X509_ATTRIBUTE_get0_data( + attr, 0, asn1_type.type, self._backend._ffi.NULL + ) + self._backend.openssl_assert(data != self._backend._ffi.NULL) + # This cast is safe iff we assert on the type above to ensure + # that it is always a type of ASN1_STRING + data = self._backend._ffi.cast("ASN1_STRING *", data) + return _asn1_string_to_bytes(self._backend, data) + @utils.register_interface( x509.certificate_transparency.SignedCertificateTimestamp @@ -523,9 +554,9 @@ class _SignedCertificateTimestamp(object): def timestamp(self): timestamp = self._backend._lib.SCT_get_timestamp(self._sct) milliseconds = timestamp % 1000 - return datetime.datetime.utcfromtimestamp( - timestamp // 1000 - ).replace(microsecond=milliseconds * 1000) + return datetime.datetime.utcfromtimestamp(timestamp // 1000).replace( + microsecond=milliseconds * 1000 + ) @property def entry_type(self): |