From f83c749ceba71729c2ad9ae549bebdc5bdf63a29 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 24 Nov 2014 17:12:46 -1000 Subject: initial x509 openssl implementation --- .../hazmat/backends/openssl/backend.py | 20 ++++- src/cryptography/hazmat/backends/openssl/x509.py | 97 ++++++++++++++++++++++ .../hazmat/primitives/serialization.py | 4 + 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 src/cryptography/hazmat/backends/openssl/x509.py (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index ebe38e20..ceb10cfc 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -19,7 +19,7 @@ from cryptography.hazmat.backends.interfaces import ( CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, PEMSerializationBackend, PKCS8SerializationBackend, RSABackend, - TraditionalOpenSSLSerializationBackend + TraditionalOpenSSLSerializationBackend, X509Backend ) from cryptography.hazmat.backends.openssl.ciphers import ( _AESCTRCipherContext, _CipherContext @@ -36,6 +36,7 @@ from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.rsa import ( _RSAPrivateKey, _RSAPublicKey ) +from cryptography.hazmat.backends.openssl.x509 import _X509Certificate from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa @@ -66,6 +67,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError", @utils.register_interface(RSABackend) @utils.register_interface(TraditionalOpenSSLSerializationBackend) @utils.register_interface(PEMSerializationBackend) +@utils.register_interface(X509Backend) class Backend(object): """ OpenSSL API binding interfaces. @@ -675,6 +677,22 @@ class Backend(object): None, ) + def load_pem_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.PEM_read_bio_X509( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + assert x509 != self._ffi.NULL + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _X509Certificate(self, x509) + + def load_der_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) + assert x509 != self._ffi.NULL + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _X509Certificate(self, x509) + def load_traditional_openssl_pem_private_key(self, data, password): warnings.warn( "load_traditional_openssl_pem_private_key is deprecated and will " diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py new file mode 100644 index 00000000..8dced83b --- /dev/null +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -0,0 +1,97 @@ +# 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. + +from __future__ import absolute_import, division, print_function + +import datetime + +from cryptography import utils +from cryptography.hazmat.primitives import hashes, interfaces + + +@utils.register_interface(interfaces.X509Certificate) +class _X509Certificate(object): + def __init__(self, backend, x509): + self._backend = backend + self._x509 = x509 + + def _create_bio(self): + bio_method = self._backend._lib.BIO_s_mem() + assert bio_method != self._backend._ffi.NULL + bio = self._backend._lib.BIO_new(bio_method) + assert bio != self._backend._ffi.NULL + bio = self._backend._ffi.gc(bio, self._backend._lib.BIO_free) + return bio + + def _read_bio(self, bio): + buf = self._backend._ffi.new("char **") + buf_len = self._backend._lib.BIO_get_mem_data(bio, buf) + assert buf_len > 0 + assert buf[0] != self._backend._ffi.NULL + bio_data = self._backend._ffi.buffer(buf[0], buf_len)[:] + return bio_data + + def fingerprint(self, algorithm): + h = hashes.Hash(algorithm, self._backend) + bio = self._create_bio() + res = self._backend._lib.i2d_X509_bio( + bio, self._x509 + ) + assert res == 1 + der = self._read_bio(bio) + h.update(der) + return h.finalize() + + @property + 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 + serial = self._backend._lib.BN_bn2hex(bn) + assert serial != self._backend._ffi.NULL + return int(self._backend._ffi.string(serial), 16) + + def public_key(self): + pkey = self._backend._lib.X509_get_pubkey(self._x509) + assert pkey != self._backend._ffi.NULL + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + return self._backend._evp_pkey_to_public_key(pkey) + + @property + def not_before(self): + asn1_time = self._backend._lib.X509_get_notBefore(self._x509) + return self._parse_asn1_time(asn1_time) + + @property + def not_after(self): + asn1_time = self._backend._lib.X509_get_notAfter(self._x509) + return self._parse_asn1_time(asn1_time) + + def _parse_asn1_time(self, asn1_time): + assert asn1_time != self._backend._ffi.NULL + generalized_time = self._backend._lib.ASN1_TIME_to_generalizedtime( + asn1_time, self._backend._ffi.NULL + ) + assert generalized_time != self._backend._ffi.NULL + generalized_time = self._backend._ffi.gc( + generalized_time, self._backend._lib.ASN1_GENERALIZEDTIME_free + ) + time = self._backend._ffi.string( + self._backend._lib.ASN1_STRING_data( + self._backend._ffi.cast("ASN1_STRING *", generalized_time) + ) + ) + return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 0dbbc85c..077d56a5 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -116,3 +116,7 @@ else: data = data[4:] return result + + +def load_pem_x509_certificate(data, backend): + return backend.load_pem_x509_certificate(data) -- cgit v1.2.3 From a1426f0afc61e4d94be012700c37e2a1a8f4fab6 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Tue, 25 Nov 2014 20:35:20 -1000 Subject: initial x509 version support Adds enum34 as a dependency --- src/cryptography/hazmat/backends/openssl/x509.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 8dced83b..9f12da0e 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -16,7 +16,7 @@ from __future__ import absolute_import, division, print_function import datetime from cryptography import utils -from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.primitives import hashes, interfaces, x509 @utils.register_interface(interfaces.X509Certificate) @@ -52,6 +52,16 @@ class _X509Certificate(object): h.update(der) return h.finalize() + @property + def version(self): + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + return x509.X509Version.v1 + elif version == 2: + return x509.X509Version.v3 + else: + raise StandardError("TODO") + @property def serial(self): asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) -- cgit v1.2.3 From 016e08abddf9fdc507da4f6c6f548c3dfee1b389 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 26 Nov 2014 09:41:18 -1000 Subject: move x509 to top level, add more docs --- src/cryptography/hazmat/backends/openssl/x509.py | 4 ++-- .../hazmat/primitives/serialization.py | 4 ---- src/cryptography/x509.py | 23 ++++++++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/cryptography/x509.py (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 9f12da0e..0c6395f4 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -15,8 +15,8 @@ from __future__ import absolute_import, division, print_function import datetime -from cryptography import utils -from cryptography.hazmat.primitives import hashes, interfaces, x509 +from cryptography import utils, x509 +from cryptography.hazmat.primitives import hashes, interfaces @utils.register_interface(interfaces.X509Certificate) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 077d56a5..0dbbc85c 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -116,7 +116,3 @@ else: data = data[4:] return result - - -def load_pem_x509_certificate(data, backend): - return backend.load_pem_x509_certificate(data) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py new file mode 100644 index 00000000..b7220239 --- /dev/null +++ b/src/cryptography/x509.py @@ -0,0 +1,23 @@ +# 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 + +from enum import Enum + + +# TODO: document this +class X509Version(Enum): + v1 = 0 + v3 = 2 + + +# TODO: document this +def load_pem_x509_certificate(data, backend): + return backend.load_pem_x509_certificate(data) + + +# TODO: document this +def load_der_x509_certificate(data, backend): + return backend.load_der_x509_certificate(data) -- cgit v1.2.3 From a9d78c13ea2996c896d3dfda8b7e887c444ec4cb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 26 Nov 2014 10:59:03 -1000 Subject: update docs, test invalid x509 version --- src/cryptography/exceptions.py | 4 ++++ src/cryptography/hazmat/backends/openssl/x509.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index b0e1a993..23edcd02 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -53,3 +53,7 @@ class InvalidKey(Exception): class InvalidToken(Exception): pass + + +class InvalidX509Version(Exception): + pass diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 0c6395f4..9f6f71d0 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -16,6 +16,7 @@ from __future__ import absolute_import, division, print_function import datetime from cryptography import utils, x509 +from cryptography.exceptions import InvalidX509Version from cryptography.hazmat.primitives import hashes, interfaces @@ -60,7 +61,9 @@ class _X509Certificate(object): elif version == 2: return x509.X509Version.v3 else: - raise StandardError("TODO") + raise InvalidX509Version( + "{0} is not a valid X509 version", version + ) @property def serial(self): -- cgit v1.2.3 From 7638c3151ccbc17ff1adee0384b1fa10530cf87c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 26 Nov 2014 11:13:31 -1000 Subject: improve x509 load error handling --- src/cryptography/hazmat/backends/openssl/backend.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index ceb10cfc..19d149b5 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -682,14 +682,20 @@ class Backend(object): x509 = self._lib.PEM_read_bio_X509( mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL ) - assert x509 != self._ffi.NULL + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load certificate") + x509 = self._ffi.gc(x509, self._lib.X509_free) return _X509Certificate(self, x509) def load_der_x509_certificate(self, data): mem_bio = self._bytes_to_bio(data) x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) - assert x509 != self._ffi.NULL + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load certificate") + x509 = self._ffi.gc(x509, self._lib.X509_free) return _X509Certificate(self, x509) -- cgit v1.2.3 From 1eb5b86f86758a8247b742c580cc7163b89a1e7a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Wed, 26 Nov 2014 11:44:03 -1000 Subject: improve tests, remove some outdated comments --- src/cryptography/x509.py | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index b7220239..f3c73d6b 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -7,17 +7,14 @@ from __future__ import absolute_import, division, print_function from enum import Enum -# TODO: document this class X509Version(Enum): v1 = 0 v3 = 2 -# TODO: document this def load_pem_x509_certificate(data, backend): return backend.load_pem_x509_certificate(data) -# TODO: document this def load_der_x509_certificate(data, backend): return backend.load_der_x509_certificate(data) -- cgit v1.2.3 From a68fd33ca8518a734b655457eca9ab28ccbcb7bb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 27 Nov 2014 07:08:40 -1000 Subject: address review feedback --- src/cryptography/exceptions.py | 4 ---- src/cryptography/hazmat/backends/openssl/x509.py | 5 ++--- src/cryptography/x509.py | 4 ++++ 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py index 23edcd02..b0e1a993 100644 --- a/src/cryptography/exceptions.py +++ b/src/cryptography/exceptions.py @@ -53,7 +53,3 @@ class InvalidKey(Exception): class InvalidToken(Exception): pass - - -class InvalidX509Version(Exception): - pass diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 9f6f71d0..6befc3cf 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -16,7 +16,6 @@ from __future__ import absolute_import, division, print_function import datetime from cryptography import utils, x509 -from cryptography.exceptions import InvalidX509Version from cryptography.hazmat.primitives import hashes, interfaces @@ -61,8 +60,8 @@ class _X509Certificate(object): elif version == 2: return x509.X509Version.v3 else: - raise InvalidX509Version( - "{0} is not a valid X509 version", version + raise x509.InvalidX509Version( + "{0} is not a valid X509 version".format(version) ) @property diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index f3c73d6b..191666e6 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -18,3 +18,7 @@ def load_pem_x509_certificate(data, backend): def load_der_x509_certificate(data, backend): return backend.load_der_x509_certificate(data) + + +class InvalidX509Version(Exception): + pass -- cgit v1.2.3 From a693cfdfb5e55f92f21cd7b2aa52f332679f241f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 27 Nov 2014 07:47:58 -1000 Subject: py3 fixes --- src/cryptography/hazmat/backends/openssl/x509.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 6befc3cf..4126a397 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -105,5 +105,5 @@ class _X509Certificate(object): self._backend._lib.ASN1_STRING_data( self._backend._ffi.cast("ASN1_STRING *", generalized_time) ) - ) + ).decode("ascii") return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") -- cgit v1.2.3 From d9fc7252f9470f6f9f6c05047e2fcf1c5c34667a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 Dec 2014 12:25:00 -0600 Subject: change it to not_valid_* why not --- src/cryptography/hazmat/backends/openssl/x509.py | 4 ++-- src/cryptography/hazmat/primitives/interfaces.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 4126a397..a348630f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -83,12 +83,12 @@ class _X509Certificate(object): return self._backend._evp_pkey_to_public_key(pkey) @property - def not_before(self): + def not_valid_before(self): asn1_time = self._backend._lib.X509_get_notBefore(self._x509) return self._parse_asn1_time(asn1_time) @property - def not_after(self): + def not_valid_after(self): asn1_time = self._backend._lib.X509_get_notAfter(self._x509) return self._parse_asn1_time(asn1_time) diff --git a/src/cryptography/hazmat/primitives/interfaces.py b/src/cryptography/hazmat/primitives/interfaces.py index 18a62601..76616e1f 100644 --- a/src/cryptography/hazmat/primitives/interfaces.py +++ b/src/cryptography/hazmat/primitives/interfaces.py @@ -517,13 +517,13 @@ class X509Certificate(object): """ @abc.abstractproperty - def not_before(self): + def not_valid_before(self): """ Not before time (represented as UTC datetime) """ @abc.abstractproperty - def not_after(self): + def not_valid_after(self): """ Not after time (represented as UTC datetime) """ -- cgit v1.2.3 From 68481c3e78d08b7defdd716b72b7563fb0ee5469 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 Dec 2014 14:44:32 -0600 Subject: move mem_bio creation/reading to backend --- .../hazmat/backends/openssl/backend.py | 22 ++++++++++++++++++++++ src/cryptography/hazmat/backends/openssl/x509.py | 20 ++------------------ 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 19d149b5..10341fa2 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -447,6 +447,28 @@ class Backend(object): return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_char_p) + def _create_mem_bio(self): + """ + Creates an empty memory BIO. + """ + bio_method = self._lib.BIO_s_mem() + assert bio_method != self._ffi.NULL + bio = self._lib.BIO_new(bio_method) + assert bio != self._ffi.NULL + bio = self._ffi.gc(bio, self._lib.BIO_free) + return bio + + def _read_mem_bio(self, bio): + """ + Reads a memory BIO. This only works on memory BIOs. + """ + buf = self._ffi.new("char **") + buf_len = self._lib.BIO_get_mem_data(bio, buf) + assert buf_len > 0 + assert buf[0] != self._ffi.NULL + bio_data = self._ffi.buffer(buf[0], buf_len)[:] + return bio_data + def _evp_pkey_to_private_key(self, evp_pkey): """ Return the appropriate type of PrivateKey given an evp_pkey cdata diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index a348630f..532785ac 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -25,30 +25,14 @@ class _X509Certificate(object): self._backend = backend self._x509 = x509 - def _create_bio(self): - bio_method = self._backend._lib.BIO_s_mem() - assert bio_method != self._backend._ffi.NULL - bio = self._backend._lib.BIO_new(bio_method) - assert bio != self._backend._ffi.NULL - bio = self._backend._ffi.gc(bio, self._backend._lib.BIO_free) - return bio - - def _read_bio(self, bio): - buf = self._backend._ffi.new("char **") - buf_len = self._backend._lib.BIO_get_mem_data(bio, buf) - assert buf_len > 0 - assert buf[0] != self._backend._ffi.NULL - bio_data = self._backend._ffi.buffer(buf[0], buf_len)[:] - return bio_data - def fingerprint(self, algorithm): h = hashes.Hash(algorithm, self._backend) - bio = self._create_bio() + bio = self._backend._create_mem_bio() res = self._backend._lib.i2d_X509_bio( bio, self._x509 ) assert res == 1 - der = self._read_bio(bio) + der = self._backend._read_mem_bio(bio) h.update(der) return h.finalize() -- cgit v1.2.3 From b2de948b18316ac5f08b22d1ab22bdd49da9cc5f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 Dec 2014 14:54:48 -0600 Subject: reorganize a bunch of things related to the x509certificate interface --- src/cryptography/hazmat/backends/openssl/x509.py | 4 +-- src/cryptography/x509.py | 42 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 532785ac..35313b25 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -16,10 +16,10 @@ from __future__ import absolute_import, division, print_function import datetime from cryptography import utils, x509 -from cryptography.hazmat.primitives import hashes, interfaces +from cryptography.hazmat.primitives import hashes -@utils.register_interface(interfaces.X509Certificate) +@utils.register_interface(x509.X509Certificate) class _X509Certificate(object): def __init__(self, backend, x509): self._backend = backend diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index 191666e6..ed754cbc 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -4,8 +4,11 @@ from __future__ import absolute_import, division, print_function +import abc from enum import Enum +import six + class X509Version(Enum): v1 = 0 @@ -22,3 +25,42 @@ def load_der_x509_certificate(data, backend): class InvalidX509Version(Exception): pass + + +@six.add_metaclass(abc.ABCMeta) +class X509Certificate(object): + @abc.abstractmethod + def fingerprint(self, algorithm): + """ + Returns bytes using digest passed. + """ + + @abc.abstractproperty + def serial(self): + """ + Returns certificate serial number + """ + + @abc.abstractproperty + def version(self): + """ + Returns the certificate version + """ + + @abc.abstractmethod + def public_key(self): + """ + Returns the public key + """ + + @abc.abstractproperty + def not_valid_before(self): + """ + Not before time (represented as UTC datetime) + """ + + @abc.abstractproperty + def not_valid_after(self): + """ + Not after time (represented as UTC datetime) + """ -- cgit v1.2.3 From b2a2050ba84e9cc2499711e24deede7cb446c516 Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Thu, 11 Dec 2014 15:26:21 -0600 Subject: simplify serial conversion --- src/cryptography/hazmat/backends/openssl/x509.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 35313b25..383322ad 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -56,9 +56,8 @@ class _X509Certificate(object): asn1_int, self._backend._ffi.NULL ) assert bn != self._backend._ffi.NULL - serial = self._backend._lib.BN_bn2hex(bn) - assert serial != self._backend._ffi.NULL - return int(self._backend._ffi.string(serial), 16) + bn = self._backend._ffi.gc(bn, self._backend._lib.BN_free) + return self._backend._bn_to_int(bn) def public_key(self): pkey = self._backend._lib.X509_get_pubkey(self._x509) -- cgit v1.2.3 From ca941e612ada82ac4d1fb20e979200746eb0a7dc Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 12 Dec 2014 10:49:20 -0600 Subject: try using ASN1_TIME_print to get ASN1_TIME data --- src/cryptography/hazmat/backends/openssl/x509.py | 19 +++++-------------- src/cryptography/hazmat/bindings/openssl/asn1.py | 1 + 2 files changed, 6 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 383322ad..fa4d1a01 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -76,17 +76,8 @@ class _X509Certificate(object): return self._parse_asn1_time(asn1_time) def _parse_asn1_time(self, asn1_time): - assert asn1_time != self._backend._ffi.NULL - generalized_time = self._backend._lib.ASN1_TIME_to_generalizedtime( - asn1_time, self._backend._ffi.NULL - ) - assert generalized_time != self._backend._ffi.NULL - generalized_time = self._backend._ffi.gc( - generalized_time, self._backend._lib.ASN1_GENERALIZEDTIME_free - ) - time = self._backend._ffi.string( - self._backend._lib.ASN1_STRING_data( - self._backend._ffi.cast("ASN1_STRING *", generalized_time) - ) - ).decode("ascii") - return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") + bio = self._backend._create_mem_bio() + res = self._backend._lib.ASN1_TIME_print(bio, asn1_time) + assert res == 1 + time = self._backend._read_mem_bio(bio) + return datetime.datetime.strptime(time, "%b %d %H:%M:%S %Y GMT") diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index a73dc325..37f95e7e 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -97,6 +97,7 @@ ASN1_TIME *ASN1_TIME_new(void); void ASN1_TIME_free(ASN1_TIME *); ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, ASN1_GENERALIZEDTIME **); +int ASN1_TIME_print(BIO *, const ASN1_TIME *); /* ASN1 UTCTIME */ int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); -- cgit v1.2.3 From d273adeae286186a71d38856dc2c2cea4acd378a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 12 Dec 2014 11:15:07 -0600 Subject: move to macros due to const/non-const --- src/cryptography/hazmat/bindings/openssl/asn1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index 37f95e7e..7fe01fbc 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -97,7 +97,6 @@ ASN1_TIME *ASN1_TIME_new(void); void ASN1_TIME_free(ASN1_TIME *); ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *, ASN1_GENERALIZEDTIME **); -int ASN1_TIME_print(BIO *, const ASN1_TIME *); /* ASN1 UTCTIME */ int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t); @@ -121,6 +120,7 @@ const ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *); /* These aren't macros these arguments are all const X on openssl > 1.0.x */ +int ASN1_TIME_print(BIO *, const ASN1_TIME *); int ASN1_STRING_length(ASN1_STRING *); ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *); int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *); -- cgit v1.2.3 From 6c660a88f1ed6d03968b26328a285cfecc4c9a2c Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 12 Dec 2014 11:50:44 -0600 Subject: raise error on unnamed EC curve certificates when calling public_key ...for now --- src/cryptography/hazmat/backends/openssl/x509.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index fa4d1a01..1de3f4d5 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -63,6 +63,26 @@ class _X509Certificate(object): pkey = self._backend._lib.X509_get_pubkey(self._x509) assert pkey != self._backend._ffi.NULL pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + # The following check is to find ECDSA certificates with unnamed + # curves and raise an error for now. + if ( + self._backend._lib.Cryptography_HAS_EC == 1 and + pkey.type == self._backend._lib.EVP_PKEY_EC + ): + ec_cdata = self._backend._lib.EVP_PKEY_get1_EC_KEY(pkey) + assert ec_cdata != self._backend._ffi.NULL + ec_cdata = self._backend._ffi.gc( + ec_cdata, self._backend._lib.EC_KEY_free + ) + group = self._backend._lib.EC_KEY_get0_group(ec_cdata) + assert group != self._backend._ffi.NULL + nid = self._backend._lib.EC_GROUP_get_curve_name(group) + if nid == self._backend._lib.NID_undef: + raise NotImplementedError( + "ECDSA certificates without named curves are unsupported " + "at this time" + ) + return self._backend._evp_pkey_to_public_key(pkey) @property -- cgit v1.2.3 From 9d0b7d420b3c32d8759a89cb37df83f2aa1ea75f Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Fri, 12 Dec 2014 12:08:33 -0600 Subject: sigh --- src/cryptography/hazmat/backends/openssl/x509.py | 2 +- src/cryptography/hazmat/bindings/openssl/asn1.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 1de3f4d5..17dd098f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -99,5 +99,5 @@ class _X509Certificate(object): bio = self._backend._create_mem_bio() res = self._backend._lib.ASN1_TIME_print(bio, asn1_time) assert res == 1 - time = self._backend._read_mem_bio(bio) + time = self._backend._read_mem_bio(bio).decode("ascii") return datetime.datetime.strptime(time, "%b %d %H:%M:%S %Y GMT") diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py index 7fe01fbc..5b1a56f2 100644 --- a/src/cryptography/hazmat/bindings/openssl/asn1.py +++ b/src/cryptography/hazmat/bindings/openssl/asn1.py @@ -120,7 +120,7 @@ const ASN1_ITEM *ASN1_ITEM_ptr(ASN1_ITEM_EXP *); /* These aren't macros these arguments are all const X on openssl > 1.0.x */ -int ASN1_TIME_print(BIO *, const ASN1_TIME *); +int ASN1_TIME_print(BIO *, ASN1_TIME *); int ASN1_STRING_length(ASN1_STRING *); ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *); int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *); -- cgit v1.2.3 From e76cd27c28f75f3972ddcf5e15d5e37e6da2098e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Sun, 14 Dec 2014 19:00:51 -0600 Subject: rename X509 classes to remove X509 and improve some tests --- src/cryptography/hazmat/backends/openssl/backend.py | 6 +++--- src/cryptography/hazmat/backends/openssl/x509.py | 10 +++++----- src/cryptography/x509.py | 6 +++--- 3 files changed, 11 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 10341fa2..daccf5ca 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -36,7 +36,7 @@ from cryptography.hazmat.backends.openssl.hmac import _HMACContext from cryptography.hazmat.backends.openssl.rsa import ( _RSAPrivateKey, _RSAPublicKey ) -from cryptography.hazmat.backends.openssl.x509 import _X509Certificate +from cryptography.hazmat.backends.openssl.x509 import _Certificate from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import hashes from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa @@ -709,7 +709,7 @@ class Backend(object): raise ValueError("Unable to load certificate") x509 = self._ffi.gc(x509, self._lib.X509_free) - return _X509Certificate(self, x509) + return _Certificate(self, x509) def load_der_x509_certificate(self, data): mem_bio = self._bytes_to_bio(data) @@ -719,7 +719,7 @@ class Backend(object): raise ValueError("Unable to load certificate") x509 = self._ffi.gc(x509, self._lib.X509_free) - return _X509Certificate(self, x509) + return _Certificate(self, x509) def load_traditional_openssl_pem_private_key(self, data, password): warnings.warn( diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 17dd098f..26c5edc2 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -19,8 +19,8 @@ from cryptography import utils, x509 from cryptography.hazmat.primitives import hashes -@utils.register_interface(x509.X509Certificate) -class _X509Certificate(object): +@utils.register_interface(x509.Certificate) +class _Certificate(object): def __init__(self, backend, x509): self._backend = backend self._x509 = x509 @@ -40,11 +40,11 @@ class _X509Certificate(object): def version(self): version = self._backend._lib.X509_get_version(self._x509) if version == 0: - return x509.X509Version.v1 + return x509.Version.v1 elif version == 2: - return x509.X509Version.v3 + return x509.Version.v3 else: - raise x509.InvalidX509Version( + raise x509.InvalidVersion( "{0} is not a valid X509 version".format(version) ) diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index ed754cbc..c79d1171 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -10,7 +10,7 @@ from enum import Enum import six -class X509Version(Enum): +class Version(Enum): v1 = 0 v3 = 2 @@ -23,12 +23,12 @@ def load_der_x509_certificate(data, backend): return backend.load_der_x509_certificate(data) -class InvalidX509Version(Exception): +class InvalidVersion(Exception): pass @six.add_metaclass(abc.ABCMeta) -class X509Certificate(object): +class Certificate(object): @abc.abstractmethod def fingerprint(self, algorithm): """ -- cgit v1.2.3 From 233f911c2ee46f3d9cdf7b15c6ccc3cc79552a9a Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 15 Dec 2014 16:27:36 -0600 Subject: revert asn1 time parsing to avoid locale problems --- src/cryptography/hazmat/backends/openssl/x509.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 26c5edc2..01055c5f 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -96,8 +96,17 @@ class _Certificate(object): return self._parse_asn1_time(asn1_time) def _parse_asn1_time(self, asn1_time): - bio = self._backend._create_mem_bio() - res = self._backend._lib.ASN1_TIME_print(bio, asn1_time) - assert res == 1 - time = self._backend._read_mem_bio(bio).decode("ascii") - return datetime.datetime.strptime(time, "%b %d %H:%M:%S %Y GMT") + assert asn1_time != self._backend._ffi.NULL + generalized_time = self._backend._lib.ASN1_TIME_to_generalizedtime( + asn1_time, self._backend._ffi.NULL + ) + assert generalized_time != self._backend._ffi.NULL + generalized_time = self._backend._ffi.gc( + generalized_time, self._backend._lib.ASN1_GENERALIZEDTIME_free + ) + time = self._backend._ffi.string( + self._backend._lib.ASN1_STRING_data( + self._backend._ffi.cast("ASN1_STRING *", generalized_time) + ) + ).decode("ascii") + return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") -- cgit v1.2.3 From 25014658d6d7df3a97f72a5a65c6833a3364c51e Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 15 Dec 2014 16:49:41 -0600 Subject: update error msg text based on feedback --- src/cryptography/hazmat/backends/openssl/x509.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 01055c5f..9a1fcc8d 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -79,7 +79,7 @@ class _Certificate(object): nid = self._backend._lib.EC_GROUP_get_curve_name(group) if nid == self._backend._lib.NID_undef: raise NotImplementedError( - "ECDSA certificates without named curves are unsupported " + "ECDSA certificates with unnamed curves are unsupported " "at this time" ) -- cgit v1.2.3 From d5cccf7a376f4cf81cab6649646af0f09f5389ac Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 15 Dec 2014 17:20:33 -0600 Subject: add parsed_version attribute to InvalidVersion --- src/cryptography/hazmat/backends/openssl/x509.py | 2 +- src/cryptography/x509.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py index 9a1fcc8d..0828f3cc 100644 --- a/src/cryptography/hazmat/backends/openssl/x509.py +++ b/src/cryptography/hazmat/backends/openssl/x509.py @@ -45,7 +45,7 @@ class _Certificate(object): return x509.Version.v3 else: raise x509.InvalidVersion( - "{0} is not a valid X509 version".format(version) + "{0} is not a valid X509 version".format(version), version ) @property diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py index c79d1171..be1298b6 100644 --- a/src/cryptography/x509.py +++ b/src/cryptography/x509.py @@ -24,7 +24,9 @@ def load_der_x509_certificate(data, backend): class InvalidVersion(Exception): - pass + def __init__(self, msg, parsed_version): + super(InvalidVersion, self).__init__(msg) + self.parsed_version = parsed_version @six.add_metaclass(abc.ABCMeta) -- cgit v1.2.3