diff options
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/backend.py | 20 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/x509.py | 97 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/serialization.py | 4 |
3 files changed, 120 insertions, 1 deletions
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) |