aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/__about__.py31
-rw-r--r--src/cryptography/__init__.py25
-rw-r--r--src/cryptography/exceptions.py63
-rw-r--r--src/cryptography/fernet.py150
-rw-r--r--src/cryptography/hazmat/__init__.py14
-rw-r--r--src/cryptography/hazmat/backends/__init__.py46
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/__init__.py19
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/backend.py253
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/ciphers.py201
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/hashes.py64
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/hmac.py68
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py261
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py358
-rw-r--r--src/cryptography/hazmat/backends/openssl/__init__.py19
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py1036
-rw-r--r--src/cryptography/hazmat/backends/openssl/ciphers.py225
-rw-r--r--src/cryptography/hazmat/backends/openssl/cmac.py89
-rw-r--r--src/cryptography/hazmat/backends/openssl/dsa.py207
-rw-r--r--src/cryptography/hazmat/backends/openssl/ec.py234
-rw-r--r--src/cryptography/hazmat/backends/openssl/hashes.py71
-rw-r--r--src/cryptography/hazmat/backends/openssl/hmac.py90
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py603
-rw-r--r--src/cryptography/hazmat/backends/openssl/utils.py35
-rw-r--r--src/cryptography/hazmat/bindings/__init__.py14
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/__init__.py14
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/binding.py60
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/cf.py114
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py110
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/common_digest.py69
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/common_hmac.py48
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py50
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/secimport.py95
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/secitem.py38
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/seckey.py35
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/seckeychain.py36
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/sectransform.py79
-rw-r--r--src/cryptography/hazmat/bindings/openssl/__init__.py14
-rw-r--r--src/cryptography/hazmat/bindings/openssl/aes.py70
-rw-r--r--src/cryptography/hazmat/bindings/openssl/asn1.py152
-rw-r--r--src/cryptography/hazmat/bindings/openssl/bignum.py114
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py176
-rw-r--r--src/cryptography/hazmat/bindings/openssl/bio.py181
-rw-r--r--src/cryptography/hazmat/bindings/openssl/cmac.py65
-rw-r--r--src/cryptography/hazmat/bindings/openssl/cms.py100
-rw-r--r--src/cryptography/hazmat/bindings/openssl/conf.py35
-rw-r--r--src/cryptography/hazmat/bindings/openssl/crypto.py67
-rw-r--r--src/cryptography/hazmat/bindings/openssl/dh.py57
-rw-r--r--src/cryptography/hazmat/bindings/openssl/dsa.py65
-rw-r--r--src/cryptography/hazmat/bindings/openssl/ec.py490
-rw-r--r--src/cryptography/hazmat/bindings/openssl/ecdh.py68
-rw-r--r--src/cryptography/hazmat/bindings/openssl/ecdsa.py130
-rw-r--r--src/cryptography/hazmat/bindings/openssl/engine.py165
-rw-r--r--src/cryptography/hazmat/bindings/openssl/err.py365
-rw-r--r--src/cryptography/hazmat/bindings/openssl/evp.py263
-rw-r--r--src/cryptography/hazmat/bindings/openssl/hmac.py94
-rw-r--r--src/cryptography/hazmat/bindings/openssl/nid.py241
-rw-r--r--src/cryptography/hazmat/bindings/openssl/objects.py45
-rw-r--r--src/cryptography/hazmat/bindings/openssl/opensslv.py36
-rw-r--r--src/cryptography/hazmat/bindings/openssl/osrandom_engine.py218
-rw-r--r--src/cryptography/hazmat/bindings/openssl/pem.py89
-rw-r--r--src/cryptography/hazmat/bindings/openssl/pkcs12.py41
-rw-r--r--src/cryptography/hazmat/bindings/openssl/pkcs7.py41
-rw-r--r--src/cryptography/hazmat/bindings/openssl/rand.py45
-rw-r--r--src/cryptography/hazmat/bindings/openssl/rsa.py108
-rw-r--r--src/cryptography/hazmat/bindings/openssl/ssl.py620
-rw-r--r--src/cryptography/hazmat/bindings/openssl/x509.py273
-rw-r--r--src/cryptography/hazmat/bindings/openssl/x509_vfy.py336
-rw-r--r--src/cryptography/hazmat/bindings/openssl/x509name.py61
-rw-r--r--src/cryptography/hazmat/bindings/openssl/x509v3.py103
-rw-r--r--src/cryptography/hazmat/bindings/utils.py144
-rw-r--r--src/cryptography/hazmat/primitives/__init__.py14
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/__init__.py14
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dsa.py108
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/ec.py195
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/padding.py65
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/rsa.py191
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/__init__.py21
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/algorithms.py147
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/base.py132
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/modes.py125
-rw-r--r--src/cryptography/hazmat/primitives/cmac.py75
-rw-r--r--src/cryptography/hazmat/primitives/constant_time.py47
-rw-r--r--src/cryptography/hazmat/primitives/hashes.py121
-rw-r--r--src/cryptography/hazmat/primitives/hmac.py78
-rw-r--r--src/cryptography/hazmat/primitives/interfaces.py499
-rw-r--r--src/cryptography/hazmat/primitives/kdf/__init__.py14
-rw-r--r--src/cryptography/hazmat/primitives/kdf/hkdf.py124
-rw-r--r--src/cryptography/hazmat/primitives/kdf/pbkdf2.py66
-rw-r--r--src/cryptography/hazmat/primitives/padding.py164
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py50
-rw-r--r--src/cryptography/hazmat/primitives/src/constant_time.c31
-rw-r--r--src/cryptography/hazmat/primitives/src/constant_time.h16
-rw-r--r--src/cryptography/hazmat/primitives/twofactor/__init__.py14
-rw-r--r--src/cryptography/hazmat/primitives/twofactor/hotp.py69
-rw-r--r--src/cryptography/hazmat/primitives/twofactor/totp.py41
-rw-r--r--src/cryptography/utils.py64
96 files changed, 12481 insertions, 0 deletions
diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py
new file mode 100644
index 00000000..3d39d18b
--- /dev/null
+++ b/src/cryptography/__about__.py
@@ -0,0 +1,31 @@
+# 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
+
+__all__ = [
+ "__title__", "__summary__", "__uri__", "__version__", "__author__",
+ "__email__", "__license__", "__copyright__",
+]
+
+__title__ = "cryptography"
+__summary__ = ("cryptography is a package which provides cryptographic recipes"
+ " and primitives to Python developers.")
+__uri__ = "https://github.com/pyca/cryptography"
+
+__version__ = "0.7.dev1"
+
+__author__ = "The cryptography developers"
+__email__ = "cryptography-dev@python.org"
+
+__license__ = "BSD or Apache License, Version 2.0"
+__copyright__ = "Copyright 2013-2014 {0}".format(__author__)
diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py
new file mode 100644
index 00000000..f27ba856
--- /dev/null
+++ b/src/cryptography/__init__.py
@@ -0,0 +1,25 @@
+# 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
+
+from cryptography.__about__ import (
+ __author__, __copyright__, __email__, __license__, __summary__, __title__,
+ __uri__, __version__
+)
+
+
+__all__ = [
+ "__title__", "__summary__", "__uri__", "__version__", "__author__",
+ "__email__", "__license__", "__copyright__",
+]
diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py
new file mode 100644
index 00000000..c14763f7
--- /dev/null
+++ b/src/cryptography/exceptions.py
@@ -0,0 +1,63 @@
+# 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
+
+
+class _Reasons(object):
+ BACKEND_MISSING_INTERFACE = object()
+ UNSUPPORTED_HASH = object()
+ UNSUPPORTED_CIPHER = object()
+ UNSUPPORTED_PADDING = object()
+ UNSUPPORTED_MGF = object()
+ UNSUPPORTED_PUBLIC_KEY_ALGORITHM = object()
+ UNSUPPORTED_ELLIPTIC_CURVE = object()
+ UNSUPPORTED_SERIALIZATION = object()
+
+
+class UnsupportedAlgorithm(Exception):
+ def __init__(self, message, reason=None):
+ super(UnsupportedAlgorithm, self).__init__(message)
+ self._reason = reason
+
+
+class AlreadyFinalized(Exception):
+ pass
+
+
+class AlreadyUpdated(Exception):
+ pass
+
+
+class NotYetFinalized(Exception):
+ pass
+
+
+class InvalidTag(Exception):
+ pass
+
+
+class InvalidSignature(Exception):
+ pass
+
+
+class InternalError(Exception):
+ pass
+
+
+class InvalidKey(Exception):
+ pass
+
+
+class InvalidToken(Exception):
+ pass
diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py
new file mode 100644
index 00000000..4f98feec
--- /dev/null
+++ b/src/cryptography/fernet.py
@@ -0,0 +1,150 @@
+# 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 base64
+import binascii
+import os
+import struct
+import time
+
+import six
+
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.primitives import hashes, padding
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.primitives.hmac import HMAC
+
+
+class InvalidToken(Exception):
+ pass
+
+
+_MAX_CLOCK_SKEW = 60
+
+
+class Fernet(object):
+ def __init__(self, key, backend=None):
+ if backend is None:
+ backend = default_backend()
+
+ key = base64.urlsafe_b64decode(key)
+ if len(key) != 32:
+ raise ValueError(
+ "Fernet key must be 32 url-safe base64-encoded bytes."
+ )
+
+ self._signing_key = key[:16]
+ self._encryption_key = key[16:]
+ self._backend = backend
+
+ @classmethod
+ def generate_key(cls):
+ return base64.urlsafe_b64encode(os.urandom(32))
+
+ def encrypt(self, data):
+ current_time = int(time.time())
+ iv = os.urandom(16)
+ return self._encrypt_from_parts(data, current_time, iv)
+
+ def _encrypt_from_parts(self, data, current_time, iv):
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+
+ padder = padding.PKCS7(algorithms.AES.block_size).padder()
+ padded_data = padder.update(data) + padder.finalize()
+ encryptor = Cipher(
+ algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend
+ ).encryptor()
+ ciphertext = encryptor.update(padded_data) + encryptor.finalize()
+
+ basic_parts = (
+ b"\x80" + struct.pack(">Q", current_time) + iv + ciphertext
+ )
+
+ h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
+ h.update(basic_parts)
+ hmac = h.finalize()
+ return base64.urlsafe_b64encode(basic_parts + hmac)
+
+ def decrypt(self, token, ttl=None):
+ if not isinstance(token, bytes):
+ raise TypeError("token must be bytes.")
+
+ current_time = int(time.time())
+
+ try:
+ data = base64.urlsafe_b64decode(token)
+ except (TypeError, binascii.Error):
+ raise InvalidToken
+
+ if not data or six.indexbytes(data, 0) != 0x80:
+ raise InvalidToken
+
+ try:
+ timestamp, = struct.unpack(">Q", data[1:9])
+ except struct.error:
+ raise InvalidToken
+ if ttl is not None:
+ if timestamp + ttl < current_time:
+ raise InvalidToken
+ if current_time + _MAX_CLOCK_SKEW < timestamp:
+ raise InvalidToken
+ h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
+ h.update(data[:-32])
+ try:
+ h.verify(data[-32:])
+ except InvalidSignature:
+ raise InvalidToken
+
+ iv = data[9:25]
+ ciphertext = data[25:-32]
+ decryptor = Cipher(
+ algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend
+ ).decryptor()
+ plaintext_padded = decryptor.update(ciphertext)
+ try:
+ plaintext_padded += decryptor.finalize()
+ except ValueError:
+ raise InvalidToken
+ unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
+
+ unpadded = unpadder.update(plaintext_padded)
+ try:
+ unpadded += unpadder.finalize()
+ except ValueError:
+ raise InvalidToken
+ return unpadded
+
+
+class MultiFernet(object):
+ def __init__(self, fernets):
+ fernets = list(fernets)
+ if not fernets:
+ raise ValueError(
+ "MultiFernet requires at least one Fernet instance"
+ )
+ self._fernets = fernets
+
+ def encrypt(self, msg):
+ return self._fernets[0].encrypt(msg)
+
+ def decrypt(self, msg, ttl=None):
+ for f in self._fernets:
+ try:
+ return f.decrypt(msg, ttl)
+ except InvalidToken:
+ pass
+ raise InvalidToken
diff --git a/src/cryptography/hazmat/__init__.py b/src/cryptography/hazmat/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py
new file mode 100644
index 00000000..b0f663fe
--- /dev/null
+++ b/src/cryptography/hazmat/backends/__init__.py
@@ -0,0 +1,46 @@
+# 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 pkg_resources
+
+from cryptography.hazmat.backends.multibackend import MultiBackend
+
+
+_available_backends_list = None
+
+
+def _available_backends():
+ global _available_backends_list
+
+ if _available_backends_list is None:
+ _available_backends_list = [
+ backend.load(require=False)
+ for backend in pkg_resources.iter_entry_points(
+ "cryptography.backends"
+ )
+ ]
+
+ return _available_backends_list
+
+_default_backend = None
+
+
+def default_backend():
+ global _default_backend
+
+ if _default_backend is None:
+ _default_backend = MultiBackend(_available_backends())
+
+ return _default_backend
diff --git a/src/cryptography/hazmat/backends/commoncrypto/__init__.py b/src/cryptography/hazmat/backends/commoncrypto/__init__.py
new file mode 100644
index 00000000..f080394f
--- /dev/null
+++ b/src/cryptography/hazmat/backends/commoncrypto/__init__.py
@@ -0,0 +1,19 @@
+# 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
+
+from cryptography.hazmat.backends.commoncrypto.backend import backend
+
+
+__all__ = ["backend"]
diff --git a/src/cryptography/hazmat/backends/commoncrypto/backend.py b/src/cryptography/hazmat/backends/commoncrypto/backend.py
new file mode 100644
index 00000000..7bab979f
--- /dev/null
+++ b/src/cryptography/hazmat/backends/commoncrypto/backend.py
@@ -0,0 +1,253 @@
+# 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
+
+from collections import namedtuple
+
+from cryptography import utils
+from cryptography.exceptions import InternalError
+from cryptography.hazmat.backends.commoncrypto.ciphers import (
+ _CipherContext, _GCMCipherContext
+)
+from cryptography.hazmat.backends.commoncrypto.hashes import _HashContext
+from cryptography.hazmat.backends.commoncrypto.hmac import _HMACContext
+from cryptography.hazmat.backends.interfaces import (
+ CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend
+)
+from cryptography.hazmat.bindings.commoncrypto.binding import Binding
+from cryptography.hazmat.primitives.ciphers.algorithms import (
+ AES, ARC4, Blowfish, CAST5, TripleDES
+)
+from cryptography.hazmat.primitives.ciphers.modes import (
+ CBC, CFB, CFB8, CTR, ECB, GCM, OFB
+)
+
+
+HashMethods = namedtuple(
+ "HashMethods", ["ctx", "hash_init", "hash_update", "hash_final"]
+)
+
+
+@utils.register_interface(CipherBackend)
+@utils.register_interface(HashBackend)
+@utils.register_interface(HMACBackend)
+@utils.register_interface(PBKDF2HMACBackend)
+class Backend(object):
+ """
+ CommonCrypto API wrapper.
+ """
+ name = "commoncrypto"
+
+ def __init__(self):
+ self._binding = Binding()
+ self._ffi = self._binding.ffi
+ self._lib = self._binding.lib
+
+ self._cipher_registry = {}
+ self._register_default_ciphers()
+ self._hash_mapping = {
+ "md5": HashMethods(
+ "CC_MD5_CTX *", self._lib.CC_MD5_Init,
+ self._lib.CC_MD5_Update, self._lib.CC_MD5_Final
+ ),
+ "sha1": HashMethods(
+ "CC_SHA1_CTX *", self._lib.CC_SHA1_Init,
+ self._lib.CC_SHA1_Update, self._lib.CC_SHA1_Final
+ ),
+ "sha224": HashMethods(
+ "CC_SHA256_CTX *", self._lib.CC_SHA224_Init,
+ self._lib.CC_SHA224_Update, self._lib.CC_SHA224_Final
+ ),
+ "sha256": HashMethods(
+ "CC_SHA256_CTX *", self._lib.CC_SHA256_Init,
+ self._lib.CC_SHA256_Update, self._lib.CC_SHA256_Final
+ ),
+ "sha384": HashMethods(
+ "CC_SHA512_CTX *", self._lib.CC_SHA384_Init,
+ self._lib.CC_SHA384_Update, self._lib.CC_SHA384_Final
+ ),
+ "sha512": HashMethods(
+ "CC_SHA512_CTX *", self._lib.CC_SHA512_Init,
+ self._lib.CC_SHA512_Update, self._lib.CC_SHA512_Final
+ ),
+ }
+
+ self._supported_hmac_algorithms = {
+ "md5": self._lib.kCCHmacAlgMD5,
+ "sha1": self._lib.kCCHmacAlgSHA1,
+ "sha224": self._lib.kCCHmacAlgSHA224,
+ "sha256": self._lib.kCCHmacAlgSHA256,
+ "sha384": self._lib.kCCHmacAlgSHA384,
+ "sha512": self._lib.kCCHmacAlgSHA512,
+ }
+
+ self._supported_pbkdf2_hmac_algorithms = {
+ "sha1": self._lib.kCCPRFHmacAlgSHA1,
+ "sha224": self._lib.kCCPRFHmacAlgSHA224,
+ "sha256": self._lib.kCCPRFHmacAlgSHA256,
+ "sha384": self._lib.kCCPRFHmacAlgSHA384,
+ "sha512": self._lib.kCCPRFHmacAlgSHA512,
+ }
+
+ def hash_supported(self, algorithm):
+ return algorithm.name in self._hash_mapping
+
+ def hmac_supported(self, algorithm):
+ return algorithm.name in self._supported_hmac_algorithms
+
+ def create_hash_ctx(self, algorithm):
+ return _HashContext(self, algorithm)
+
+ def create_hmac_ctx(self, key, algorithm):
+ return _HMACContext(self, key, algorithm)
+
+ def cipher_supported(self, cipher, mode):
+ return (type(cipher), type(mode)) in self._cipher_registry
+
+ def create_symmetric_encryption_ctx(self, cipher, mode):
+ if isinstance(mode, GCM):
+ return _GCMCipherContext(
+ self, cipher, mode, self._lib.kCCEncrypt
+ )
+ else:
+ return _CipherContext(self, cipher, mode, self._lib.kCCEncrypt)
+
+ def create_symmetric_decryption_ctx(self, cipher, mode):
+ if isinstance(mode, GCM):
+ return _GCMCipherContext(
+ self, cipher, mode, self._lib.kCCDecrypt
+ )
+ else:
+ return _CipherContext(self, cipher, mode, self._lib.kCCDecrypt)
+
+ def pbkdf2_hmac_supported(self, algorithm):
+ return algorithm.name in self._supported_pbkdf2_hmac_algorithms
+
+ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
+ key_material):
+ alg_enum = self._supported_pbkdf2_hmac_algorithms[algorithm.name]
+ buf = self._ffi.new("char[]", length)
+ res = self._lib.CCKeyDerivationPBKDF(
+ self._lib.kCCPBKDF2,
+ key_material,
+ len(key_material),
+ salt,
+ len(salt),
+ alg_enum,
+ iterations,
+ buf,
+ length
+ )
+ self._check_cipher_response(res)
+
+ return self._ffi.buffer(buf)[:]
+
+ def _register_cipher_adapter(self, cipher_cls, cipher_const, mode_cls,
+ mode_const):
+ if (cipher_cls, mode_cls) in self._cipher_registry:
+ raise ValueError("Duplicate registration for: {0} {1}.".format(
+ cipher_cls, mode_cls)
+ )
+ self._cipher_registry[cipher_cls, mode_cls] = (cipher_const,
+ mode_const)
+
+ def _register_default_ciphers(self):
+ for mode_cls, mode_const in [
+ (CBC, self._lib.kCCModeCBC),
+ (ECB, self._lib.kCCModeECB),
+ (CFB, self._lib.kCCModeCFB),
+ (CFB8, self._lib.kCCModeCFB8),
+ (OFB, self._lib.kCCModeOFB),
+ (CTR, self._lib.kCCModeCTR),
+ (GCM, self._lib.kCCModeGCM),
+ ]:
+ self._register_cipher_adapter(
+ AES,
+ self._lib.kCCAlgorithmAES128,
+ mode_cls,
+ mode_const
+ )
+ for mode_cls, mode_const in [
+ (CBC, self._lib.kCCModeCBC),
+ (ECB, self._lib.kCCModeECB),
+ (CFB, self._lib.kCCModeCFB),
+ (CFB8, self._lib.kCCModeCFB8),
+ (OFB, self._lib.kCCModeOFB),
+ ]:
+ self._register_cipher_adapter(
+ TripleDES,
+ self._lib.kCCAlgorithm3DES,
+ mode_cls,
+ mode_const
+ )
+ for mode_cls, mode_const in [
+ (CBC, self._lib.kCCModeCBC),
+ (ECB, self._lib.kCCModeECB),
+ (CFB, self._lib.kCCModeCFB),
+ (OFB, self._lib.kCCModeOFB)
+ ]:
+ self._register_cipher_adapter(
+ Blowfish,
+ self._lib.kCCAlgorithmBlowfish,
+ mode_cls,
+ mode_const
+ )
+ for mode_cls, mode_const in [
+ (CBC, self._lib.kCCModeCBC),
+ (ECB, self._lib.kCCModeECB),
+ (CFB, self._lib.kCCModeCFB),
+ (OFB, self._lib.kCCModeOFB),
+ (CTR, self._lib.kCCModeCTR)
+ ]:
+ self._register_cipher_adapter(
+ CAST5,
+ self._lib.kCCAlgorithmCAST,
+ mode_cls,
+ mode_const
+ )
+ self._register_cipher_adapter(
+ ARC4,
+ self._lib.kCCAlgorithmRC4,
+ type(None),
+ self._lib.kCCModeRC4
+ )
+
+ def _check_cipher_response(self, response):
+ if response == self._lib.kCCSuccess:
+ return
+ elif response == self._lib.kCCAlignmentError:
+ # This error is not currently triggered due to a bug filed as
+ # rdar://15589470
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length."
+ )
+ else:
+ raise InternalError(
+ "The backend returned an unknown error, consider filing a bug."
+ " Code: {0}.".format(response)
+ )
+
+ def _release_cipher_ctx(self, ctx):
+ """
+ Called by the garbage collector and used to safely dereference and
+ release the context.
+ """
+ if ctx[0] != self._ffi.NULL:
+ res = self._lib.CCCryptorRelease(ctx[0])
+ self._check_cipher_response(res)
+ ctx[0] = self._ffi.NULL
+
+
+backend = Backend()
diff --git a/src/cryptography/hazmat/backends/commoncrypto/ciphers.py b/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
new file mode 100644
index 00000000..d94746c6
--- /dev/null
+++ b/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
@@ -0,0 +1,201 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidTag, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
+from cryptography.hazmat.primitives.ciphers.modes import (
+ CFB, CFB8, CTR, OFB
+)
+
+
+@utils.register_interface(interfaces.CipherContext)
+class _CipherContext(object):
+ def __init__(self, backend, cipher, mode, operation):
+ self._backend = backend
+ self._cipher = cipher
+ self._mode = mode
+ self._operation = operation
+ # There is a bug in CommonCrypto where block ciphers do not raise
+ # kCCAlignmentError when finalizing if you supply non-block aligned
+ # data. To work around this we need to keep track of the block
+ # alignment ourselves, but only for alg+mode combos that require
+ # block alignment. OFB, CFB, and CTR make a block cipher algorithm
+ # into a stream cipher so we don't need to track them (and thus their
+ # block size is effectively 1 byte just like OpenSSL/CommonCrypto
+ # treat RC4 and other stream cipher block sizes).
+ # This bug has been filed as rdar://15589470
+ self._bytes_processed = 0
+ if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
+ isinstance(mode, (OFB, CFB, CFB8, CTR))):
+ self._byte_block_size = cipher.block_size // 8
+ else:
+ self._byte_block_size = 1
+
+ registry = self._backend._cipher_registry
+ try:
+ cipher_enum, mode_enum = registry[type(cipher), type(mode)]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ ctx = self._backend._ffi.new("CCCryptorRef *")
+ ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
+
+ if isinstance(mode, interfaces.ModeWithInitializationVector):
+ iv_nonce = mode.initialization_vector
+ elif isinstance(mode, interfaces.ModeWithNonce):
+ iv_nonce = mode.nonce
+ else:
+ iv_nonce = self._backend._ffi.NULL
+
+ if isinstance(mode, CTR):
+ mode_option = self._backend._lib.kCCModeOptionCTR_BE
+ else:
+ mode_option = 0
+
+ res = self._backend._lib.CCCryptorCreateWithMode(
+ operation,
+ mode_enum, cipher_enum,
+ self._backend._lib.ccNoPadding, iv_nonce,
+ cipher.key, len(cipher.key),
+ self._backend._ffi.NULL, 0, 0, mode_option, ctx)
+ self._backend._check_cipher_response(res)
+
+ self._ctx = ctx
+
+ def update(self, data):
+ # Count bytes processed to handle block alignment.
+ self._bytes_processed += len(data)
+ buf = self._backend._ffi.new(
+ "unsigned char[]", len(data) + self._byte_block_size - 1)
+ outlen = self._backend._ffi.new("size_t *")
+ res = self._backend._lib.CCCryptorUpdate(
+ self._ctx[0], data, len(data), buf,
+ len(data) + self._byte_block_size - 1, outlen)
+ self._backend._check_cipher_response(res)
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def finalize(self):
+ # Raise error if block alignment is wrong.
+ if self._bytes_processed % self._byte_block_size:
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length."
+ )
+ buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
+ outlen = self._backend._ffi.new("size_t *")
+ res = self._backend._lib.CCCryptorFinal(
+ self._ctx[0], buf, len(buf), outlen)
+ self._backend._check_cipher_response(res)
+ self._backend._release_cipher_ctx(self._ctx)
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+
+@utils.register_interface(interfaces.AEADCipherContext)
+@utils.register_interface(interfaces.AEADEncryptionContext)
+class _GCMCipherContext(object):
+ def __init__(self, backend, cipher, mode, operation):
+ self._backend = backend
+ self._cipher = cipher
+ self._mode = mode
+ self._operation = operation
+ self._tag = None
+
+ registry = self._backend._cipher_registry
+ try:
+ cipher_enum, mode_enum = registry[type(cipher), type(mode)]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ ctx = self._backend._ffi.new("CCCryptorRef *")
+ ctx = self._backend._ffi.gc(ctx, self._backend._release_cipher_ctx)
+
+ self._ctx = ctx
+
+ res = self._backend._lib.CCCryptorCreateWithMode(
+ operation,
+ mode_enum, cipher_enum,
+ self._backend._lib.ccNoPadding,
+ self._backend._ffi.NULL,
+ cipher.key, len(cipher.key),
+ self._backend._ffi.NULL, 0, 0, 0, self._ctx)
+ self._backend._check_cipher_response(res)
+
+ res = self._backend._lib.CCCryptorGCMAddIV(
+ self._ctx[0],
+ mode.initialization_vector,
+ len(mode.initialization_vector)
+ )
+ self._backend._check_cipher_response(res)
+ # CommonCrypto has a bug where calling update without at least one
+ # call to authenticate_additional_data will result in null byte output
+ # for ciphertext. The following empty byte string call prevents the
+ # issue, which is present in at least 10.8 and 10.9.
+ # Filed as rdar://18314544
+ self.authenticate_additional_data(b"")
+
+ def update(self, data):
+ buf = self._backend._ffi.new("unsigned char[]", len(data))
+ args = (self._ctx[0], data, len(data), buf)
+ if self._operation == self._backend._lib.kCCEncrypt:
+ res = self._backend._lib.CCCryptorGCMEncrypt(*args)
+ else:
+ res = self._backend._lib.CCCryptorGCMDecrypt(*args)
+
+ self._backend._check_cipher_response(res)
+ return self._backend._ffi.buffer(buf)[:]
+
+ def finalize(self):
+ # CommonCrypto has a yet another bug where you must make at least one
+ # call to update. If you pass just AAD and call finalize without a call
+ # to update you'll get null bytes for tag. The following update call
+ # prevents this issue, which is present in at least 10.8 and 10.9.
+ # Filed as rdar://18314580
+ self.update(b"")
+ tag_size = self._cipher.block_size // 8
+ tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
+ tag_len = self._backend._ffi.new("size_t *", tag_size)
+ res = self._backend._lib.CCCryptorGCMFinal(
+ self._ctx[0], tag_buf, tag_len
+ )
+ self._backend._check_cipher_response(res)
+ self._backend._release_cipher_ctx(self._ctx)
+ self._tag = self._backend._ffi.buffer(tag_buf)[:]
+ if (self._operation == self._backend._lib.kCCDecrypt and
+ not constant_time.bytes_eq(
+ self._tag[:len(self._mode.tag)], self._mode.tag
+ )):
+ raise InvalidTag
+ return b""
+
+ def authenticate_additional_data(self, data):
+ res = self._backend._lib.CCCryptorGCMAddAAD(
+ self._ctx[0], data, len(data)
+ )
+ self._backend._check_cipher_response(res)
+
+ tag = utils.read_only_property("_tag")
diff --git a/src/cryptography/hazmat/backends/commoncrypto/hashes.py b/src/cryptography/hazmat/backends/commoncrypto/hashes.py
new file mode 100644
index 00000000..217f4e8c
--- /dev/null
+++ b/src/cryptography/hazmat/backends/commoncrypto/hashes.py
@@ -0,0 +1,64 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HashContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ self._algorithm = algorithm
+ self._backend = backend
+
+ if ctx is None:
+ try:
+ methods = self._backend._hash_mapping[self.algorithm.name]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+ ctx = self._backend._ffi.new(methods.ctx)
+ res = methods.hash_init(ctx)
+ assert res == 1
+
+ self._ctx = ctx
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def copy(self):
+ methods = self._backend._hash_mapping[self.algorithm.name]
+ new_ctx = self._backend._ffi.new(methods.ctx)
+ # CommonCrypto has no APIs for copying hashes, so we have to copy the
+ # underlying struct.
+ new_ctx[0] = self._ctx[0]
+
+ return _HashContext(self._backend, self.algorithm, ctx=new_ctx)
+
+ def update(self, data):
+ methods = self._backend._hash_mapping[self.algorithm.name]
+ res = methods.hash_update(self._ctx, data, len(data))
+ assert res == 1
+
+ def finalize(self):
+ methods = self._backend._hash_mapping[self.algorithm.name]
+ buf = self._backend._ffi.new("unsigned char[]",
+ self.algorithm.digest_size)
+ res = methods.hash_final(buf, self._ctx)
+ assert res == 1
+ return self._backend._ffi.buffer(buf)[:]
diff --git a/src/cryptography/hazmat/backends/commoncrypto/hmac.py b/src/cryptography/hazmat/backends/commoncrypto/hmac.py
new file mode 100644
index 00000000..ee7e3abb
--- /dev/null
+++ b/src/cryptography/hazmat/backends/commoncrypto/hmac.py
@@ -0,0 +1,68 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
+
+
+@utils.register_interface(interfaces.MACContext)
+@utils.register_interface(interfaces.HashContext)
+class _HMACContext(object):
+ def __init__(self, backend, key, algorithm, ctx=None):
+ self._algorithm = algorithm
+ self._backend = backend
+ if ctx is None:
+ ctx = self._backend._ffi.new("CCHmacContext *")
+ try:
+ alg = self._backend._supported_hmac_algorithms[algorithm.name]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported HMAC hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ self._backend._lib.CCHmacInit(ctx, alg, key, len(key))
+
+ self._ctx = ctx
+ self._key = key
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def copy(self):
+ copied_ctx = self._backend._ffi.new("CCHmacContext *")
+ # CommonCrypto has no APIs for copying HMACs, so we have to copy the
+ # underlying struct.
+ copied_ctx[0] = self._ctx[0]
+ return _HMACContext(
+ self._backend, self._key, self.algorithm, ctx=copied_ctx
+ )
+
+ def update(self, data):
+ self._backend._lib.CCHmacUpdate(self._ctx, data, len(data))
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]",
+ self.algorithm.digest_size)
+ self._backend._lib.CCHmacFinal(self._ctx, buf)
+ return self._backend._ffi.buffer(buf)[:]
+
+ def verify(self, signature):
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
diff --git a/src/cryptography/hazmat/backends/interfaces.py b/src/cryptography/hazmat/backends/interfaces.py
new file mode 100644
index 00000000..ecb5bf48
--- /dev/null
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -0,0 +1,261 @@
+# 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 abc
+
+import six
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CipherBackend(object):
+ @abc.abstractmethod
+ def cipher_supported(self, cipher, mode):
+ """
+ Return True if the given cipher and mode are supported.
+ """
+
+ @abc.abstractmethod
+ def create_symmetric_encryption_ctx(self, cipher, mode):
+ """
+ Get a CipherContext that can be used for encryption.
+ """
+
+ @abc.abstractmethod
+ def create_symmetric_decryption_ctx(self, cipher, mode):
+ """
+ Get a CipherContext that can be used for decryption.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class HashBackend(object):
+ @abc.abstractmethod
+ def hash_supported(self, algorithm):
+ """
+ Return True if the hash algorithm is supported by this backend.
+ """
+
+ @abc.abstractmethod
+ def create_hash_ctx(self, algorithm):
+ """
+ Create a HashContext for calculating a message digest.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class HMACBackend(object):
+ @abc.abstractmethod
+ def hmac_supported(self, algorithm):
+ """
+ Return True if the hash algorithm is supported for HMAC by this
+ backend.
+ """
+
+ @abc.abstractmethod
+ def create_hmac_ctx(self, key, algorithm):
+ """
+ Create a MACContext for calculating a message authentication code.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CMACBackend(object):
+ @abc.abstractmethod
+ def cmac_algorithm_supported(self, algorithm):
+ """
+ Returns True if the block cipher is supported for CMAC by this backend
+ """
+
+ @abc.abstractmethod
+ def create_cmac_ctx(self, algorithm):
+ """
+ Create a MACContext for calculating a message authentication code.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class PBKDF2HMACBackend(object):
+ @abc.abstractmethod
+ def pbkdf2_hmac_supported(self, algorithm):
+ """
+ Return True if the hash algorithm is supported for PBKDF2 by this
+ backend.
+ """
+
+ @abc.abstractmethod
+ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
+ key_material):
+ """
+ Return length bytes derived from provided PBKDF2 parameters.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RSABackend(object):
+ @abc.abstractmethod
+ def generate_rsa_private_key(self, public_exponent, key_size):
+ """
+ Generate an RSAPrivateKey instance with public_exponent and a modulus
+ of key_size bits.
+ """
+
+ @abc.abstractmethod
+ def rsa_padding_supported(self, padding):
+ """
+ Returns True if the backend supports the given padding options.
+ """
+
+ @abc.abstractmethod
+ def generate_rsa_parameters_supported(self, public_exponent, key_size):
+ """
+ Returns True if the backend supports the given parameters for key
+ generation.
+ """
+
+ @abc.abstractmethod
+ def load_rsa_private_numbers(self, numbers):
+ """
+ Returns an RSAPrivateKey provider.
+ """
+
+ @abc.abstractmethod
+ def load_rsa_public_numbers(self, numbers):
+ """
+ Returns an RSAPublicKey provider.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSABackend(object):
+ @abc.abstractmethod
+ def generate_dsa_parameters(self, key_size):
+ """
+ Generate a DSAParameters instance with a modulus of key_size bits.
+ """
+
+ @abc.abstractmethod
+ def generate_dsa_private_key(self, parameters):
+ """
+ Generate a DSAPrivateKey instance with parameters as a DSAParameters
+ object.
+ """
+
+ @abc.abstractmethod
+ def generate_dsa_private_key_and_parameters(self, key_size):
+ """
+ Generate a DSAPrivateKey instance using key size only.
+ """
+
+ @abc.abstractmethod
+ def dsa_hash_supported(self, algorithm):
+ """
+ Return True if the hash algorithm is supported by the backend for DSA.
+ """
+
+ @abc.abstractmethod
+ def dsa_parameters_supported(self, p, q, g):
+ """
+ Return True if the parameters are supported by the backend for DSA.
+ """
+
+ @abc.abstractmethod
+ def load_dsa_private_numbers(self, numbers):
+ """
+ Returns a DSAPrivateKey provider.
+ """
+
+ @abc.abstractmethod
+ def load_dsa_public_numbers(self, numbers):
+ """
+ Returns a DSAPublicKey provider.
+ """
+
+ @abc.abstractmethod
+ def load_dsa_parameter_numbers(self, numbers):
+ """
+ Returns a DSAParameters provider.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurveBackend(object):
+ @abc.abstractmethod
+ def elliptic_curve_signature_algorithm_supported(
+ self, signature_algorithm, curve
+ ):
+ """
+ Returns True if the backend supports the named elliptic curve with the
+ specified signature algorithm.
+ """
+
+ @abc.abstractmethod
+ def elliptic_curve_supported(self, curve):
+ """
+ Returns True if the backend supports the named elliptic curve.
+ """
+
+ @abc.abstractmethod
+ def generate_elliptic_curve_private_key(self, curve):
+ """
+ Return an object conforming to the EllipticCurvePrivateKey interface.
+ """
+
+ @abc.abstractmethod
+ def load_elliptic_curve_public_numbers(self, numbers):
+ """
+ Return an EllipticCurvePublicKey provider using the given numbers.
+ """
+
+ @abc.abstractmethod
+ def load_elliptic_curve_private_numbers(self, numbers):
+ """
+ Return an EllipticCurvePublicKey provider using the given numbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class PEMSerializationBackend(object):
+ @abc.abstractmethod
+ def load_pem_private_key(self, data, password):
+ """
+ Loads a private key from PEM encoded data, using the provided password
+ if the data is encrypted.
+ """
+
+ @abc.abstractmethod
+ def load_pem_public_key(self, data):
+ """
+ Loads a public key from PEM encoded data.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class TraditionalOpenSSLSerializationBackend(object):
+ @abc.abstractmethod
+ def load_traditional_openssl_pem_private_key(self, data, password):
+ """
+ Load a private key from PEM encoded data, using password if the data
+ is encrypted.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class PKCS8SerializationBackend(object):
+ @abc.abstractmethod
+ def load_pkcs8_pem_private_key(self, data, password):
+ """
+ Load a private key from PKCS8 encoded data, using password if the data
+ is encrypted.
+ """
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
new file mode 100644
index 00000000..c62b790c
--- /dev/null
+++ b/src/cryptography/hazmat/backends/multibackend.py
@@ -0,0 +1,358 @@
+# 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 warnings
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.backends.interfaces import (
+ CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+ HashBackend, PBKDF2HMACBackend, PEMSerializationBackend,
+ PKCS8SerializationBackend, RSABackend,
+ TraditionalOpenSSLSerializationBackend
+)
+
+
+@utils.register_interface(CMACBackend)
+@utils.register_interface(CipherBackend)
+@utils.register_interface(HashBackend)
+@utils.register_interface(HMACBackend)
+@utils.register_interface(PBKDF2HMACBackend)
+@utils.register_interface(PKCS8SerializationBackend)
+@utils.register_interface(RSABackend)
+@utils.register_interface(TraditionalOpenSSLSerializationBackend)
+@utils.register_interface(DSABackend)
+@utils.register_interface(EllipticCurveBackend)
+@utils.register_interface(PEMSerializationBackend)
+class MultiBackend(object):
+ name = "multibackend"
+
+ def __init__(self, backends):
+ self._backends = backends
+
+ def _filtered_backends(self, interface):
+ for b in self._backends:
+ if isinstance(b, interface):
+ yield b
+
+ def cipher_supported(self, cipher, mode):
+ return any(
+ b.cipher_supported(cipher, mode)
+ for b in self._filtered_backends(CipherBackend)
+ )
+
+ def create_symmetric_encryption_ctx(self, cipher, mode):
+ for b in self._filtered_backends(CipherBackend):
+ try:
+ return b.create_symmetric_encryption_ctx(cipher, mode)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ def create_symmetric_decryption_ctx(self, cipher, mode):
+ for b in self._filtered_backends(CipherBackend):
+ try:
+ return b.create_symmetric_decryption_ctx(cipher, mode)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ def hash_supported(self, algorithm):
+ return any(
+ b.hash_supported(algorithm)
+ for b in self._filtered_backends(HashBackend)
+ )
+
+ def create_hash_ctx(self, algorithm):
+ for b in self._filtered_backends(HashBackend):
+ try:
+ return b.create_hash_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ def hmac_supported(self, algorithm):
+ return any(
+ b.hmac_supported(algorithm)
+ for b in self._filtered_backends(HMACBackend)
+ )
+
+ def create_hmac_ctx(self, key, algorithm):
+ for b in self._filtered_backends(HMACBackend):
+ try:
+ return b.create_hmac_ctx(key, algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ def pbkdf2_hmac_supported(self, algorithm):
+ return any(
+ b.pbkdf2_hmac_supported(algorithm)
+ for b in self._filtered_backends(PBKDF2HMACBackend)
+ )
+
+ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
+ key_material):
+ for b in self._filtered_backends(PBKDF2HMACBackend):
+ try:
+ return b.derive_pbkdf2_hmac(
+ algorithm, length, salt, iterations, key_material
+ )
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ def generate_rsa_private_key(self, public_exponent, key_size):
+ for b in self._filtered_backends(RSABackend):
+ return b.generate_rsa_private_key(public_exponent, key_size)
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def generate_rsa_parameters_supported(self, public_exponent, key_size):
+ for b in self._filtered_backends(RSABackend):
+ return b.generate_rsa_parameters_supported(
+ public_exponent, key_size
+ )
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def rsa_padding_supported(self, padding):
+ for b in self._filtered_backends(RSABackend):
+ return b.rsa_padding_supported(padding)
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def load_rsa_private_numbers(self, numbers):
+ for b in self._filtered_backends(RSABackend):
+ return b.load_rsa_private_numbers(numbers)
+
+ raise UnsupportedAlgorithm("RSA is not supported by the backend",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def load_rsa_public_numbers(self, numbers):
+ for b in self._filtered_backends(RSABackend):
+ return b.load_rsa_public_numbers(numbers)
+
+ raise UnsupportedAlgorithm("RSA is not supported by the backend",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def generate_dsa_parameters(self, key_size):
+ for b in self._filtered_backends(DSABackend):
+ return b.generate_dsa_parameters(key_size)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def generate_dsa_private_key(self, parameters):
+ for b in self._filtered_backends(DSABackend):
+ return b.generate_dsa_private_key(parameters)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def generate_dsa_private_key_and_parameters(self, key_size):
+ for b in self._filtered_backends(DSABackend):
+ return b.generate_dsa_private_key_and_parameters(key_size)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def dsa_hash_supported(self, algorithm):
+ for b in self._filtered_backends(DSABackend):
+ return b.dsa_hash_supported(algorithm)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def dsa_parameters_supported(self, p, q, g):
+ for b in self._filtered_backends(DSABackend):
+ return b.dsa_parameters_supported(p, q, g)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def load_dsa_public_numbers(self, numbers):
+ for b in self._filtered_backends(DSABackend):
+ return b.load_dsa_public_numbers(numbers)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def load_dsa_private_numbers(self, numbers):
+ for b in self._filtered_backends(DSABackend):
+ return b.load_dsa_private_numbers(numbers)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def load_dsa_parameter_numbers(self, numbers):
+ for b in self._filtered_backends(DSABackend):
+ return b.load_dsa_parameter_numbers(numbers)
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def cmac_algorithm_supported(self, algorithm):
+ return any(
+ b.cmac_algorithm_supported(algorithm)
+ for b in self._filtered_backends(CMACBackend)
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ for b in self._filtered_backends(CMACBackend):
+ try:
+ return b.create_cmac_ctx(algorithm)
+ except UnsupportedAlgorithm:
+ pass
+ raise UnsupportedAlgorithm("This backend does not support CMAC.",
+ _Reasons.UNSUPPORTED_CIPHER)
+
+ def elliptic_curve_supported(self, curve):
+ return any(
+ b.elliptic_curve_supported(curve)
+ for b in self._filtered_backends(EllipticCurveBackend)
+ )
+
+ def elliptic_curve_signature_algorithm_supported(
+ self, signature_algorithm, curve
+ ):
+ return any(
+ b.elliptic_curve_signature_algorithm_supported(
+ signature_algorithm, curve
+ )
+ for b in self._filtered_backends(EllipticCurveBackend)
+ )
+
+ def generate_elliptic_curve_private_key(self, curve):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.generate_elliptic_curve_private_key(curve)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def elliptic_curve_private_key_from_numbers(self, numbers):
+ warnings.warn(
+ "elliptic_curve_private_key_from_numbers is deprecated and will "
+ "be removed in a future version.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.elliptic_curve_private_key_from_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def load_elliptic_curve_private_numbers(self, numbers):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.load_elliptic_curve_private_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def elliptic_curve_public_key_from_numbers(self, numbers):
+ warnings.warn(
+ "elliptic_curve_public_key_from_numbers is deprecated and will "
+ "be removed in a future version.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.elliptic_curve_public_key_from_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def load_elliptic_curve_public_numbers(self, numbers):
+ for b in self._filtered_backends(EllipticCurveBackend):
+ try:
+ return b.load_elliptic_curve_public_numbers(numbers)
+ except UnsupportedAlgorithm:
+ continue
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this elliptic curve.",
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def load_pem_private_key(self, data, password):
+ for b in self._filtered_backends(PEMSerializationBackend):
+ return b.load_pem_private_key(data, password)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this key serialization.",
+ _Reasons.UNSUPPORTED_SERIALIZATION
+ )
+
+ def load_pem_public_key(self, data):
+ for b in self._filtered_backends(PEMSerializationBackend):
+ return b.load_pem_public_key(data)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this key serialization.",
+ _Reasons.UNSUPPORTED_SERIALIZATION
+ )
+
+ def load_pkcs8_pem_private_key(self, data, password):
+ for b in self._filtered_backends(PKCS8SerializationBackend):
+ return b.load_pkcs8_pem_private_key(data, password)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this key serialization.",
+ _Reasons.UNSUPPORTED_SERIALIZATION
+ )
+
+ def load_traditional_openssl_pem_private_key(self, data, password):
+ for b in self._filtered_backends(
+ TraditionalOpenSSLSerializationBackend
+ ):
+ return b.load_traditional_openssl_pem_private_key(data, password)
+
+ raise UnsupportedAlgorithm(
+ "This backend does not support this key serialization.",
+ _Reasons.UNSUPPORTED_SERIALIZATION
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/__init__.py b/src/cryptography/hazmat/backends/openssl/__init__.py
new file mode 100644
index 00000000..25885e18
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/__init__.py
@@ -0,0 +1,19 @@
+# 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
+
+from cryptography.hazmat.backends.openssl.backend import backend
+
+
+__all__ = ["backend"]
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
new file mode 100644
index 00000000..bb1a3f3d
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -0,0 +1,1036 @@
+# 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 collections
+import itertools
+import warnings
+from contextlib import contextmanager
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InternalError, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import (
+ CMACBackend, CipherBackend, DSABackend, EllipticCurveBackend, HMACBackend,
+ HashBackend, PBKDF2HMACBackend, PEMSerializationBackend,
+ PKCS8SerializationBackend, RSABackend,
+ TraditionalOpenSSLSerializationBackend
+)
+from cryptography.hazmat.backends.openssl.ciphers import (
+ _AESCTRCipherContext, _CipherContext
+)
+from cryptography.hazmat.backends.openssl.cmac import _CMACContext
+from cryptography.hazmat.backends.openssl.dsa import (
+ _DSAParameters, _DSAPrivateKey, _DSAPublicKey
+)
+from cryptography.hazmat.backends.openssl.ec import (
+ _EllipticCurvePrivateKey, _EllipticCurvePublicKey
+)
+from cryptography.hazmat.backends.openssl.hashes import _HashContext
+from cryptography.hazmat.backends.openssl.hmac import _HMACContext
+from cryptography.hazmat.backends.openssl.rsa import (
+ _RSAPrivateKey, _RSAPublicKey
+)
+from cryptography.hazmat.bindings.openssl.binding import Binding
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
+from cryptography.hazmat.primitives.asymmetric.padding import (
+ MGF1, OAEP, PKCS1v15, PSS
+)
+from cryptography.hazmat.primitives.ciphers.algorithms import (
+ AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
+)
+from cryptography.hazmat.primitives.ciphers.modes import (
+ CBC, CFB, CFB8, CTR, ECB, GCM, OFB
+)
+
+
+_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
+_OpenSSLError = collections.namedtuple("_OpenSSLError",
+ ["code", "lib", "func", "reason"])
+
+
+@utils.register_interface(CipherBackend)
+@utils.register_interface(CMACBackend)
+@utils.register_interface(DSABackend)
+@utils.register_interface(EllipticCurveBackend)
+@utils.register_interface(HashBackend)
+@utils.register_interface(HMACBackend)
+@utils.register_interface(PBKDF2HMACBackend)
+@utils.register_interface(PKCS8SerializationBackend)
+@utils.register_interface(RSABackend)
+@utils.register_interface(TraditionalOpenSSLSerializationBackend)
+@utils.register_interface(PEMSerializationBackend)
+class Backend(object):
+ """
+ OpenSSL API binding interfaces.
+ """
+ name = "openssl"
+
+ def __init__(self):
+ self._binding = Binding()
+ self._ffi = self._binding.ffi
+ self._lib = self._binding.lib
+
+ self._binding.init_static_locks()
+
+ # adds all ciphers/digests for EVP
+ self._lib.OpenSSL_add_all_algorithms()
+ # registers available SSL/TLS ciphers and digests
+ self._lib.SSL_library_init()
+ # loads error strings for libcrypto and libssl functions
+ self._lib.SSL_load_error_strings()
+
+ self._cipher_registry = {}
+ self._register_default_ciphers()
+ self.activate_osrandom_engine()
+
+ def activate_builtin_random(self):
+ # Obtain a new structural reference.
+ e = self._lib.ENGINE_get_default_RAND()
+ if e != self._ffi.NULL:
+ self._lib.ENGINE_unregister_RAND(e)
+ # Reset the RNG to use the new engine.
+ self._lib.RAND_cleanup()
+ # decrement the structural reference from get_default_RAND
+ res = self._lib.ENGINE_finish(e)
+ assert res == 1
+
+ def activate_osrandom_engine(self):
+ # Unregister and free the current engine.
+ self.activate_builtin_random()
+ # Fetches an engine by id and returns it. This creates a structural
+ # reference.
+ e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
+ assert e != self._ffi.NULL
+ # Initialize the engine for use. This adds a functional reference.
+ res = self._lib.ENGINE_init(e)
+ assert res == 1
+ # Set the engine as the default RAND provider.
+ res = self._lib.ENGINE_set_default_RAND(e)
+ assert res == 1
+ # Decrement the structural ref incremented by ENGINE_by_id.
+ res = self._lib.ENGINE_free(e)
+ assert res == 1
+ # Decrement the functional ref incremented by ENGINE_init.
+ res = self._lib.ENGINE_finish(e)
+ assert res == 1
+ # Reset the RNG to use the new engine.
+ self._lib.RAND_cleanup()
+
+ def openssl_version_text(self):
+ """
+ Friendly string name of the loaded OpenSSL library. This is not
+ necessarily the same version as it was compiled against.
+
+ Example: OpenSSL 1.0.1e 11 Feb 2013
+ """
+ return self._ffi.string(
+ self._lib.SSLeay_version(self._lib.SSLEAY_VERSION)
+ ).decode("ascii")
+
+ def create_hmac_ctx(self, key, algorithm):
+ return _HMACContext(self, key, algorithm)
+
+ def hash_supported(self, algorithm):
+ digest = self._lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
+ return digest != self._ffi.NULL
+
+ def hmac_supported(self, algorithm):
+ return self.hash_supported(algorithm)
+
+ def create_hash_ctx(self, algorithm):
+ return _HashContext(self, algorithm)
+
+ def cipher_supported(self, cipher, mode):
+ if self._evp_cipher_supported(cipher, mode):
+ return True
+ elif isinstance(mode, CTR) and isinstance(cipher, AES):
+ return True
+ else:
+ return False
+
+ def _evp_cipher_supported(self, cipher, mode):
+ try:
+ adapter = self._cipher_registry[type(cipher), type(mode)]
+ except KeyError:
+ return False
+ evp_cipher = adapter(self, cipher, mode)
+ return self._ffi.NULL != evp_cipher
+
+ def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
+ if (cipher_cls, mode_cls) in self._cipher_registry:
+ raise ValueError("Duplicate registration for: {0} {1}.".format(
+ cipher_cls, mode_cls)
+ )
+ self._cipher_registry[cipher_cls, mode_cls] = adapter
+
+ def _register_default_ciphers(self):
+ for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8]:
+ self.register_cipher_adapter(
+ AES,
+ mode_cls,
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ )
+ for mode_cls in [CBC, CTR, ECB, OFB, CFB]:
+ self.register_cipher_adapter(
+ Camellia,
+ mode_cls,
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ )
+ for mode_cls in [CBC, CFB, CFB8, OFB]:
+ self.register_cipher_adapter(
+ TripleDES,
+ mode_cls,
+ GetCipherByName("des-ede3-{mode.name}")
+ )
+ self.register_cipher_adapter(
+ TripleDES,
+ ECB,
+ GetCipherByName("des-ede3")
+ )
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ Blowfish,
+ mode_cls,
+ GetCipherByName("bf-{mode.name}")
+ )
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ SEED,
+ mode_cls,
+ GetCipherByName("seed-{mode.name}")
+ )
+ for cipher_cls, mode_cls in itertools.product(
+ [CAST5, IDEA],
+ [CBC, OFB, CFB, ECB],
+ ):
+ self.register_cipher_adapter(
+ cipher_cls,
+ mode_cls,
+ GetCipherByName("{cipher.name}-{mode.name}")
+ )
+ self.register_cipher_adapter(
+ ARC4,
+ type(None),
+ GetCipherByName("rc4")
+ )
+ self.register_cipher_adapter(
+ AES,
+ GCM,
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ )
+
+ def create_symmetric_encryption_ctx(self, cipher, mode):
+ if (isinstance(mode, CTR) and isinstance(cipher, AES)
+ and not self._evp_cipher_supported(cipher, mode)):
+ # This is needed to provide support for AES CTR mode in OpenSSL
+ # 0.9.8. It can be removed when we drop 0.9.8 support (RHEL 5
+ # extended life ends 2020).
+ return _AESCTRCipherContext(self, cipher, mode)
+ else:
+ return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
+
+ def create_symmetric_decryption_ctx(self, cipher, mode):
+ if (isinstance(mode, CTR) and isinstance(cipher, AES)
+ and not self._evp_cipher_supported(cipher, mode)):
+ # This is needed to provide support for AES CTR mode in OpenSSL
+ # 0.9.8. It can be removed when we drop 0.9.8 support (RHEL 5
+ # extended life ends 2020).
+ return _AESCTRCipherContext(self, cipher, mode)
+ else:
+ return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
+
+ def pbkdf2_hmac_supported(self, algorithm):
+ if self._lib.Cryptography_HAS_PBKDF2_HMAC:
+ return self.hmac_supported(algorithm)
+ else:
+ # OpenSSL < 1.0.0 has an explicit PBKDF2-HMAC-SHA1 function,
+ # so if the PBKDF2_HMAC function is missing we only support
+ # SHA1 via PBKDF2_HMAC_SHA1.
+ return isinstance(algorithm, hashes.SHA1)
+
+ def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
+ key_material):
+ buf = self._ffi.new("char[]", length)
+ if self._lib.Cryptography_HAS_PBKDF2_HMAC:
+ evp_md = self._lib.EVP_get_digestbyname(
+ algorithm.name.encode("ascii"))
+ assert evp_md != self._ffi.NULL
+ res = self._lib.PKCS5_PBKDF2_HMAC(
+ key_material,
+ len(key_material),
+ salt,
+ len(salt),
+ iterations,
+ evp_md,
+ length,
+ buf
+ )
+ assert res == 1
+ else:
+ if not isinstance(algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This version of OpenSSL only supports PBKDF2HMAC with "
+ "SHA1.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+ res = self._lib.PKCS5_PBKDF2_HMAC_SHA1(
+ key_material,
+ len(key_material),
+ salt,
+ len(salt),
+ iterations,
+ length,
+ buf
+ )
+ assert res == 1
+
+ return self._ffi.buffer(buf)[:]
+
+ def _err_string(self, code):
+ err_buf = self._ffi.new("char[]", 256)
+ self._lib.ERR_error_string_n(code, err_buf, 256)
+ return self._ffi.string(err_buf, 256)[:]
+
+ def _consume_errors(self):
+ errors = []
+ while True:
+ code = self._lib.ERR_get_error()
+ if code == 0:
+ break
+
+ lib = self._lib.ERR_GET_LIB(code)
+ func = self._lib.ERR_GET_FUNC(code)
+ reason = self._lib.ERR_GET_REASON(code)
+
+ errors.append(_OpenSSLError(code, lib, func, reason))
+ return errors
+
+ def _unknown_error(self, error):
+ return InternalError(
+ "Unknown error code {0} from OpenSSL, "
+ "you should probably file a bug. {1}.".format(
+ error.code, self._err_string(error.code)
+ )
+ )
+
+ def _bn_to_int(self, bn):
+ if six.PY3:
+ # Python 3 has constant time from_bytes, so use that.
+
+ bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8
+ bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
+ bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
+ assert bin_len > 0
+ assert bin_ptr != self._ffi.NULL
+ return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+
+ else:
+ # Under Python 2 the best we can do is hex()
+
+ hex_cdata = self._lib.BN_bn2hex(bn)
+ assert hex_cdata != self._ffi.NULL
+ hex_str = self._ffi.string(hex_cdata)
+ self._lib.OPENSSL_free(hex_cdata)
+ return int(hex_str, 16)
+
+ def _int_to_bn(self, num, bn=None):
+ """
+ Converts a python integer to a BIGNUM. The returned BIGNUM will not
+ be garbage collected (to support adding them to structs that take
+ ownership of the object). Be sure to register it for GC if it will
+ be discarded after use.
+ """
+
+ if bn is None:
+ bn = self._ffi.NULL
+
+ if six.PY3:
+ # Python 3 has constant time to_bytes, so use that.
+
+ binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big")
+ bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn)
+ assert bn_ptr != self._ffi.NULL
+ return bn_ptr
+
+ else:
+ # Under Python 2 the best we can do is hex()
+
+ hex_num = hex(num).rstrip("L").lstrip("0x").encode("ascii") or b"0"
+ bn_ptr = self._ffi.new("BIGNUM **")
+ bn_ptr[0] = bn
+ res = self._lib.BN_hex2bn(bn_ptr, hex_num)
+ assert res != 0
+ assert bn_ptr[0] != self._ffi.NULL
+ return bn_ptr[0]
+
+ def generate_rsa_private_key(self, public_exponent, key_size):
+ rsa._verify_rsa_parameters(public_exponent, key_size)
+
+ rsa_cdata = self._lib.RSA_new()
+ assert rsa_cdata != self._ffi.NULL
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+
+ bn = self._int_to_bn(public_exponent)
+ bn = self._ffi.gc(bn, self._lib.BN_free)
+
+ res = self._lib.RSA_generate_key_ex(
+ rsa_cdata, key_size, bn, self._ffi.NULL
+ )
+ assert res == 1
+
+ return _RSAPrivateKey(self, rsa_cdata)
+
+ def generate_rsa_parameters_supported(self, public_exponent, key_size):
+ return (public_exponent >= 3 and public_exponent & 1 != 0 and
+ key_size >= 512)
+
+ def load_rsa_private_numbers(self, numbers):
+ rsa._check_private_key_components(
+ numbers.p,
+ numbers.q,
+ numbers.d,
+ numbers.dmp1,
+ numbers.dmq1,
+ numbers.iqmp,
+ numbers.public_numbers.e,
+ numbers.public_numbers.n
+ )
+ rsa_cdata = self._lib.RSA_new()
+ assert rsa_cdata != self._ffi.NULL
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ rsa_cdata.p = self._int_to_bn(numbers.p)
+ rsa_cdata.q = self._int_to_bn(numbers.q)
+ rsa_cdata.d = self._int_to_bn(numbers.d)
+ rsa_cdata.dmp1 = self._int_to_bn(numbers.dmp1)
+ rsa_cdata.dmq1 = self._int_to_bn(numbers.dmq1)
+ rsa_cdata.iqmp = self._int_to_bn(numbers.iqmp)
+ rsa_cdata.e = self._int_to_bn(numbers.public_numbers.e)
+ rsa_cdata.n = self._int_to_bn(numbers.public_numbers.n)
+ res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL)
+ assert res == 1
+
+ return _RSAPrivateKey(self, rsa_cdata)
+
+ def load_rsa_public_numbers(self, numbers):
+ rsa._check_public_key_components(numbers.e, numbers.n)
+ rsa_cdata = self._lib.RSA_new()
+ assert rsa_cdata != self._ffi.NULL
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ rsa_cdata.e = self._int_to_bn(numbers.e)
+ rsa_cdata.n = self._int_to_bn(numbers.n)
+ res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL)
+ assert res == 1
+
+ return _RSAPublicKey(self, rsa_cdata)
+
+ def _bytes_to_bio(self, data):
+ """
+ Return a _MemoryBIO namedtuple of (BIO, char*).
+
+ The char* is the storage for the BIO and it must stay alive until the
+ BIO is finished with.
+ """
+ data_char_p = self._ffi.new("char[]", data)
+ bio = self._lib.BIO_new_mem_buf(
+ data_char_p, len(data)
+ )
+ assert bio != self._ffi.NULL
+
+ return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_char_p)
+
+ def _evp_pkey_to_private_key(self, evp_pkey):
+ """
+ Return the appropriate type of PrivateKey given an evp_pkey cdata
+ pointer.
+ """
+
+ type = evp_pkey.type
+
+ if type == self._lib.EVP_PKEY_RSA:
+ rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
+ assert rsa_cdata != self._ffi.NULL
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ return _RSAPrivateKey(self, rsa_cdata)
+ elif type == self._lib.EVP_PKEY_DSA:
+ dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
+ assert dsa_cdata != self._ffi.NULL
+ dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
+ return _DSAPrivateKey(self, dsa_cdata)
+ elif (self._lib.Cryptography_HAS_EC == 1 and
+ type == self._lib.EVP_PKEY_EC):
+ ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
+ assert ec_cdata != self._ffi.NULL
+ ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+ return _EllipticCurvePrivateKey(self, ec_cdata)
+ else:
+ raise UnsupportedAlgorithm("Unsupported key type.")
+
+ def _evp_pkey_to_public_key(self, evp_pkey):
+ """
+ Return the appropriate type of PublicKey given an evp_pkey cdata
+ pointer.
+ """
+
+ type = evp_pkey.type
+
+ if type == self._lib.EVP_PKEY_RSA:
+ rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
+ assert rsa_cdata != self._ffi.NULL
+ rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
+ return _RSAPublicKey(self, rsa_cdata)
+ elif type == self._lib.EVP_PKEY_DSA:
+ dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
+ assert dsa_cdata != self._ffi.NULL
+ dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
+ return _DSAPublicKey(self, dsa_cdata)
+ elif (self._lib.Cryptography_HAS_EC == 1 and
+ type == self._lib.EVP_PKEY_EC):
+ ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
+ assert ec_cdata != self._ffi.NULL
+ ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+ return _EllipticCurvePublicKey(self, ec_cdata)
+ else:
+ raise UnsupportedAlgorithm("Unsupported key type.")
+
+ def _pem_password_cb(self, password):
+ """
+ Generate a pem_password_cb function pointer that copied the password to
+ OpenSSL as required and returns the number of bytes copied.
+
+ typedef int pem_password_cb(char *buf, int size,
+ int rwflag, void *userdata);
+
+ Useful for decrypting PKCS8 files and so on.
+
+ Returns a tuple of (cdata function pointer, callback function).
+ """
+
+ def pem_password_cb(buf, size, writing, userdata):
+ pem_password_cb.called += 1
+
+ if not password:
+ pem_password_cb.exception = TypeError(
+ "Password was not given but private key is encrypted."
+ )
+ return 0
+ elif len(password) < size:
+ pw_buf = self._ffi.buffer(buf, size)
+ pw_buf[:len(password)] = password
+ return len(password)
+ else:
+ pem_password_cb.exception = ValueError(
+ "Passwords longer than {0} bytes are not supported "
+ "by this backend.".format(size - 1)
+ )
+ return 0
+
+ pem_password_cb.called = 0
+ pem_password_cb.exception = None
+
+ return (
+ self._ffi.callback("int (char *, int, int, void *)",
+ pem_password_cb),
+ pem_password_cb
+ )
+
+ def _mgf1_hash_supported(self, algorithm):
+ if self._lib.Cryptography_HAS_MGF1_MD:
+ return self.hash_supported(algorithm)
+ else:
+ return isinstance(algorithm, hashes.SHA1)
+
+ def rsa_padding_supported(self, padding):
+ if isinstance(padding, PKCS1v15):
+ return True
+ elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
+ return self._mgf1_hash_supported(padding._mgf._algorithm)
+ elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
+ return isinstance(padding._mgf._algorithm, hashes.SHA1)
+ else:
+ return False
+
+ def generate_dsa_parameters(self, key_size):
+ if key_size not in (1024, 2048, 3072):
+ raise ValueError(
+ "Key size must be 1024 or 2048 or 3072 bits.")
+
+ if (self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f and
+ key_size > 1024):
+ raise ValueError(
+ "Key size must be 1024 because OpenSSL < 1.0.0 doesn't "
+ "support larger key sizes.")
+
+ ctx = self._lib.DSA_new()
+ assert ctx != self._ffi.NULL
+ ctx = self._ffi.gc(ctx, self._lib.DSA_free)
+
+ res = self._lib.DSA_generate_parameters_ex(
+ ctx, key_size, self._ffi.NULL, 0,
+ self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+ )
+
+ assert res == 1
+
+ return _DSAParameters(self, ctx)
+
+ def generate_dsa_private_key(self, parameters):
+ ctx = self._lib.DSA_new()
+ assert ctx != self._ffi.NULL
+ ctx = self._ffi.gc(ctx, self._lib.DSA_free)
+ ctx.p = self._lib.BN_dup(parameters._dsa_cdata.p)
+ ctx.q = self._lib.BN_dup(parameters._dsa_cdata.q)
+ ctx.g = self._lib.BN_dup(parameters._dsa_cdata.g)
+
+ self._lib.DSA_generate_key(ctx)
+
+ return _DSAPrivateKey(self, ctx)
+
+ def generate_dsa_private_key_and_parameters(self, key_size):
+ parameters = self.generate_dsa_parameters(key_size)
+ return self.generate_dsa_private_key(parameters)
+
+ def load_dsa_private_numbers(self, numbers):
+ dsa._check_dsa_private_numbers(numbers)
+ parameter_numbers = numbers.public_numbers.parameter_numbers
+
+ dsa_cdata = self._lib.DSA_new()
+ assert dsa_cdata != self._ffi.NULL
+ dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
+
+ dsa_cdata.p = self._int_to_bn(parameter_numbers.p)
+ dsa_cdata.q = self._int_to_bn(parameter_numbers.q)
+ dsa_cdata.g = self._int_to_bn(parameter_numbers.g)
+ dsa_cdata.pub_key = self._int_to_bn(numbers.public_numbers.y)
+ dsa_cdata.priv_key = self._int_to_bn(numbers.x)
+
+ return _DSAPrivateKey(self, dsa_cdata)
+
+ def load_dsa_public_numbers(self, numbers):
+ dsa._check_dsa_parameters(numbers.parameter_numbers)
+ dsa_cdata = self._lib.DSA_new()
+ assert dsa_cdata != self._ffi.NULL
+ dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
+
+ dsa_cdata.p = self._int_to_bn(numbers.parameter_numbers.p)
+ dsa_cdata.q = self._int_to_bn(numbers.parameter_numbers.q)
+ dsa_cdata.g = self._int_to_bn(numbers.parameter_numbers.g)
+ dsa_cdata.pub_key = self._int_to_bn(numbers.y)
+
+ return _DSAPublicKey(self, dsa_cdata)
+
+ def load_dsa_parameter_numbers(self, numbers):
+ dsa._check_dsa_parameters(numbers)
+ dsa_cdata = self._lib.DSA_new()
+ assert dsa_cdata != self._ffi.NULL
+ dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
+
+ dsa_cdata.p = self._int_to_bn(numbers.p)
+ dsa_cdata.q = self._int_to_bn(numbers.q)
+ dsa_cdata.g = self._int_to_bn(numbers.g)
+
+ return _DSAParameters(self, dsa_cdata)
+
+ def dsa_hash_supported(self, algorithm):
+ if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f:
+ return isinstance(algorithm, hashes.SHA1)
+ else:
+ return self.hash_supported(algorithm)
+
+ def dsa_parameters_supported(self, p, q, g):
+ if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f:
+ return (utils.bit_length(p) <= 1024 and utils.bit_length(q) <= 160)
+ else:
+ return True
+
+ def cmac_algorithm_supported(self, algorithm):
+ return (
+ self._lib.Cryptography_HAS_CMAC == 1
+ and self.cipher_supported(algorithm, CBC(
+ b"\x00" * algorithm.block_size))
+ )
+
+ def create_cmac_ctx(self, algorithm):
+ return _CMACContext(self, algorithm)
+
+ def load_pem_private_key(self, data, password):
+ return self._load_key(
+ self._lib.PEM_read_bio_PrivateKey,
+ self._evp_pkey_to_private_key,
+ data,
+ password,
+ )
+
+ def load_pem_public_key(self, data):
+ return self._load_key(
+ self._lib.PEM_read_bio_PUBKEY,
+ self._evp_pkey_to_public_key,
+ data,
+ None,
+ )
+
+ def load_traditional_openssl_pem_private_key(self, data, password):
+ warnings.warn(
+ "load_traditional_openssl_pem_private_key is deprecated and will "
+ "be removed in a future version, use load_pem_private_key "
+ "instead.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ return self.load_pem_private_key(data, password)
+
+ def load_pkcs8_pem_private_key(self, data, password):
+ warnings.warn(
+ "load_pkcs8_pem_private_key is deprecated and will be removed in a"
+ " future version, use load_pem_private_key instead.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ return self.load_pem_private_key(data, password)
+
+ def _load_key(self, openssl_read_func, convert_func, data, password):
+ mem_bio = self._bytes_to_bio(data)
+
+ password_callback, password_func = self._pem_password_cb(password)
+
+ evp_pkey = openssl_read_func(
+ mem_bio.bio,
+ self._ffi.NULL,
+ password_callback,
+ self._ffi.NULL
+ )
+
+ if evp_pkey == self._ffi.NULL:
+ if password_func.exception is not None:
+ errors = self._consume_errors()
+ assert errors
+ raise password_func.exception
+ else:
+ self._handle_key_loading_error()
+
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+
+ if password is not None and password_func.called == 0:
+ raise TypeError(
+ "Password was given but private key is not encrypted.")
+
+ assert (
+ (password is not None and password_func.called == 1) or
+ password is None
+ )
+
+ return convert_func(evp_pkey)
+
+ def _handle_key_loading_error(self):
+ errors = self._consume_errors()
+
+ if not errors:
+ raise ValueError("Could not unserialize key data.")
+
+ elif errors[0][1:] in (
+ (
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_F_EVP_DECRYPTFINAL_EX,
+ self._lib.EVP_R_BAD_DECRYPT
+ ),
+ (
+ self._lib.ERR_LIB_PKCS12,
+ self._lib.PKCS12_F_PKCS12_PBE_CRYPT,
+ self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR,
+ )
+ ):
+ raise ValueError("Bad decrypt. Incorrect password?")
+
+ elif errors[0][1:] in (
+ (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO,
+ self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
+ ),
+
+ (
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_F_EVP_PBE_CIPHERINIT,
+ self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
+ )
+ ):
+ raise UnsupportedAlgorithm(
+ "PEM data is encrypted with an unsupported cipher",
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ elif any(
+ error[1:] == (
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_F_EVP_PKCS82PKEY,
+ self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM
+ )
+ for error in errors
+ ):
+ raise UnsupportedAlgorithm(
+ "Unsupported public key algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ else:
+ assert errors[0][1] in (
+ self._lib.ERR_LIB_EVP,
+ self._lib.ERR_LIB_PEM,
+ self._lib.ERR_LIB_ASN1,
+ )
+ raise ValueError("Could not unserialize key data.")
+
+ def elliptic_curve_supported(self, curve):
+ if self._lib.Cryptography_HAS_EC != 1:
+ return False
+
+ try:
+ curve_nid = self._elliptic_curve_to_nid(curve)
+ except UnsupportedAlgorithm:
+ curve_nid = self._lib.NID_undef
+
+ ctx = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
+
+ if ctx == self._ffi.NULL:
+ errors = self._consume_errors()
+ assert (
+ curve_nid == self._lib.NID_undef or
+ errors[0][1:] == (
+ self._lib.ERR_LIB_EC,
+ self._lib.EC_F_EC_GROUP_NEW_BY_CURVE_NAME,
+ self._lib.EC_R_UNKNOWN_GROUP
+ )
+ )
+ return False
+ else:
+ assert curve_nid != self._lib.NID_undef
+ self._lib.EC_GROUP_free(ctx)
+ return True
+
+ def elliptic_curve_signature_algorithm_supported(
+ self, signature_algorithm, curve
+ ):
+ if self._lib.Cryptography_HAS_EC != 1:
+ return False
+
+ # We only support ECDSA right now.
+ if not isinstance(signature_algorithm, ec.ECDSA):
+ return False
+
+ # Before 0.9.8m OpenSSL can't cope with digests longer than the curve.
+ if (
+ self._lib.OPENSSL_VERSION_NUMBER < 0x009080df and
+ curve.key_size < signature_algorithm.algorithm.digest_size * 8
+ ):
+ return False
+
+ return self.elliptic_curve_supported(curve)
+
+ def generate_elliptic_curve_private_key(self, curve):
+ """
+ Generate a new private key on the named curve.
+ """
+
+ if self.elliptic_curve_supported(curve):
+ curve_nid = self._elliptic_curve_to_nid(curve)
+
+ ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
+ assert ec_cdata != self._ffi.NULL
+ ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+
+ res = self._lib.EC_KEY_generate_key(ec_cdata)
+ assert res == 1
+
+ res = self._lib.EC_KEY_check_key(ec_cdata)
+ assert res == 1
+
+ return _EllipticCurvePrivateKey(self, ec_cdata)
+ else:
+ raise UnsupportedAlgorithm(
+ "Backend object does not support {0}.".format(curve.name),
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+ def elliptic_curve_private_key_from_numbers(self, numbers):
+ warnings.warn(
+ "elliptic_curve_private_key_from_numbers is deprecated and will "
+ "be removed in a future version.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ return self.load_elliptic_curve_private_numbers(numbers)
+
+ def load_elliptic_curve_private_numbers(self, numbers):
+ public = numbers.public_numbers
+
+ curve_nid = self._elliptic_curve_to_nid(public.curve)
+
+ ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
+ assert ec_cdata != self._ffi.NULL
+ ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+
+ ec_cdata = self._ec_key_set_public_key_affine_coordinates(
+ ec_cdata, public.x, public.y)
+
+ res = self._lib.EC_KEY_set_private_key(
+ ec_cdata, self._int_to_bn(numbers.private_value))
+ assert res == 1
+
+ return _EllipticCurvePrivateKey(self, ec_cdata)
+
+ def elliptic_curve_public_key_from_numbers(self, numbers):
+ warnings.warn(
+ "elliptic_curve_public_key_from_numbers is deprecated and will be "
+ "removed in a future version.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+ return self.load_elliptic_curve_public_numbers(numbers)
+
+ def load_elliptic_curve_public_numbers(self, numbers):
+ curve_nid = self._elliptic_curve_to_nid(numbers.curve)
+
+ ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
+ assert ec_cdata != self._ffi.NULL
+ ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+
+ ec_cdata = self._ec_key_set_public_key_affine_coordinates(
+ ec_cdata, numbers.x, numbers.y)
+
+ return _EllipticCurvePublicKey(self, ec_cdata)
+
+ def _elliptic_curve_to_nid(self, curve):
+ """
+ Get the NID for a curve name.
+ """
+
+ curve_aliases = {
+ "secp192r1": "prime192v1",
+ "secp256r1": "prime256v1"
+ }
+
+ curve_name = curve_aliases.get(curve.name, curve.name)
+
+ curve_nid = self._lib.OBJ_sn2nid(curve_name.encode())
+ if curve_nid == self._lib.NID_undef:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported elliptic curve".format(curve.name),
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+ return curve_nid
+
+ @contextmanager
+ def _tmp_bn_ctx(self):
+ bn_ctx = self._lib.BN_CTX_new()
+ assert bn_ctx != self._ffi.NULL
+ bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free)
+ self._lib.BN_CTX_start(bn_ctx)
+ try:
+ yield bn_ctx
+ finally:
+ self._lib.BN_CTX_end(bn_ctx)
+
+ def _ec_key_determine_group_get_set_funcs(self, ctx):
+ """
+ Given an EC_KEY determine the group and what methods are required to
+ get/set point coordinates.
+ """
+ assert ctx != self._ffi.NULL
+
+ nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field")
+ assert nid_two_field != self._lib.NID_undef
+
+ group = self._lib.EC_KEY_get0_group(ctx)
+ assert group != self._ffi.NULL
+
+ method = self._lib.EC_GROUP_method_of(group)
+ assert method != self._ffi.NULL
+
+ nid = self._lib.EC_METHOD_get_field_type(method)
+ assert nid != self._lib.NID_undef
+
+ if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M:
+ set_func = self._lib.EC_POINT_set_affine_coordinates_GF2m
+ get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m
+ else:
+ set_func = self._lib.EC_POINT_set_affine_coordinates_GFp
+ get_func = self._lib.EC_POINT_get_affine_coordinates_GFp
+
+ assert set_func and get_func
+
+ return set_func, get_func, group
+
+ def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y):
+ """
+ This is a port of EC_KEY_set_public_key_affine_coordinates that was
+ added in 1.0.1.
+
+ Sets the public key point in the EC_KEY context to the affine x and y
+ values.
+ """
+
+ if x < 0 or y < 0:
+ raise ValueError(
+ "Invalid EC key. Both x and y must be non-negative."
+ )
+
+ bn_x = self._int_to_bn(x)
+ bn_y = self._int_to_bn(y)
+
+ set_func, get_func, group = (
+ self._ec_key_determine_group_get_set_funcs(ctx)
+ )
+
+ point = self._lib.EC_POINT_new(group)
+ assert point != self._ffi.NULL
+ point = self._ffi.gc(point, self._lib.EC_POINT_free)
+
+ with self._tmp_bn_ctx() as bn_ctx:
+ check_x = self._lib.BN_CTX_get(bn_ctx)
+ check_y = self._lib.BN_CTX_get(bn_ctx)
+
+ res = set_func(group, point, bn_x, bn_y, bn_ctx)
+ assert res == 1
+
+ res = get_func(group, point, check_x, check_y, bn_ctx)
+ assert res == 1
+
+ assert self._lib.BN_cmp(bn_x, check_x) == 0
+ assert self._lib.BN_cmp(bn_y, check_y) == 0
+
+ res = self._lib.EC_KEY_set_public_key(ctx, point)
+ assert res == 1
+
+ res = self._lib.EC_KEY_check_key(ctx)
+ if res != 1:
+ self._consume_errors()
+ raise ValueError("Invalid EC key.")
+
+ return ctx
+
+
+class GetCipherByName(object):
+ def __init__(self, fmt):
+ self._fmt = fmt
+
+ def __call__(self, backend, cipher, mode):
+ cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower()
+ return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
+
+
+backend = Backend()
diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py
new file mode 100644
index 00000000..4ec2ac89
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/ciphers.py
@@ -0,0 +1,225 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+from cryptography.hazmat.primitives.ciphers.modes import GCM
+
+
+@utils.register_interface(interfaces.CipherContext)
+@utils.register_interface(interfaces.AEADCipherContext)
+@utils.register_interface(interfaces.AEADEncryptionContext)
+class _CipherContext(object):
+ _ENCRYPT = 1
+ _DECRYPT = 0
+
+ def __init__(self, backend, cipher, mode, operation):
+ self._backend = backend
+ self._cipher = cipher
+ self._mode = mode
+ self._operation = operation
+ self._tag = None
+
+ if isinstance(self._cipher, interfaces.BlockCipherAlgorithm):
+ self._block_size = self._cipher.block_size
+ else:
+ self._block_size = 1
+
+ ctx = self._backend._lib.EVP_CIPHER_CTX_new()
+ ctx = self._backend._ffi.gc(
+ ctx, self._backend._lib.EVP_CIPHER_CTX_free
+ )
+
+ registry = self._backend._cipher_registry
+ try:
+ adapter = registry[type(cipher), type(mode)]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ evp_cipher = adapter(self._backend, cipher, mode)
+ if evp_cipher == self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "cipher {0} in {1} mode is not supported "
+ "by this backend.".format(
+ cipher.name, mode.name if mode else mode),
+ _Reasons.UNSUPPORTED_CIPHER
+ )
+
+ if isinstance(mode, interfaces.ModeWithInitializationVector):
+ iv_nonce = mode.initialization_vector
+ elif isinstance(mode, interfaces.ModeWithNonce):
+ iv_nonce = mode.nonce
+ else:
+ iv_nonce = self._backend._ffi.NULL
+ # begin init with cipher and operation type
+ res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ operation)
+ assert res != 0
+ # set the key length to handle variable key ciphers
+ res = self._backend._lib.EVP_CIPHER_CTX_set_key_length(
+ ctx, len(cipher.key)
+ )
+ assert res != 0
+ if isinstance(mode, GCM):
+ res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, self._backend._lib.EVP_CTRL_GCM_SET_IVLEN,
+ len(iv_nonce), self._backend._ffi.NULL
+ )
+ assert res != 0
+ if operation == self._DECRYPT:
+ res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
+ len(mode.tag), mode.tag
+ )
+ assert res != 0
+
+ # pass key/iv
+ res = self._backend._lib.EVP_CipherInit_ex(
+ ctx,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ cipher.key,
+ iv_nonce,
+ operation
+ )
+ assert res != 0
+ # We purposely disable padding here as it's handled higher up in the
+ # API.
+ self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0)
+ self._ctx = ctx
+
+ def update(self, data):
+ # OpenSSL 0.9.8e has an assertion in its EVP code that causes it
+ # to SIGABRT if you call update with an empty byte string. This can be
+ # removed when we drop support for 0.9.8e (CentOS/RHEL 5). This branch
+ # should be taken only when length is zero and mode is not GCM because
+ # AES GCM can return improper tag values if you don't call update
+ # with empty plaintext when authenticating AAD for ...reasons.
+ if len(data) == 0 and not isinstance(self._mode, GCM):
+ return b""
+
+ buf = self._backend._ffi.new("unsigned char[]",
+ len(data) + self._block_size - 1)
+ outlen = self._backend._ffi.new("int *")
+ res = self._backend._lib.EVP_CipherUpdate(self._ctx, buf, outlen, data,
+ len(data))
+ assert res != 0
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def finalize(self):
+ # OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions)
+ # appears to have a bug where you must make at least one call to update
+ # even if you are only using authenticate_additional_data or the
+ # GCM tag will be wrong. An (empty) call to update resolves this
+ # and is harmless for all other versions of OpenSSL.
+ if isinstance(self._mode, GCM):
+ self.update(b"")
+
+ buf = self._backend._ffi.new("unsigned char[]", self._block_size)
+ outlen = self._backend._ffi.new("int *")
+ res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
+ if res == 0:
+ errors = self._backend._consume_errors()
+
+ if not errors and isinstance(self._mode, GCM):
+ raise InvalidTag
+
+ assert errors
+
+ if errors[0][1:] == (
+ self._backend._lib.ERR_LIB_EVP,
+ self._backend._lib.EVP_F_EVP_ENCRYPTFINAL_EX,
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+ ) or errors[0][1:] == (
+ self._backend._lib.ERR_LIB_EVP,
+ self._backend._lib.EVP_F_EVP_DECRYPTFINAL_EX,
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
+ ):
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length."
+ )
+ else:
+ raise self._backend._unknown_error(errors[0])
+
+ if (isinstance(self._mode, GCM) and
+ self._operation == self._ENCRYPT):
+ block_byte_size = self._block_size // 8
+ tag_buf = self._backend._ffi.new(
+ "unsigned char[]", block_byte_size
+ )
+ res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
+ self._ctx, self._backend._lib.EVP_CTRL_GCM_GET_TAG,
+ block_byte_size, tag_buf
+ )
+ assert res != 0
+ self._tag = self._backend._ffi.buffer(tag_buf)[:]
+
+ res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
+ assert res == 1
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def authenticate_additional_data(self, data):
+ outlen = self._backend._ffi.new("int *")
+ res = self._backend._lib.EVP_CipherUpdate(
+ self._ctx, self._backend._ffi.NULL, outlen, data, len(data)
+ )
+ assert res != 0
+
+ tag = utils.read_only_property("_tag")
+
+
+@utils.register_interface(interfaces.CipherContext)
+class _AESCTRCipherContext(object):
+ """
+ This is needed to provide support for AES CTR mode in OpenSSL 0.9.8. It can
+ be removed when we drop 0.9.8 support (RHEL5 extended life ends 2020).
+ """
+ def __init__(self, backend, cipher, mode):
+ self._backend = backend
+
+ self._key = self._backend._ffi.new("AES_KEY *")
+ assert self._key != self._backend._ffi.NULL
+ res = self._backend._lib.AES_set_encrypt_key(
+ cipher.key, len(cipher.key) * 8, self._key
+ )
+ assert res == 0
+ self._ecount = self._backend._ffi.new("char[]", 16)
+ self._nonce = self._backend._ffi.new("char[16]", mode.nonce)
+ self._num = self._backend._ffi.new("unsigned int *", 0)
+
+ def update(self, data):
+ buf = self._backend._ffi.new("unsigned char[]", len(data))
+ self._backend._lib.AES_ctr128_encrypt(
+ data, buf, len(data), self._key, self._nonce,
+ self._ecount, self._num
+ )
+ return self._backend._ffi.buffer(buf)[:]
+
+ def finalize(self):
+ self._key = None
+ self._ecount = None
+ self._nonce = None
+ self._num = None
+ return b""
diff --git a/src/cryptography/hazmat/backends/openssl/cmac.py b/src/cryptography/hazmat/backends/openssl/cmac.py
new file mode 100644
index 00000000..1ad6055b
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/cmac.py
@@ -0,0 +1,89 @@
+# 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
+
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
+from cryptography.hazmat.primitives.ciphers.modes import CBC
+
+
+@utils.register_interface(interfaces.MACContext)
+class _CMACContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ if not backend.cmac_algorithm_supported(algorithm):
+ raise UnsupportedAlgorithm("This backend does not support CMAC.",
+ _Reasons.UNSUPPORTED_CIPHER)
+
+ self._backend = backend
+ self._key = algorithm.key
+ self._algorithm = algorithm
+ self._output_length = algorithm.block_size // 8
+
+ if ctx is None:
+ registry = self._backend._cipher_registry
+ adapter = registry[type(algorithm), CBC]
+
+ evp_cipher = adapter(self._backend, algorithm, CBC)
+
+ ctx = self._backend._lib.CMAC_CTX_new()
+
+ assert ctx != self._backend._ffi.NULL
+ ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
+
+ self._backend._lib.CMAC_Init(
+ ctx, self._key, len(self._key),
+ evp_cipher, self._backend._ffi.NULL
+ )
+
+ self._ctx = ctx
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def update(self, data):
+ res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
+ assert res == 1
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]", self._output_length)
+ length = self._backend._ffi.new("size_t *", self._output_length)
+ res = self._backend._lib.CMAC_Final(
+ self._ctx, buf, length
+ )
+ assert res == 1
+
+ self._ctx = None
+
+ return self._backend._ffi.buffer(buf)[:]
+
+ def copy(self):
+ copied_ctx = self._backend._lib.CMAC_CTX_new()
+ copied_ctx = self._backend._ffi.gc(
+ copied_ctx, self._backend._lib.CMAC_CTX_free
+ )
+ res = self._backend._lib.CMAC_CTX_copy(
+ copied_ctx, self._ctx
+ )
+ assert res == 1
+ return _CMACContext(
+ self._backend, self._algorithm, ctx=copied_ctx
+ )
+
+ def verify(self, signature):
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py
new file mode 100644
index 00000000..8652d50b
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/dsa.py
@@ -0,0 +1,207 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.backends.openssl.utils import _truncate_digest
+from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives.asymmetric import dsa
+from cryptography.hazmat.primitives.interfaces import (
+ DSAParametersWithNumbers, DSAPrivateKeyWithNumbers, DSAPublicKeyWithNumbers
+)
+
+
+def _truncate_digest_for_dsa(dsa_cdata, digest, backend):
+ """
+ This function truncates digests that are longer than a given DS
+ key's length so they can be signed. OpenSSL does this for us in
+ 1.0.0c+ and it isn't needed in 0.9.8, but that leaves us with three
+ releases (1.0.0, 1.0.0a, and 1.0.0b) where this is a problem. This
+ truncation is not required in 0.9.8 because DSA is limited to SHA-1.
+ """
+
+ order_bits = backend._lib.BN_num_bits(dsa_cdata.q)
+ return _truncate_digest(digest, order_bits)
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _DSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+ self._algorithm = algorithm
+
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def verify(self):
+ self._dsa_cdata = self._backend._ffi.gc(self._public_key._dsa_cdata,
+ self._backend._lib.DSA_free)
+
+ data_to_verify = self._hash_ctx.finalize()
+
+ data_to_verify = _truncate_digest_for_dsa(
+ self._dsa_cdata, data_to_verify, self._backend
+ )
+
+ # The first parameter passed to DSA_verify is unused by OpenSSL but
+ # must be an integer.
+ res = self._backend._lib.DSA_verify(
+ 0, data_to_verify, len(data_to_verify), self._signature,
+ len(self._signature), self._public_key._dsa_cdata)
+
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors
+ if res == -1:
+ assert errors[0].lib == self._backend._lib.ERR_LIB_ASN1
+
+ raise InvalidSignature
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _DSASignatureContext(object):
+ def __init__(self, backend, private_key, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+ self._algorithm = algorithm
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def finalize(self):
+ data_to_sign = self._hash_ctx.finalize()
+ data_to_sign = _truncate_digest_for_dsa(
+ self._private_key._dsa_cdata, data_to_sign, self._backend
+ )
+ sig_buf_len = self._backend._lib.DSA_size(self._private_key._dsa_cdata)
+ sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len)
+ buflen = self._backend._ffi.new("unsigned int *")
+
+ # The first parameter passed to DSA_sign is unused by OpenSSL but
+ # must be an integer.
+ res = self._backend._lib.DSA_sign(
+ 0, data_to_sign, len(data_to_sign), sig_buf,
+ buflen, self._private_key._dsa_cdata)
+ assert res == 1
+ assert buflen[0]
+
+ return self._backend._ffi.buffer(sig_buf)[:buflen[0]]
+
+
+@utils.register_interface(DSAParametersWithNumbers)
+class _DSAParameters(object):
+ def __init__(self, backend, dsa_cdata):
+ self._backend = backend
+ self._dsa_cdata = dsa_cdata
+
+ def parameter_numbers(self):
+ return dsa.DSAParameterNumbers(
+ p=self._backend._bn_to_int(self._dsa_cdata.p),
+ q=self._backend._bn_to_int(self._dsa_cdata.q),
+ g=self._backend._bn_to_int(self._dsa_cdata.g)
+ )
+
+ def generate_private_key(self):
+ return self._backend.generate_dsa_private_key(self)
+
+
+@utils.register_interface(DSAPrivateKeyWithNumbers)
+class _DSAPrivateKey(object):
+ def __init__(self, backend, dsa_cdata):
+ self._backend = backend
+ self._dsa_cdata = dsa_cdata
+ self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
+
+ key_size = utils.read_only_property("_key_size")
+
+ def signer(self, signature_algorithm):
+ return _DSASignatureContext(self._backend, self, signature_algorithm)
+
+ def private_numbers(self):
+ return dsa.DSAPrivateNumbers(
+ public_numbers=dsa.DSAPublicNumbers(
+ parameter_numbers=dsa.DSAParameterNumbers(
+ p=self._backend._bn_to_int(self._dsa_cdata.p),
+ q=self._backend._bn_to_int(self._dsa_cdata.q),
+ g=self._backend._bn_to_int(self._dsa_cdata.g)
+ ),
+ y=self._backend._bn_to_int(self._dsa_cdata.pub_key)
+ ),
+ x=self._backend._bn_to_int(self._dsa_cdata.priv_key)
+ )
+
+ def public_key(self):
+ dsa_cdata = self._backend._lib.DSA_new()
+ assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._ffi.gc(
+ dsa_cdata, self._backend._lib.DSA_free
+ )
+ dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p)
+ dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q)
+ dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
+ dsa_cdata.pub_key = self._backend._lib.BN_dup(self._dsa_cdata.pub_key)
+ return _DSAPublicKey(self._backend, dsa_cdata)
+
+ def parameters(self):
+ dsa_cdata = self._backend._lib.DSA_new()
+ assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._ffi.gc(
+ dsa_cdata, self._backend._lib.DSA_free
+ )
+ dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p)
+ dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q)
+ dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
+ return _DSAParameters(self._backend, dsa_cdata)
+
+
+@utils.register_interface(DSAPublicKeyWithNumbers)
+class _DSAPublicKey(object):
+ def __init__(self, backend, dsa_cdata):
+ self._backend = backend
+ self._dsa_cdata = dsa_cdata
+ self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
+
+ key_size = utils.read_only_property("_key_size")
+
+ def verifier(self, signature, signature_algorithm):
+ return _DSAVerificationContext(
+ self._backend, self, signature, signature_algorithm
+ )
+
+ def public_numbers(self):
+ return dsa.DSAPublicNumbers(
+ parameter_numbers=dsa.DSAParameterNumbers(
+ p=self._backend._bn_to_int(self._dsa_cdata.p),
+ q=self._backend._bn_to_int(self._dsa_cdata.q),
+ g=self._backend._bn_to_int(self._dsa_cdata.g)
+ ),
+ y=self._backend._bn_to_int(self._dsa_cdata.pub_key)
+ )
+
+ def parameters(self):
+ dsa_cdata = self._backend._lib.DSA_new()
+ assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._ffi.gc(
+ dsa_cdata, self._backend._lib.DSA_free
+ )
+ dsa_cdata.p = self._backend._lib.BN_dup(self._dsa_cdata.p)
+ dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q)
+ dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g)
+ return _DSAParameters(self._backend, dsa_cdata)
diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py
new file mode 100644
index 00000000..13b0ddbb
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/ec.py
@@ -0,0 +1,234 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.openssl.utils import _truncate_digest
+from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives.asymmetric import ec
+
+
+def _truncate_digest_for_ecdsa(ec_key_cdata, digest, backend):
+ """
+ This function truncates digests that are longer than a given elliptic
+ curve key's length so they can be signed. Since elliptic curve keys are
+ much shorter than RSA keys many digests (e.g. SHA-512) may require
+ truncation.
+ """
+
+ _lib = backend._lib
+ _ffi = backend._ffi
+
+ group = _lib.EC_KEY_get0_group(ec_key_cdata)
+
+ with backend._tmp_bn_ctx() as bn_ctx:
+ order = _lib.BN_CTX_get(bn_ctx)
+ assert order != _ffi.NULL
+
+ res = _lib.EC_GROUP_get_order(group, order, bn_ctx)
+ assert res == 1
+
+ order_bits = _lib.BN_num_bits(order)
+
+ return _truncate_digest(digest, order_bits)
+
+
+def _ec_key_curve_sn(backend, ec_key):
+ group = backend._lib.EC_KEY_get0_group(ec_key)
+ assert group != backend._ffi.NULL
+
+ nid = backend._lib.EC_GROUP_get_curve_name(group)
+ assert nid != backend._lib.NID_undef
+
+ curve_name = backend._lib.OBJ_nid2sn(nid)
+ assert curve_name != backend._ffi.NULL
+
+ sn = backend._ffi.string(curve_name).decode('ascii')
+ return sn
+
+
+def _sn_to_elliptic_curve(backend, sn):
+ try:
+ return ec._CURVE_TYPES[sn]()
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported elliptic curve".format(sn),
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ )
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _ECDSASignatureContext(object):
+ def __init__(self, backend, private_key, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+ self._digest = hashes.Hash(algorithm, backend)
+
+ def update(self, data):
+ self._digest.update(data)
+
+ def finalize(self):
+ ec_key = self._private_key._ec_key
+
+ digest = self._digest.finalize()
+
+ digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+ max_size = self._backend._lib.ECDSA_size(ec_key)
+ assert max_size > 0
+
+ sigbuf = self._backend._ffi.new("char[]", max_size)
+ siglen_ptr = self._backend._ffi.new("unsigned int[]", 1)
+ res = self._backend._lib.ECDSA_sign(
+ 0,
+ digest,
+ len(digest),
+ sigbuf,
+ siglen_ptr,
+ ec_key
+ )
+ assert res == 1
+ return self._backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _ECDSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+ self._digest = hashes.Hash(algorithm, backend)
+
+ def update(self, data):
+ self._digest.update(data)
+
+ def verify(self):
+ ec_key = self._public_key._ec_key
+
+ digest = self._digest.finalize()
+
+ digest = _truncate_digest_for_ecdsa(ec_key, digest, self._backend)
+
+ res = self._backend._lib.ECDSA_verify(
+ 0,
+ digest,
+ len(digest),
+ self._signature,
+ len(self._signature),
+ ec_key
+ )
+ if res != 1:
+ self._backend._consume_errors()
+ raise InvalidSignature
+ return True
+
+
+@utils.register_interface(interfaces.EllipticCurvePrivateKeyWithNumbers)
+class _EllipticCurvePrivateKey(object):
+ def __init__(self, backend, ec_key_cdata):
+ self._backend = backend
+ self._ec_key = ec_key_cdata
+
+ sn = _ec_key_curve_sn(backend, ec_key_cdata)
+ self._curve = _sn_to_elliptic_curve(backend, sn)
+
+ curve = utils.read_only_property("_curve")
+
+ def signer(self, signature_algorithm):
+ if isinstance(signature_algorithm, ec.ECDSA):
+ return _ECDSASignatureContext(
+ self._backend, self, signature_algorithm.algorithm
+ )
+ else:
+ raise UnsupportedAlgorithm(
+ "Unsupported elliptic curve signature algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def public_key(self):
+ group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
+ assert group != self._backend._ffi.NULL
+
+ curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group)
+
+ public_ec_key = self._backend._lib.EC_KEY_new_by_curve_name(curve_nid)
+ assert public_ec_key != self._backend._ffi.NULL
+ public_ec_key = self._backend._ffi.gc(
+ public_ec_key, self._backend._lib.EC_KEY_free
+ )
+
+ point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
+ assert point != self._backend._ffi.NULL
+
+ res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
+ assert res == 1
+
+ return _EllipticCurvePublicKey(
+ self._backend, public_ec_key
+ )
+
+ def private_numbers(self):
+ bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key)
+ private_value = self._backend._bn_to_int(bn)
+ return ec.EllipticCurvePrivateNumbers(
+ private_value=private_value,
+ public_numbers=self.public_key().public_numbers()
+ )
+
+
+@utils.register_interface(interfaces.EllipticCurvePublicKeyWithNumbers)
+class _EllipticCurvePublicKey(object):
+ def __init__(self, backend, ec_key_cdata):
+ self._backend = backend
+ self._ec_key = ec_key_cdata
+
+ sn = _ec_key_curve_sn(backend, ec_key_cdata)
+ self._curve = _sn_to_elliptic_curve(backend, sn)
+
+ curve = utils.read_only_property("_curve")
+
+ def verifier(self, signature, signature_algorithm):
+ if isinstance(signature_algorithm, ec.ECDSA):
+ return _ECDSAVerificationContext(
+ self._backend, self, signature, signature_algorithm.algorithm
+ )
+ else:
+ raise UnsupportedAlgorithm(
+ "Unsupported elliptic curve signature algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def public_numbers(self):
+ set_func, get_func, group = (
+ self._backend._ec_key_determine_group_get_set_funcs(self._ec_key)
+ )
+ point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
+ assert point != self._backend._ffi.NULL
+
+ with self._backend._tmp_bn_ctx() as bn_ctx:
+ bn_x = self._backend._lib.BN_CTX_get(bn_ctx)
+ bn_y = self._backend._lib.BN_CTX_get(bn_ctx)
+
+ res = get_func(group, point, bn_x, bn_y, bn_ctx)
+ assert res == 1
+
+ x = self._backend._bn_to_int(bn_x)
+ y = self._backend._bn_to_int(bn_y)
+
+ return ec.EllipticCurvePublicNumbers(
+ x=x,
+ y=y,
+ curve=self._curve
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py
new file mode 100644
index 00000000..591c014a
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/hashes.py
@@ -0,0 +1,71 @@
+# 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
+
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class _HashContext(object):
+ def __init__(self, backend, algorithm, ctx=None):
+ self._algorithm = algorithm
+
+ self._backend = backend
+
+ if ctx is None:
+ ctx = self._backend._lib.EVP_MD_CTX_create()
+ ctx = self._backend._ffi.gc(ctx,
+ self._backend._lib.EVP_MD_CTX_destroy)
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ algorithm.name.encode("ascii"))
+ if evp_md == self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+ res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
+ self._backend._ffi.NULL)
+ assert res != 0
+
+ self._ctx = ctx
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def copy(self):
+ copied_ctx = self._backend._lib.EVP_MD_CTX_create()
+ copied_ctx = self._backend._ffi.gc(
+ copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
+ )
+ res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
+ assert res != 0
+ return _HashContext(self._backend, self.algorithm, ctx=copied_ctx)
+
+ def update(self, data):
+ res = self._backend._lib.EVP_DigestUpdate(self._ctx, data, len(data))
+ assert res != 0
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]",
+ self._backend._lib.EVP_MAX_MD_SIZE)
+ outlen = self._backend._ffi.new("unsigned int *")
+ res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen)
+ assert res != 0
+ assert outlen[0] == self.algorithm.digest_size
+ res = self._backend._lib.EVP_MD_CTX_cleanup(self._ctx)
+ assert res == 1
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py
new file mode 100644
index 00000000..c324bd8c
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/hmac.py
@@ -0,0 +1,90 @@
+# 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
+
+
+from cryptography import utils
+from cryptography.exceptions import (
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import constant_time, interfaces
+
+
+@utils.register_interface(interfaces.MACContext)
+@utils.register_interface(interfaces.HashContext)
+class _HMACContext(object):
+ def __init__(self, backend, key, algorithm, ctx=None):
+ self._algorithm = algorithm
+ self._backend = backend
+
+ if ctx is None:
+ ctx = self._backend._ffi.new("HMAC_CTX *")
+ self._backend._lib.HMAC_CTX_init(ctx)
+ ctx = self._backend._ffi.gc(
+ ctx, self._backend._lib.HMAC_CTX_cleanup
+ )
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ algorithm.name.encode('ascii'))
+ if evp_md == self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "{0} is not a supported hash on this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+ res = self._backend._lib.Cryptography_HMAC_Init_ex(
+ ctx, key, len(key), evp_md, self._backend._ffi.NULL
+ )
+ assert res != 0
+
+ self._ctx = ctx
+ self._key = key
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def copy(self):
+ copied_ctx = self._backend._ffi.new("HMAC_CTX *")
+ self._backend._lib.HMAC_CTX_init(copied_ctx)
+ copied_ctx = self._backend._ffi.gc(
+ copied_ctx, self._backend._lib.HMAC_CTX_cleanup
+ )
+ res = self._backend._lib.Cryptography_HMAC_CTX_copy(
+ copied_ctx, self._ctx
+ )
+ assert res != 0
+ return _HMACContext(
+ self._backend, self._key, self.algorithm, ctx=copied_ctx
+ )
+
+ def update(self, data):
+ res = self._backend._lib.Cryptography_HMAC_Update(
+ self._ctx, data, len(data)
+ )
+ assert res != 0
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]",
+ self._backend._lib.EVP_MAX_MD_SIZE)
+ outlen = self._backend._ffi.new("unsigned int *")
+ res = self._backend._lib.Cryptography_HMAC_Final(
+ self._ctx, buf, outlen
+ )
+ assert res != 0
+ assert outlen[0] == self.algorithm.digest_size
+ self._backend._lib.HMAC_CTX_cleanup(self._ctx)
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def verify(self, signature):
+ digest = self.finalize()
+ if not constant_time.bytes_eq(digest, signature):
+ raise InvalidSignature("Signature did not match digest.")
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
new file mode 100644
index 00000000..0a2a7f96
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -0,0 +1,603 @@
+# 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 math
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives.asymmetric import rsa
+from cryptography.hazmat.primitives.asymmetric.padding import (
+ MGF1, OAEP, PKCS1v15, PSS
+)
+from cryptography.hazmat.primitives.interfaces import (
+ RSAPrivateKeyWithNumbers, RSAPublicKeyWithNumbers
+)
+
+
+def _get_rsa_pss_salt_length(pss, key_size, digest_size):
+ salt = pss._salt_length
+
+ if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH:
+ # bit length - 1 per RFC 3447
+ emlen = int(math.ceil((key_size - 1) / 8.0))
+ salt_length = emlen - digest_size - 2
+ assert salt_length >= 0
+ return salt_length
+ else:
+ return salt
+
+
+def _enc_dec_rsa(backend, key, data, padding):
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError("Padding must be an instance of AsymmetricPadding.")
+
+ if isinstance(padding, PKCS1v15):
+ padding_enum = backend._lib.RSA_PKCS1_PADDING
+ elif isinstance(padding, OAEP):
+ padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend.",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ if not isinstance(padding._mgf._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend supports only SHA1 inside MGF1 when "
+ "using OAEP.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if padding._label is not None and padding._label != b"":
+ raise ValueError("This backend does not support OAEP labels.")
+
+ if not isinstance(padding._algorithm, hashes.SHA1):
+ raise UnsupportedAlgorithm(
+ "This backend only supports SHA1 when using OAEP.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend.".format(
+ padding.name
+ ),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ if backend._lib.Cryptography_HAS_PKEY_CTX:
+ return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum)
+ else:
+ return _enc_dec_rsa_098(backend, key, data, padding_enum)
+
+
+def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
+ if isinstance(key, _RSAPublicKey):
+ init = backend._lib.EVP_PKEY_encrypt_init
+ crypt = backend._lib.Cryptography_EVP_PKEY_encrypt
+ else:
+ init = backend._lib.EVP_PKEY_decrypt_init
+ crypt = backend._lib.Cryptography_EVP_PKEY_decrypt
+
+ pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
+ key._evp_pkey, backend._ffi.NULL
+ )
+ assert pkey_ctx != backend._ffi.NULL
+ pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
+ res = init(pkey_ctx)
+ assert res == 1
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, padding_enum)
+ assert res > 0
+ buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
+ assert buf_size > 0
+ outlen = backend._ffi.new("size_t *", buf_size)
+ buf = backend._ffi.new("char[]", buf_size)
+ res = crypt(pkey_ctx, buf, outlen, data, len(data))
+ if res <= 0:
+ _handle_rsa_enc_dec_error(backend, key)
+
+ return backend._ffi.buffer(buf)[:outlen[0]]
+
+
+def _enc_dec_rsa_098(backend, key, data, padding_enum):
+ if isinstance(key, _RSAPublicKey):
+ crypt = backend._lib.RSA_public_encrypt
+ else:
+ crypt = backend._lib.RSA_private_decrypt
+
+ key_size = backend._lib.RSA_size(key._rsa_cdata)
+ assert key_size > 0
+ buf = backend._ffi.new("unsigned char[]", key_size)
+ res = crypt(len(data), data, buf, key._rsa_cdata, padding_enum)
+ if res < 0:
+ _handle_rsa_enc_dec_error(backend, key)
+
+ return backend._ffi.buffer(buf)[:res]
+
+
+def _handle_rsa_enc_dec_error(backend, key):
+ errors = backend._consume_errors()
+ assert errors
+ assert errors[0].lib == backend._lib.ERR_LIB_RSA
+ if isinstance(key, _RSAPublicKey):
+ assert (errors[0].reason ==
+ backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
+ raise ValueError(
+ "Data too long for key size. Encrypt less data or use a "
+ "larger key size."
+ )
+ else:
+ decoding_errors = [
+ backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
+ backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
+ ]
+ if backend._lib.Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR:
+ decoding_errors.append(backend._lib.RSA_R_PKCS_DECODING_ERROR)
+
+ assert errors[0].reason in decoding_errors
+ raise ValueError("Decryption failed.")
+
+
+@utils.register_interface(interfaces.AsymmetricSignatureContext)
+class _RSASignatureContext(object):
+ def __init__(self, backend, private_key, padding, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError(
+ "Expected provider of interfaces.AsymmetricPadding.")
+
+ self._pkey_size = self._backend._lib.EVP_PKEY_size(
+ self._private_key._evp_pkey
+ )
+
+ if isinstance(padding, PKCS1v15):
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._finalize_method = self._finalize_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
+ else:
+ self._finalize_method = self._finalize_pkcs1
+ elif isinstance(padding, PSS):
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend.",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ # Size of key in bytes - 2 is the maximum
+ # PSS signature length (salt length is checked later)
+ assert self._pkey_size > 0
+ if self._pkey_size - algorithm.digest_size - 2 < 0:
+ raise ValueError("Digest too large for key size. Use a larger "
+ "key.")
+
+ if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
+ raise UnsupportedAlgorithm(
+ "When OpenSSL is older than 1.0.1 then only SHA1 is "
+ "supported with MGF1.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._finalize_method = self._finalize_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
+ else:
+ self._finalize_method = self._finalize_pss
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ self._padding = padding
+ self._algorithm = algorithm
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def finalize(self):
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ self._algorithm.name.encode("ascii"))
+ assert evp_md != self._backend._ffi.NULL
+
+ return self._finalize_method(evp_md)
+
+ def _finalize_pkey_ctx(self, evp_md):
+ pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
+ self._private_key._evp_pkey, self._backend._ffi.NULL
+ )
+ assert pkey_ctx != self._backend._ffi.NULL
+ pkey_ctx = self._backend._ffi.gc(pkey_ctx,
+ self._backend._lib.EVP_PKEY_CTX_free)
+ res = self._backend._lib.EVP_PKEY_sign_init(pkey_ctx)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
+ pkey_ctx, evp_md)
+ assert res > 0
+
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, self._padding_enum)
+ assert res > 0
+ if isinstance(self._padding, PSS):
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ pkey_ctx,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._private_key.key_size,
+ self._hash_ctx.algorithm.digest_size
+ )
+ )
+ assert res > 0
+
+ if self._backend._lib.Cryptography_HAS_MGF1_MD:
+ # MGF1 MD is configurable in OpenSSL 1.0.1+
+ mgf1_md = self._backend._lib.EVP_get_digestbyname(
+ self._padding._mgf._algorithm.name.encode("ascii"))
+ assert mgf1_md != self._backend._ffi.NULL
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
+ pkey_ctx, mgf1_md
+ )
+ assert res > 0
+ data_to_sign = self._hash_ctx.finalize()
+ buflen = self._backend._ffi.new("size_t *")
+ res = self._backend._lib.EVP_PKEY_sign(
+ pkey_ctx,
+ self._backend._ffi.NULL,
+ buflen,
+ data_to_sign,
+ len(data_to_sign)
+ )
+ assert res == 1
+ buf = self._backend._ffi.new("unsigned char[]", buflen[0])
+ res = self._backend._lib.EVP_PKEY_sign(
+ pkey_ctx, buf, buflen, data_to_sign, len(data_to_sign))
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ reason = None
+ if (errors[0].reason ==
+ self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE):
+ reason = ("Salt length too long for key size. Try using "
+ "MAX_LENGTH instead.")
+ elif (errors[0].reason ==
+ self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY):
+ reason = "Digest too large for key size. Use a larger key."
+ assert reason is not None
+ raise ValueError(reason)
+
+ return self._backend._ffi.buffer(buf)[:]
+
+ def _finalize_pkcs1(self, evp_md):
+ if self._hash_ctx._ctx is None:
+ raise AlreadyFinalized("Context has already been finalized.")
+
+ sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
+ sig_len = self._backend._ffi.new("unsigned int *")
+ res = self._backend._lib.EVP_SignFinal(
+ self._hash_ctx._ctx._ctx,
+ sig_buf,
+ sig_len,
+ self._private_key._evp_pkey
+ )
+ self._hash_ctx.finalize()
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ assert (errors[0].reason ==
+ self._backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY)
+ raise ValueError("Digest too large for key size. Use a larger "
+ "key.")
+
+ return self._backend._ffi.buffer(sig_buf)[:sig_len[0]]
+
+ def _finalize_pss(self, evp_md):
+ data_to_sign = self._hash_ctx.finalize()
+ padded = self._backend._ffi.new("unsigned char[]", self._pkey_size)
+ res = self._backend._lib.RSA_padding_add_PKCS1_PSS(
+ self._private_key._rsa_cdata,
+ padded,
+ data_to_sign,
+ evp_md,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._private_key.key_size,
+ len(data_to_sign)
+ )
+ )
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors[0].lib == self._backend._lib.ERR_LIB_RSA
+ assert (errors[0].reason ==
+ self._backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
+ raise ValueError("Salt length too long for key size. Try using "
+ "MAX_LENGTH instead.")
+
+ sig_buf = self._backend._ffi.new("char[]", self._pkey_size)
+ sig_len = self._backend._lib.RSA_private_encrypt(
+ self._pkey_size,
+ padded,
+ sig_buf,
+ self._private_key._rsa_cdata,
+ self._backend._lib.RSA_NO_PADDING
+ )
+ assert sig_len != -1
+ return self._backend._ffi.buffer(sig_buf)[:sig_len]
+
+
+@utils.register_interface(interfaces.AsymmetricVerificationContext)
+class _RSAVerificationContext(object):
+ def __init__(self, backend, public_key, signature, padding, algorithm):
+ self._backend = backend
+ self._public_key = public_key
+ self._signature = signature
+
+ if not isinstance(padding, interfaces.AsymmetricPadding):
+ raise TypeError(
+ "Expected provider of interfaces.AsymmetricPadding.")
+
+ self._pkey_size = self._backend._lib.EVP_PKEY_size(
+ self._public_key._evp_pkey
+ )
+
+ if isinstance(padding, PKCS1v15):
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._verify_method = self._verify_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING
+ else:
+ self._verify_method = self._verify_pkcs1
+ elif isinstance(padding, PSS):
+ if not isinstance(padding._mgf, MGF1):
+ raise UnsupportedAlgorithm(
+ "Only MGF1 is supported by this backend.",
+ _Reasons.UNSUPPORTED_MGF
+ )
+
+ # Size of key in bytes - 2 is the maximum
+ # PSS signature length (salt length is checked later)
+ assert self._pkey_size > 0
+ if self._pkey_size - algorithm.digest_size - 2 < 0:
+ raise ValueError(
+ "Digest too large for key size. Check that you have the "
+ "correct key and digest algorithm."
+ )
+
+ if not self._backend._mgf1_hash_supported(padding._mgf._algorithm):
+ raise UnsupportedAlgorithm(
+ "When OpenSSL is older than 1.0.1 then only SHA1 is "
+ "supported with MGF1.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if self._backend._lib.Cryptography_HAS_PKEY_CTX:
+ self._verify_method = self._verify_pkey_ctx
+ self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING
+ else:
+ self._verify_method = self._verify_pss
+ else:
+ raise UnsupportedAlgorithm(
+ "{0} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ self._padding = padding
+ self._algorithm = algorithm
+ self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
+
+ def update(self, data):
+ self._hash_ctx.update(data)
+
+ def verify(self):
+ evp_md = self._backend._lib.EVP_get_digestbyname(
+ self._algorithm.name.encode("ascii"))
+ assert evp_md != self._backend._ffi.NULL
+
+ self._verify_method(evp_md)
+
+ def _verify_pkey_ctx(self, evp_md):
+ pkey_ctx = self._backend._lib.EVP_PKEY_CTX_new(
+ self._public_key._evp_pkey, self._backend._ffi.NULL
+ )
+ assert pkey_ctx != self._backend._ffi.NULL
+ pkey_ctx = self._backend._ffi.gc(pkey_ctx,
+ self._backend._lib.EVP_PKEY_CTX_free)
+ res = self._backend._lib.EVP_PKEY_verify_init(pkey_ctx)
+ assert res == 1
+ res = self._backend._lib.EVP_PKEY_CTX_set_signature_md(
+ pkey_ctx, evp_md)
+ assert res > 0
+
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding(
+ pkey_ctx, self._padding_enum)
+ assert res > 0
+ if isinstance(self._padding, PSS):
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ pkey_ctx,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._public_key.key_size,
+ self._hash_ctx.algorithm.digest_size
+ )
+ )
+ assert res > 0
+ if self._backend._lib.Cryptography_HAS_MGF1_MD:
+ # MGF1 MD is configurable in OpenSSL 1.0.1+
+ mgf1_md = self._backend._lib.EVP_get_digestbyname(
+ self._padding._mgf._algorithm.name.encode("ascii"))
+ assert mgf1_md != self._backend._ffi.NULL
+ res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(
+ pkey_ctx, mgf1_md
+ )
+ assert res > 0
+
+ data_to_verify = self._hash_ctx.finalize()
+ res = self._backend._lib.EVP_PKEY_verify(
+ pkey_ctx,
+ self._signature,
+ len(self._signature),
+ data_to_verify,
+ len(data_to_verify)
+ )
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ def _verify_pkcs1(self, evp_md):
+ if self._hash_ctx._ctx is None:
+ raise AlreadyFinalized("Context has already been finalized.")
+
+ res = self._backend._lib.EVP_VerifyFinal(
+ self._hash_ctx._ctx._ctx,
+ self._signature,
+ len(self._signature),
+ self._public_key._evp_pkey
+ )
+ self._hash_ctx.finalize()
+ # The previous call can return negative numbers in the event of an
+ # error. This is not a signature failure but we need to fail if it
+ # occurs.
+ assert res >= 0
+ if res == 0:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ def _verify_pss(self, evp_md):
+ buf = self._backend._ffi.new("unsigned char[]", self._pkey_size)
+ res = self._backend._lib.RSA_public_decrypt(
+ len(self._signature),
+ self._signature,
+ buf,
+ self._public_key._rsa_cdata,
+ self._backend._lib.RSA_NO_PADDING
+ )
+ if res != self._pkey_size:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+ data_to_verify = self._hash_ctx.finalize()
+ res = self._backend._lib.RSA_verify_PKCS1_PSS(
+ self._public_key._rsa_cdata,
+ data_to_verify,
+ evp_md,
+ buf,
+ _get_rsa_pss_salt_length(
+ self._padding,
+ self._public_key.key_size,
+ len(data_to_verify)
+ )
+ )
+ if res != 1:
+ errors = self._backend._consume_errors()
+ assert errors
+ raise InvalidSignature
+
+
+@utils.register_interface(RSAPrivateKeyWithNumbers)
+class _RSAPrivateKey(object):
+ def __init__(self, backend, rsa_cdata):
+ self._backend = backend
+ self._rsa_cdata = rsa_cdata
+
+ evp_pkey = self._backend._lib.EVP_PKEY_new()
+ assert evp_pkey != self._backend._ffi.NULL
+ evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
+ assert res == 1
+ self._evp_pkey = evp_pkey
+
+ self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+ key_size = utils.read_only_property("_key_size")
+
+ def signer(self, padding, algorithm):
+ return _RSASignatureContext(self._backend, self, padding, algorithm)
+
+ def decrypt(self, ciphertext, padding):
+ key_size_bytes = int(math.ceil(self.key_size / 8.0))
+ if key_size_bytes != len(ciphertext):
+ raise ValueError("Ciphertext length must be equal to key size.")
+
+ return _enc_dec_rsa(self._backend, self, ciphertext, padding)
+
+ def public_key(self):
+ ctx = self._backend._lib.RSA_new()
+ assert ctx != self._backend._ffi.NULL
+ ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free)
+ ctx.e = self._backend._lib.BN_dup(self._rsa_cdata.e)
+ ctx.n = self._backend._lib.BN_dup(self._rsa_cdata.n)
+ res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
+ assert res == 1
+ return _RSAPublicKey(self._backend, ctx)
+
+ def private_numbers(self):
+ return rsa.RSAPrivateNumbers(
+ p=self._backend._bn_to_int(self._rsa_cdata.p),
+ q=self._backend._bn_to_int(self._rsa_cdata.q),
+ d=self._backend._bn_to_int(self._rsa_cdata.d),
+ dmp1=self._backend._bn_to_int(self._rsa_cdata.dmp1),
+ dmq1=self._backend._bn_to_int(self._rsa_cdata.dmq1),
+ iqmp=self._backend._bn_to_int(self._rsa_cdata.iqmp),
+ public_numbers=rsa.RSAPublicNumbers(
+ e=self._backend._bn_to_int(self._rsa_cdata.e),
+ n=self._backend._bn_to_int(self._rsa_cdata.n),
+ )
+ )
+
+
+@utils.register_interface(RSAPublicKeyWithNumbers)
+class _RSAPublicKey(object):
+ def __init__(self, backend, rsa_cdata):
+ self._backend = backend
+ self._rsa_cdata = rsa_cdata
+
+ evp_pkey = self._backend._lib.EVP_PKEY_new()
+ assert evp_pkey != self._backend._ffi.NULL
+ evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ res = self._backend._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
+ assert res == 1
+ self._evp_pkey = evp_pkey
+
+ self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+
+ key_size = utils.read_only_property("_key_size")
+
+ def verifier(self, signature, padding, algorithm):
+ return _RSAVerificationContext(
+ self._backend, self, signature, padding, algorithm
+ )
+
+ def encrypt(self, plaintext, padding):
+ return _enc_dec_rsa(self._backend, self, plaintext, padding)
+
+ def public_numbers(self):
+ return rsa.RSAPublicNumbers(
+ e=self._backend._bn_to_int(self._rsa_cdata.e),
+ n=self._backend._bn_to_int(self._rsa_cdata.n),
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py
new file mode 100644
index 00000000..408b6146
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/utils.py
@@ -0,0 +1,35 @@
+# 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 six
+
+
+def _truncate_digest(digest, order_bits):
+ digest_len = len(digest)
+
+ if 8 * digest_len > order_bits:
+ digest_len = (order_bits + 7) // 8
+ digest = digest[:digest_len]
+
+ if 8 * digest_len > order_bits:
+ rshift = 8 - (order_bits & 0x7)
+ assert rshift > 0 and rshift < 8
+
+ mask = 0xFF >> rshift << rshift
+
+ # Set the bottom rshift bits to 0
+ digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
+
+ return digest
diff --git a/src/cryptography/hazmat/bindings/__init__.py b/src/cryptography/hazmat/bindings/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/__init__.py b/src/cryptography/hazmat/bindings/commoncrypto/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/binding.py b/src/cryptography/hazmat/bindings/commoncrypto/binding.py
new file mode 100644
index 00000000..bb950aac
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -0,0 +1,60 @@
+# 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
+
+from cryptography.hazmat.bindings.utils import (
+ build_ffi_for_binding, load_library_for_binding,
+)
+
+
+class Binding(object):
+ """
+ CommonCrypto API wrapper.
+ """
+ _module_prefix = "cryptography.hazmat.bindings.commoncrypto."
+ _modules = [
+ "cf",
+ "common_digest",
+ "common_hmac",
+ "common_key_derivation",
+ "common_cryptor",
+ "secimport",
+ "secitem",
+ "seckey",
+ "seckeychain",
+ "sectransform",
+ ]
+
+ ffi = build_ffi_for_binding(
+ module_prefix=_module_prefix,
+ modules=_modules,
+ extra_link_args=[
+ "-framework", "Security", "-framework", "CoreFoundation"
+ ],
+ )
+ lib = None
+
+ def __init__(self):
+ self._ensure_ffi_initialized()
+
+ @classmethod
+ def _ensure_ffi_initialized(cls):
+ if cls.lib is not None:
+ return
+
+ cls.lib = load_library_for_binding(
+ cls.ffi,
+ module_prefix=cls._module_prefix,
+ modules=cls._modules,
+ )
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/cf.py b/src/cryptography/hazmat/bindings/commoncrypto/cf.py
new file mode 100644
index 00000000..671963a3
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/cf.py
@@ -0,0 +1,114 @@
+# 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
+
+INCLUDES = """
+#include <CoreFoundation/CoreFoundation.h>
+"""
+
+TYPES = """
+typedef bool Boolean;
+typedef signed long OSStatus;
+typedef unsigned char UInt8;
+typedef uint32_t UInt32;
+
+typedef const void * CFAllocatorRef;
+const CFAllocatorRef kCFAllocatorDefault;
+typedef const void * CFDataRef;
+typedef signed long long CFIndex;
+typedef ... *CFStringRef;
+typedef ... *CFArrayRef;
+typedef ... *CFBooleanRef;
+typedef ... *CFErrorRef;
+typedef ... *CFNumberRef;
+typedef ... *CFTypeRef;
+typedef ... *CFDictionaryRef;
+typedef ... *CFMutableDictionaryRef;
+typedef struct {
+ ...;
+} CFDictionaryKeyCallBacks;
+typedef struct {
+ ...;
+} CFDictionaryValueCallBacks;
+typedef struct {
+ ...;
+} CFRange;
+
+typedef UInt32 CFStringEncoding;
+enum {
+ kCFStringEncodingASCII = 0x0600
+};
+
+enum {
+ kCFNumberSInt8Type = 1,
+ kCFNumberSInt16Type = 2,
+ kCFNumberSInt32Type = 3,
+ kCFNumberSInt64Type = 4,
+ kCFNumberFloat32Type = 5,
+ kCFNumberFloat64Type = 6,
+ kCFNumberCharType = 7,
+ kCFNumberShortType = 8,
+ kCFNumberIntType = 9,
+ kCFNumberLongType = 10,
+ kCFNumberLongLongType = 11,
+ kCFNumberFloatType = 12,
+ kCFNumberDoubleType = 13,
+ kCFNumberCFIndexType = 14,
+ kCFNumberNSIntegerType = 15,
+ kCFNumberCGFloatType = 16,
+ kCFNumberMaxType = 16
+};
+typedef int CFNumberType;
+
+const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks;
+const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks;
+
+const CFBooleanRef kCFBooleanTrue;
+const CFBooleanRef kCFBooleanFalse;
+"""
+
+FUNCTIONS = """
+CFDataRef CFDataCreate(CFAllocatorRef, const UInt8 *, CFIndex);
+CFStringRef CFStringCreateWithCString(CFAllocatorRef, const char *,
+ CFStringEncoding);
+CFDictionaryRef CFDictionaryCreate(CFAllocatorRef, const void **,
+ const void **, CFIndex,
+ const CFDictionaryKeyCallBacks *,
+ const CFDictionaryValueCallBacks *);
+CFMutableDictionaryRef CFDictionaryCreateMutable(
+ CFAllocatorRef,
+ CFIndex,
+ const CFDictionaryKeyCallBacks *,
+ const CFDictionaryValueCallBacks *
+);
+void CFDictionarySetValue(CFMutableDictionaryRef, const void *, const void *);
+CFIndex CFArrayGetCount(CFArrayRef);
+const void *CFArrayGetValueAtIndex(CFArrayRef, CFIndex);
+CFIndex CFDataGetLength(CFDataRef);
+void CFDataGetBytes(CFDataRef, CFRange, UInt8 *);
+CFRange CFRangeMake(CFIndex, CFIndex);
+void CFShow(CFTypeRef);
+Boolean CFBooleanGetValue(CFBooleanRef);
+CFNumberRef CFNumberCreate(CFAllocatorRef, CFNumberType, const void *);
+void CFRelease(CFTypeRef);
+CFTypeRef CFRetain(CFTypeRef);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py b/src/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
new file mode 100644
index 00000000..713bc566
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/common_cryptor.py
@@ -0,0 +1,110 @@
+# 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
+
+INCLUDES = """
+#include <CommonCrypto/CommonCryptor.h>
+"""
+
+TYPES = """
+enum {
+ kCCAlgorithmAES128 = 0,
+ kCCAlgorithmDES,
+ kCCAlgorithm3DES,
+ kCCAlgorithmCAST,
+ kCCAlgorithmRC4,
+ kCCAlgorithmRC2,
+ kCCAlgorithmBlowfish
+};
+typedef uint32_t CCAlgorithm;
+enum {
+ kCCSuccess = 0,
+ kCCParamError = -4300,
+ kCCBufferTooSmall = -4301,
+ kCCMemoryFailure = -4302,
+ kCCAlignmentError = -4303,
+ kCCDecodeError = -4304,
+ kCCUnimplemented = -4305
+};
+typedef int32_t CCCryptorStatus;
+typedef uint32_t CCOptions;
+enum {
+ kCCEncrypt = 0,
+ kCCDecrypt,
+};
+typedef uint32_t CCOperation;
+typedef ... *CCCryptorRef;
+
+enum {
+ kCCModeOptionCTR_LE = 0x0001,
+ kCCModeOptionCTR_BE = 0x0002
+};
+
+typedef uint32_t CCModeOptions;
+
+enum {
+ kCCModeECB = 1,
+ kCCModeCBC = 2,
+ kCCModeCFB = 3,
+ kCCModeCTR = 4,
+ kCCModeF8 = 5,
+ kCCModeLRW = 6,
+ kCCModeOFB = 7,
+ kCCModeXTS = 8,
+ kCCModeRC4 = 9,
+ kCCModeCFB8 = 10,
+ kCCModeGCM = 11
+};
+typedef uint32_t CCMode;
+enum {
+ ccNoPadding = 0,
+ ccPKCS7Padding = 1,
+};
+typedef uint32_t CCPadding;
+"""
+
+FUNCTIONS = """
+CCCryptorStatus CCCryptorCreateWithMode(CCOperation, CCMode, CCAlgorithm,
+ CCPadding, const void *, const void *,
+ size_t, const void *, size_t, int,
+ CCModeOptions, CCCryptorRef *);
+CCCryptorStatus CCCryptorCreate(CCOperation, CCAlgorithm, CCOptions,
+ const void *, size_t, const void *,
+ CCCryptorRef *);
+CCCryptorStatus CCCryptorUpdate(CCCryptorRef, const void *, size_t, void *,
+ size_t, size_t *);
+CCCryptorStatus CCCryptorFinal(CCCryptorRef, void *, size_t, size_t *);
+CCCryptorStatus CCCryptorRelease(CCCryptorRef);
+
+CCCryptorStatus CCCryptorGCMAddIV(CCCryptorRef, const void *, size_t);
+CCCryptorStatus CCCryptorGCMAddAAD(CCCryptorRef, const void *, size_t);
+CCCryptorStatus CCCryptorGCMEncrypt(CCCryptorRef, const void *, size_t,
+ void *);
+CCCryptorStatus CCCryptorGCMDecrypt(CCCryptorRef, const void *, size_t,
+ void *);
+CCCryptorStatus CCCryptorGCMFinal(CCCryptorRef, const void *, size_t *);
+CCCryptorStatus CCCryptorGCMReset(CCCryptorRef);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+/* Not defined in the public header */
+enum {
+ kCCModeGCM = 11
+};
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/common_digest.py b/src/cryptography/hazmat/bindings/commoncrypto/common_digest.py
new file mode 100644
index 00000000..c59200cb
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/common_digest.py
@@ -0,0 +1,69 @@
+# 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
+
+INCLUDES = """
+#include <CommonCrypto/CommonDigest.h>
+"""
+
+TYPES = """
+typedef uint32_t CC_LONG;
+typedef uint64_t CC_LONG64;
+typedef struct CC_MD5state_st {
+ ...;
+} CC_MD5_CTX;
+typedef struct CC_SHA1state_st {
+ ...;
+} CC_SHA1_CTX;
+typedef struct CC_SHA256state_st {
+ ...;
+} CC_SHA256_CTX;
+typedef struct CC_SHA512state_st {
+ ...;
+} CC_SHA512_CTX;
+"""
+
+FUNCTIONS = """
+int CC_MD5_Init(CC_MD5_CTX *);
+int CC_MD5_Update(CC_MD5_CTX *, const void *, CC_LONG);
+int CC_MD5_Final(unsigned char *, CC_MD5_CTX *);
+
+int CC_SHA1_Init(CC_SHA1_CTX *);
+int CC_SHA1_Update(CC_SHA1_CTX *, const void *, CC_LONG);
+int CC_SHA1_Final(unsigned char *, CC_SHA1_CTX *);
+
+int CC_SHA224_Init(CC_SHA256_CTX *);
+int CC_SHA224_Update(CC_SHA256_CTX *, const void *, CC_LONG);
+int CC_SHA224_Final(unsigned char *, CC_SHA256_CTX *);
+
+int CC_SHA256_Init(CC_SHA256_CTX *);
+int CC_SHA256_Update(CC_SHA256_CTX *, const void *, CC_LONG);
+int CC_SHA256_Final(unsigned char *, CC_SHA256_CTX *);
+
+int CC_SHA384_Init(CC_SHA512_CTX *);
+int CC_SHA384_Update(CC_SHA512_CTX *, const void *, CC_LONG);
+int CC_SHA384_Final(unsigned char *, CC_SHA512_CTX *);
+
+int CC_SHA512_Init(CC_SHA512_CTX *);
+int CC_SHA512_Update(CC_SHA512_CTX *, const void *, CC_LONG);
+int CC_SHA512_Final(unsigned char *, CC_SHA512_CTX *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/common_hmac.py b/src/cryptography/hazmat/bindings/commoncrypto/common_hmac.py
new file mode 100644
index 00000000..4f54b62b
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/common_hmac.py
@@ -0,0 +1,48 @@
+# 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
+
+INCLUDES = """
+#include <CommonCrypto/CommonHMAC.h>
+"""
+
+TYPES = """
+typedef struct {
+ ...;
+} CCHmacContext;
+enum {
+ kCCHmacAlgSHA1,
+ kCCHmacAlgMD5,
+ kCCHmacAlgSHA256,
+ kCCHmacAlgSHA384,
+ kCCHmacAlgSHA512,
+ kCCHmacAlgSHA224
+};
+typedef uint32_t CCHmacAlgorithm;
+"""
+
+FUNCTIONS = """
+void CCHmacInit(CCHmacContext *, CCHmacAlgorithm, const void *, size_t);
+void CCHmacUpdate(CCHmacContext *, const void *, size_t);
+void CCHmacFinal(CCHmacContext *, void *);
+
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py b/src/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py
new file mode 100644
index 00000000..e8cc03ef
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/common_key_derivation.py
@@ -0,0 +1,50 @@
+# 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
+
+INCLUDES = """
+#include <CommonCrypto/CommonKeyDerivation.h>
+"""
+
+TYPES = """
+enum {
+ kCCPBKDF2 = 2,
+};
+typedef uint32_t CCPBKDFAlgorithm;
+enum {
+ kCCPRFHmacAlgSHA1 = 1,
+ kCCPRFHmacAlgSHA224 = 2,
+ kCCPRFHmacAlgSHA256 = 3,
+ kCCPRFHmacAlgSHA384 = 4,
+ kCCPRFHmacAlgSHA512 = 5,
+};
+typedef uint32_t CCPseudoRandomAlgorithm;
+typedef unsigned int uint;
+"""
+
+FUNCTIONS = """
+int CCKeyDerivationPBKDF(CCPBKDFAlgorithm, const char *, size_t,
+ const uint8_t *, size_t, CCPseudoRandomAlgorithm,
+ uint, uint8_t *, size_t);
+uint CCCalibratePBKDF(CCPBKDFAlgorithm, size_t, size_t,
+ CCPseudoRandomAlgorithm, size_t, uint32_t);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/secimport.py b/src/cryptography/hazmat/bindings/commoncrypto/secimport.py
new file mode 100644
index 00000000..add62c79
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/secimport.py
@@ -0,0 +1,95 @@
+# 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
+
+INCLUDES = """
+#include <Security/SecImportExport.h>
+"""
+
+TYPES = """
+typedef ... *SecAccessRef;
+
+CFStringRef kSecImportExportPassphrase;
+CFStringRef kSecImportExportKeychain;
+CFStringRef kSecImportExportAccess;
+
+typedef uint32_t SecExternalItemType;
+enum {
+ kSecItemTypeUnknown,
+ kSecItemTypePrivateKey,
+ kSecItemTypePublicKey,
+ kSecItemTypeSessionKey,
+ kSecItemTypeCertificate,
+ kSecItemTypeAggregate
+};
+
+
+typedef uint32_t SecExternalFormat;
+enum {
+ kSecFormatUnknown = 0,
+ kSecFormatOpenSSL,
+ kSecFormatSSH,
+ kSecFormatBSAFE,
+ kSecFormatRawKey,
+ kSecFormatWrappedPKCS8,
+ kSecFormatWrappedOpenSSL,
+ kSecFormatWrappedSSH,
+ kSecFormatWrappedLSH,
+ kSecFormatX509Cert,
+ kSecFormatPEMSequence,
+ kSecFormatPKCS7,
+ kSecFormatPKCS12,
+ kSecFormatNetscapeCertSequence,
+ kSecFormatSSHv2
+};
+
+typedef uint32_t SecItemImportExportFlags;
+enum {
+ kSecKeyImportOnlyOne = 0x00000001,
+ kSecKeySecurePassphrase = 0x00000002,
+ kSecKeyNoAccessControl = 0x00000004
+};
+typedef uint32_t SecKeyImportExportFlags;
+
+typedef struct {
+ /* for import and export */
+ uint32_t version;
+ SecKeyImportExportFlags flags;
+ CFTypeRef passphrase;
+ CFStringRef alertTitle;
+ CFStringRef alertPrompt;
+
+ /* for import only */
+ SecAccessRef accessRef;
+ CFArrayRef keyUsage;
+
+ CFArrayRef keyAttributes;
+} SecItemImportExportKeyParameters;
+"""
+
+FUNCTIONS = """
+OSStatus SecItemImport(CFDataRef, CFStringRef, SecExternalFormat *,
+ SecExternalItemType *, SecItemImportExportFlags,
+ const SecItemImportExportKeyParameters *,
+ SecKeychainRef, CFArrayRef *);
+OSStatus SecPKCS12Import(CFDataRef, CFDictionaryRef, CFArrayRef *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/secitem.py b/src/cryptography/hazmat/bindings/commoncrypto/secitem.py
new file mode 100644
index 00000000..ac3dad3f
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/secitem.py
@@ -0,0 +1,38 @@
+# 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
+
+INCLUDES = """
+#include <Security/SecItem.h>
+"""
+
+TYPES = """
+const CFTypeRef kSecAttrKeyType;
+const CFTypeRef kSecAttrKeySizeInBits;
+const CFTypeRef kSecAttrIsPermanent;
+const CFTypeRef kSecAttrKeyTypeRSA;
+const CFTypeRef kSecAttrKeyTypeDSA;
+const CFTypeRef kSecUseKeychain;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/seckey.py b/src/cryptography/hazmat/bindings/commoncrypto/seckey.py
new file mode 100644
index 00000000..5e4b6dac
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/seckey.py
@@ -0,0 +1,35 @@
+# 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
+
+INCLUDES = """
+#include <Security/SecKey.h>
+"""
+
+TYPES = """
+typedef ... *SecKeyRef;
+"""
+
+FUNCTIONS = """
+OSStatus SecKeyGeneratePair(CFDictionaryRef, SecKeyRef *, SecKeyRef *);
+size_t SecKeyGetBlockSize(SecKeyRef);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/seckeychain.py b/src/cryptography/hazmat/bindings/commoncrypto/seckeychain.py
new file mode 100644
index 00000000..c045c347
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/seckeychain.py
@@ -0,0 +1,36 @@
+# 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
+
+INCLUDES = """
+#include <Security/SecKeychain.h>
+"""
+
+TYPES = """
+typedef ... *SecKeychainRef;
+"""
+
+FUNCTIONS = """
+OSStatus SecKeychainCreate(const char *, UInt32, const void *, Boolean,
+ SecAccessRef, SecKeychainRef *);
+OSStatus SecKeychainDelete(SecKeychainRef);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/sectransform.py b/src/cryptography/hazmat/bindings/commoncrypto/sectransform.py
new file mode 100644
index 00000000..d6dbc5f6
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/commoncrypto/sectransform.py
@@ -0,0 +1,79 @@
+# 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
+
+INCLUDES = """
+#include <Security/SecDigestTransform.h>
+#include <Security/SecSignVerifyTransform.h>
+#include <Security/SecEncryptTransform.h>
+"""
+
+TYPES = """
+typedef ... *SecTransformRef;
+
+CFStringRef kSecImportExportPassphrase;
+CFStringRef kSecImportExportKeychain;
+CFStringRef kSecImportExportAccess;
+
+CFStringRef kSecEncryptionMode;
+CFStringRef kSecEncryptKey;
+CFStringRef kSecIVKey;
+CFStringRef kSecModeCBCKey;
+CFStringRef kSecModeCFBKey;
+CFStringRef kSecModeECBKey;
+CFStringRef kSecModeNoneKey;
+CFStringRef kSecModeOFBKey;
+CFStringRef kSecOAEPEncodingParametersAttributeName;
+CFStringRef kSecPaddingKey;
+CFStringRef kSecPaddingNoneKey;
+CFStringRef kSecPaddingOAEPKey;
+CFStringRef kSecPaddingPKCS1Key;
+CFStringRef kSecPaddingPKCS5Key;
+CFStringRef kSecPaddingPKCS7Key;
+
+const CFStringRef kSecTransformInputAttributeName;
+const CFStringRef kSecTransformOutputAttributeName;
+const CFStringRef kSecTransformDebugAttributeName;
+const CFStringRef kSecTransformTransformName;
+const CFStringRef kSecTransformAbortAttributeName;
+
+CFStringRef kSecInputIsAttributeName;
+CFStringRef kSecInputIsPlainText;
+CFStringRef kSecInputIsDigest;
+CFStringRef kSecInputIsRaw;
+
+const CFStringRef kSecDigestTypeAttribute;
+const CFStringRef kSecDigestLengthAttribute;
+const CFStringRef kSecDigestMD5;
+const CFStringRef kSecDigestSHA1;
+const CFStringRef kSecDigestSHA2;
+"""
+
+FUNCTIONS = """
+Boolean SecTransformSetAttribute(SecTransformRef, CFStringRef, CFTypeRef,
+ CFErrorRef *);
+SecTransformRef SecDecryptTransformCreate(SecKeyRef, CFErrorRef *);
+SecTransformRef SecEncryptTransformCreate(SecKeyRef, CFErrorRef *);
+SecTransformRef SecVerifyTransformCreate(SecKeyRef, CFDataRef, CFErrorRef *);
+SecTransformRef SecSignTransformCreate(SecKeyRef, CFErrorRef *) ;
+CFTypeRef SecTransformExecute(SecTransformRef, CFErrorRef *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/__init__.py b/src/cryptography/hazmat/bindings/openssl/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/bindings/openssl/aes.py b/src/cryptography/hazmat/bindings/openssl/aes.py
new file mode 100644
index 00000000..e4071523
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/aes.py
@@ -0,0 +1,70 @@
+# 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
+
+INCLUDES = """
+#include <openssl/aes.h>
+"""
+
+TYPES = """
+static const int Cryptography_HAS_AES_WRAP;
+
+struct aes_key_st {
+ ...;
+};
+typedef struct aes_key_st AES_KEY;
+"""
+
+FUNCTIONS = """
+int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *);
+int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *);
+"""
+
+MACROS = """
+/* these can be moved back to FUNCTIONS once we drop support for 0.9.8h.
+ This should be when we drop RHEL/CentOS 5, which is on 0.9.8e. */
+int AES_wrap_key(AES_KEY *, const unsigned char *, unsigned char *,
+ const unsigned char *, unsigned int);
+int AES_unwrap_key(AES_KEY *, const unsigned char *, unsigned char *,
+ const unsigned char *, unsigned int);
+
+/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
+ this in 1.0.0+. It is defined in macros because the function signature
+ changed after 0.9.8 */
+void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
+ const size_t, const AES_KEY *,
+ unsigned char[], unsigned char[], unsigned int *);
+
+"""
+
+CUSTOMIZATIONS = """
+/* OpenSSL 0.9.8h+ */
+#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
+static const long Cryptography_HAS_AES_WRAP = 1;
+#else
+static const long Cryptography_HAS_AES_WRAP = 0;
+int (*AES_wrap_key)(AES_KEY *, const unsigned char *, unsigned char *,
+ const unsigned char *, unsigned int) = NULL;
+int (*AES_unwrap_key)(AES_KEY *, const unsigned char *, unsigned char *,
+ const unsigned char *, unsigned int) = NULL;
+#endif
+
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_AES_WRAP": [
+ "AES_wrap_key",
+ "AES_unwrap_key",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/asn1.py b/src/cryptography/hazmat/bindings/openssl/asn1.py
new file mode 100644
index 00000000..2edfd2d8
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/asn1.py
@@ -0,0 +1,152 @@
+# 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
+
+INCLUDES = """
+#include <openssl/asn1.h>
+"""
+
+TYPES = """
+/*
+ * TODO: This typedef is wrong.
+ *
+ * This is due to limitations of cffi.
+ * See https://bitbucket.org/cffi/cffi/issue/69
+ *
+ * For another possible work-around (not used here because it involves more
+ * complicated use of the cffi API which falls outside the general pattern used
+ * by this package), see
+ * http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/
+ *
+ * The work-around used here is to just be sure to declare a type that is at
+ * least as large as the real type. Maciej explains:
+ *
+ * <fijal> I think you want to declare your value too large (e.g. long)
+ * <fijal> that way you'll never pass garbage
+ */
+typedef intptr_t time_t;
+
+typedef int ASN1_BOOLEAN;
+typedef ... ASN1_INTEGER;
+
+struct asn1_string_st {
+ int length;
+ int type;
+ unsigned char *data;
+ long flags;
+};
+
+typedef struct asn1_string_st ASN1_OCTET_STRING;
+typedef struct asn1_string_st ASN1_IA5STRING;
+typedef ... ASN1_OBJECT;
+typedef ... ASN1_STRING;
+typedef ... ASN1_TYPE;
+typedef ... ASN1_GENERALIZEDTIME;
+typedef ... ASN1_ENUMERATED;
+typedef ... ASN1_ITEM;
+typedef ... ASN1_VALUE;
+
+typedef struct {
+ ...;
+} ASN1_TIME;
+typedef ... ASN1_ITEM_EXP;
+
+typedef ... ASN1_UTCTIME;
+
+static const int V_ASN1_GENERALIZEDTIME;
+
+static const int MBSTRING_UTF8;
+"""
+
+FUNCTIONS = """
+ASN1_OBJECT *ASN1_OBJECT_new(void);
+void ASN1_OBJECT_free(ASN1_OBJECT *);
+
+/* ASN1 OBJECT IDENTIFIER */
+ASN1_OBJECT *d2i_ASN1_OBJECT(ASN1_OBJECT **, const unsigned char **, long);
+int i2d_ASN1_OBJECT(ASN1_OBJECT *, unsigned char **);
+
+/* ASN1 STRING */
+ASN1_STRING *ASN1_STRING_new(void);
+ASN1_STRING *ASN1_STRING_type_new(int);
+void ASN1_STRING_free(ASN1_STRING *);
+unsigned char *ASN1_STRING_data(ASN1_STRING *);
+int ASN1_STRING_set(ASN1_STRING *, const void *, int);
+int ASN1_STRING_type(ASN1_STRING *);
+int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *);
+
+/* ASN1 OCTET STRING */
+ASN1_OCTET_STRING *ASN1_OCTET_STRING_new(void);
+void ASN1_OCTET_STRING_free(ASN1_OCTET_STRING *);
+int ASN1_OCTET_STRING_set(ASN1_OCTET_STRING *, const unsigned char *, int);
+
+/* ASN1 INTEGER */
+ASN1_INTEGER *ASN1_INTEGER_new(void);
+void ASN1_INTEGER_free(ASN1_INTEGER *);
+int ASN1_INTEGER_set(ASN1_INTEGER *, long);
+int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *);
+
+/* ASN1 TIME */
+ASN1_TIME *ASN1_TIME_new(void);
+void ASN1_TIME_free(ASN1_TIME *);
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *,
+ ASN1_GENERALIZEDTIME **);
+
+/* ASN1 UTCTIME */
+int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t);
+
+/* ASN1 GENERALIZEDTIME */
+int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *);
+void ASN1_GENERALIZEDTIME_free(ASN1_GENERALIZEDTIME *);
+
+/* ASN1 ENUMERATED */
+ASN1_ENUMERATED *ASN1_ENUMERATED_new(void);
+void ASN1_ENUMERATED_free(ASN1_ENUMERATED *);
+int ASN1_ENUMERATED_set(ASN1_ENUMERATED *, long);
+
+ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long,
+ const ASN1_ITEM *);
+"""
+
+MACROS = """
+ASN1_TIME *M_ASN1_TIME_dup(void *);
+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_STRING_length(ASN1_STRING *);
+ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *);
+int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *);
+
+ASN1_OCTET_STRING *ASN1_OCTET_STRING_dup(ASN1_OCTET_STRING *);
+int ASN1_OCTET_STRING_cmp(ASN1_OCTET_STRING *, ASN1_OCTET_STRING *);
+
+ASN1_INTEGER *ASN1_INTEGER_dup(ASN1_INTEGER *);
+int ASN1_INTEGER_cmp(ASN1_INTEGER *, ASN1_INTEGER *);
+long ASN1_INTEGER_get(ASN1_INTEGER *);
+
+BIGNUM *ASN1_INTEGER_to_BN(ASN1_INTEGER *, BIGNUM *);
+ASN1_INTEGER *BN_to_ASN1_INTEGER(BIGNUM *, ASN1_INTEGER *);
+
+/* These isn't a macro the arg is const on openssl 1.0.2+ */
+int ASN1_GENERALIZEDTIME_check(ASN1_GENERALIZEDTIME *);
+
+/* Not a macro, const on openssl 1.0 */
+int ASN1_STRING_set_default_mask_asc(char *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/bignum.py b/src/cryptography/hazmat/bindings/openssl/bignum.py
new file mode 100644
index 00000000..1d944ee9
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/bignum.py
@@ -0,0 +1,114 @@
+# 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
+
+INCLUDES = """
+#include <openssl/bn.h>
+"""
+
+TYPES = """
+typedef ... BN_CTX;
+typedef ... BIGNUM;
+/*
+ * TODO: This typedef is wrong.
+ *
+ * This is due to limitations of cffi.
+ * See https://bitbucket.org/cffi/cffi/issue/69
+ *
+ * For another possible work-around (not used here because it involves more
+ * complicated use of the cffi API which falls outside the general pattern used
+ * by this package), see
+ * http://paste.pound-python.org/show/iJcTUMkKeBeS6yXpZWUU/
+ *
+ * The work-around used here is to just be sure to declare a type that is at
+ * least as large as the real type. Maciej explains:
+ *
+ * <fijal> I think you want to declare your value too large (e.g. long)
+ * <fijal> that way you'll never pass garbage
+ */
+typedef uintptr_t BN_ULONG;
+"""
+
+FUNCTIONS = """
+BIGNUM *BN_new(void);
+void BN_free(BIGNUM *);
+
+BN_CTX *BN_CTX_new(void);
+void BN_CTX_free(BN_CTX *);
+
+void BN_CTX_start(BN_CTX *);
+BIGNUM *BN_CTX_get(BN_CTX *);
+void BN_CTX_end(BN_CTX *);
+
+BIGNUM *BN_copy(BIGNUM *, const BIGNUM *);
+BIGNUM *BN_dup(const BIGNUM *);
+
+int BN_set_word(BIGNUM *, BN_ULONG);
+BN_ULONG BN_get_word(const BIGNUM *);
+
+const BIGNUM *BN_value_one(void);
+
+char *BN_bn2hex(const BIGNUM *);
+int BN_hex2bn(BIGNUM **, const char *);
+int BN_dec2bn(BIGNUM **, const char *);
+
+int BN_bn2bin(const BIGNUM *, unsigned char *);
+BIGNUM *BN_bin2bn(const unsigned char *, int, BIGNUM *);
+
+int BN_num_bits(const BIGNUM *);
+
+int BN_cmp(const BIGNUM *, const BIGNUM *);
+int BN_add(BIGNUM *, const BIGNUM *, const BIGNUM *);
+int BN_sub(BIGNUM *, const BIGNUM *, const BIGNUM *);
+int BN_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_sqr(BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_div(BIGNUM *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_nnmod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_mod_add(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+int BN_mod_sub(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+int BN_mod_mul(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+int BN_mod_sqr(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int BN_mod_exp(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *);
+int BN_gcd(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+BIGNUM *BN_mod_inverse(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_set_bit(BIGNUM *, int);
+int BN_clear_bit(BIGNUM *, int);
+
+int BN_is_bit_set(const BIGNUM *, int);
+
+int BN_mask_bits(BIGNUM *, int);
+"""
+
+MACROS = """
+int BN_zero(BIGNUM *);
+int BN_one(BIGNUM *);
+int BN_mod(BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int BN_lshift(BIGNUM *, const BIGNUM *, int);
+int BN_lshift1(BIGNUM *, BIGNUM *);
+
+int BN_rshift(BIGNUM *, BIGNUM *, int);
+int BN_rshift1(BIGNUM *, BIGNUM *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
new file mode 100644
index 00000000..ff9039cf
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -0,0 +1,176 @@
+# 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 os
+import sys
+import threading
+
+from cryptography.hazmat.bindings.utils import (
+ build_ffi_for_binding, load_library_for_binding,
+)
+
+
+_OSX_PRE_INCLUDE = """
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+#define __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
+ DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+"""
+
+_OSX_POST_INCLUDE = """
+#ifdef __APPLE__
+#undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER \
+ __ORIG_DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER
+#endif
+"""
+
+
+def _get_libraries(platform):
+ # OpenSSL goes by a different library name on different operating systems.
+ if platform != "win32":
+ # In some circumstances, the order in which these libs are
+ # specified on the linker command-line is significant;
+ # libssl must come before libcrypto
+ # (http://marc.info/?l=openssl-users&m=135361825921871)
+ return ["ssl", "crypto"]
+ else:
+ link_type = os.environ.get("PYCA_WINDOWS_LINK_TYPE", "static")
+ return _get_windows_libraries(link_type)
+
+
+def _get_windows_libraries(link_type):
+ if link_type == "dynamic":
+ return ["libeay32", "ssleay32", "advapi32"]
+ elif link_type == "static" or link_type == "":
+ return ["libeay32mt", "ssleay32mt", "advapi32",
+ "crypt32", "gdi32", "user32", "ws2_32"]
+ else:
+ raise ValueError(
+ "PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
+ )
+
+
+class Binding(object):
+ """
+ OpenSSL API wrapper.
+ """
+ _module_prefix = "cryptography.hazmat.bindings.openssl."
+ _modules = [
+ "aes",
+ "asn1",
+ "bignum",
+ "bio",
+ "cmac",
+ "cms",
+ "conf",
+ "crypto",
+ "dh",
+ "dsa",
+ "ec",
+ "ecdh",
+ "ecdsa",
+ "engine",
+ "err",
+ "evp",
+ "hmac",
+ "nid",
+ "objects",
+ "opensslv",
+ "osrandom_engine",
+ "pem",
+ "pkcs7",
+ "pkcs12",
+ "rand",
+ "rsa",
+ "ssl",
+ "x509",
+ "x509name",
+ "x509v3",
+ "x509_vfy"
+ ]
+
+ _locks = None
+ _lock_cb_handle = None
+ _lock_init_lock = threading.Lock()
+
+ ffi = build_ffi_for_binding(
+ module_prefix=_module_prefix,
+ modules=_modules,
+ pre_include=_OSX_PRE_INCLUDE,
+ post_include=_OSX_POST_INCLUDE,
+ libraries=_get_libraries(sys.platform)
+ )
+ lib = None
+
+ def __init__(self):
+ self._ensure_ffi_initialized()
+
+ @classmethod
+ def _ensure_ffi_initialized(cls):
+ if cls.lib is not None:
+ return
+
+ cls.lib = load_library_for_binding(
+ cls.ffi,
+ cls._module_prefix,
+ cls._modules,
+ )
+
+ res = cls.lib.Cryptography_add_osrandom_engine()
+ assert res != 0
+
+ @classmethod
+ def init_static_locks(cls):
+ with cls._lock_init_lock:
+ cls._ensure_ffi_initialized()
+
+ if not cls._lock_cb_handle:
+ cls._lock_cb_handle = cls.ffi.callback(
+ "void(int, int, const char *, int)",
+ cls._lock_cb
+ )
+
+ # Use Python's implementation if available, importing _ssl triggers
+ # the setup for this.
+ __import__("_ssl")
+
+ if cls.lib.CRYPTO_get_locking_callback() != cls.ffi.NULL:
+ return
+
+ # If nothing else has setup a locking callback already, we set up
+ # our own
+ num_locks = cls.lib.CRYPTO_num_locks()
+ cls._locks = [threading.Lock() for n in range(num_locks)]
+
+ cls.lib.CRYPTO_set_locking_callback(cls._lock_cb_handle)
+
+ @classmethod
+ def _lock_cb(cls, mode, n, file, line):
+ lock = cls._locks[n]
+
+ if mode & cls.lib.CRYPTO_LOCK:
+ lock.acquire()
+ elif mode & cls.lib.CRYPTO_UNLOCK:
+ lock.release()
+ else:
+ raise RuntimeError(
+ "Unknown lock mode {0}: lock={1}, file={2}, line={3}.".format(
+ mode, n, file, line
+ )
+ )
diff --git a/src/cryptography/hazmat/bindings/openssl/bio.py b/src/cryptography/hazmat/bindings/openssl/bio.py
new file mode 100644
index 00000000..cfe6034f
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/bio.py
@@ -0,0 +1,181 @@
+# 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
+
+INCLUDES = """
+#include <openssl/bio.h>
+"""
+
+TYPES = """
+typedef struct bio_st BIO;
+typedef void bio_info_cb(BIO *, int, const char *, int, long, long);
+struct bio_method_st {
+ int type;
+ const char *name;
+ int (*bwrite)(BIO *, const char *, int);
+ int (*bread)(BIO *, char *, int);
+ int (*bputs)(BIO *, const char *);
+ int (*bgets)(BIO *, char*, int);
+ long (*ctrl)(BIO *, int, long, void *);
+ int (*create)(BIO *);
+ int (*destroy)(BIO *);
+ long (*callback_ctrl)(BIO *, int, bio_info_cb *);
+ ...;
+};
+typedef struct bio_method_st BIO_METHOD;
+struct bio_st {
+ BIO_METHOD *method;
+ long (*callback)(struct bio_st*, int, const char*, int, long, long);
+ char *cb_arg;
+ int init;
+ int shutdown;
+ int flags;
+ int retry_reason;
+ int num;
+ void *ptr;
+ struct bio_st *next_bio;
+ struct bio_st *prev_bio;
+ int references;
+ unsigned long num_read;
+ unsigned long num_write;
+ ...;
+};
+typedef ... BUF_MEM;
+
+static const int BIO_TYPE_MEM;
+static const int BIO_TYPE_FILE;
+static const int BIO_TYPE_FD;
+static const int BIO_TYPE_SOCKET;
+static const int BIO_TYPE_CONNECT;
+static const int BIO_TYPE_ACCEPT;
+static const int BIO_TYPE_NULL;
+static const int BIO_CLOSE;
+static const int BIO_NOCLOSE;
+static const int BIO_TYPE_SOURCE_SINK;
+static const int BIO_CTRL_RESET;
+static const int BIO_CTRL_EOF;
+static const int BIO_CTRL_SET;
+static const int BIO_CTRL_SET_CLOSE;
+static const int BIO_CTRL_FLUSH;
+static const int BIO_CTRL_DUP;
+static const int BIO_CTRL_GET_CLOSE;
+static const int BIO_CTRL_INFO;
+static const int BIO_CTRL_GET;
+static const int BIO_CTRL_PENDING;
+static const int BIO_CTRL_WPENDING;
+static const int BIO_C_FILE_SEEK;
+static const int BIO_C_FILE_TELL;
+static const int BIO_TYPE_NONE;
+static const int BIO_TYPE_PROXY_CLIENT;
+static const int BIO_TYPE_PROXY_SERVER;
+static const int BIO_TYPE_NBIO_TEST;
+static const int BIO_TYPE_BER;
+static const int BIO_TYPE_BIO;
+static const int BIO_TYPE_DESCRIPTOR;
+static const int BIO_FLAGS_READ;
+static const int BIO_FLAGS_WRITE;
+static const int BIO_FLAGS_IO_SPECIAL;
+static const int BIO_FLAGS_RWS;
+static const int BIO_FLAGS_SHOULD_RETRY;
+static const int BIO_TYPE_NULL_FILTER;
+static const int BIO_TYPE_SSL;
+static const int BIO_TYPE_MD;
+static const int BIO_TYPE_BUFFER;
+static const int BIO_TYPE_CIPHER;
+static const int BIO_TYPE_BASE64;
+static const int BIO_TYPE_FILTER;
+"""
+
+FUNCTIONS = """
+BIO* BIO_new(BIO_METHOD *);
+int BIO_set(BIO *, BIO_METHOD *);
+int BIO_free(BIO *);
+void BIO_vfree(BIO *);
+void BIO_free_all(BIO *);
+BIO *BIO_push(BIO *, BIO *);
+BIO *BIO_pop(BIO *);
+BIO *BIO_next(BIO *);
+BIO *BIO_find_type(BIO *, int);
+BIO_METHOD *BIO_s_mem(void);
+BIO *BIO_new_mem_buf(void *, int);
+BIO_METHOD *BIO_s_file(void);
+BIO *BIO_new_file(const char *, const char *);
+BIO *BIO_new_fp(FILE *, int);
+BIO_METHOD *BIO_s_fd(void);
+BIO *BIO_new_fd(int, int);
+BIO_METHOD *BIO_s_socket(void);
+BIO *BIO_new_socket(int, int);
+BIO_METHOD *BIO_s_null(void);
+long BIO_ctrl(BIO *, int, long, void *);
+long BIO_callback_ctrl(
+ BIO *,
+ int,
+ void (*)(struct bio_st *, int, const char *, int, long, long)
+);
+char *BIO_ptr_ctrl(BIO *, int, long);
+long BIO_int_ctrl(BIO *, int, long, int);
+size_t BIO_ctrl_pending(BIO *);
+size_t BIO_ctrl_wpending(BIO *);
+int BIO_read(BIO *, void *, int);
+int BIO_gets(BIO *, char *, int);
+int BIO_write(BIO *, const void *, int);
+int BIO_puts(BIO *, const char *);
+BIO_METHOD *BIO_f_null(void);
+BIO_METHOD *BIO_f_buffer(void);
+"""
+
+MACROS = """
+long BIO_set_fd(BIO *, long, int);
+long BIO_get_fd(BIO *, char *);
+long BIO_set_mem_eof_return(BIO *, int);
+long BIO_get_mem_data(BIO *, char **);
+long BIO_set_mem_buf(BIO *, BUF_MEM *, int);
+long BIO_get_mem_ptr(BIO *, BUF_MEM **);
+long BIO_set_fp(BIO *, FILE *, int);
+long BIO_get_fp(BIO *, FILE **);
+long BIO_read_filename(BIO *, char *);
+long BIO_write_filename(BIO *, char *);
+long BIO_append_filename(BIO *, char *);
+long BIO_rw_filename(BIO *, char *);
+int BIO_should_read(BIO *);
+int BIO_should_write(BIO *);
+int BIO_should_io_special(BIO *);
+int BIO_retry_type(BIO *);
+int BIO_should_retry(BIO *);
+int BIO_reset(BIO *);
+int BIO_seek(BIO *, int);
+int BIO_tell(BIO *);
+int BIO_flush(BIO *);
+int BIO_eof(BIO *);
+int BIO_set_close(BIO *,long);
+int BIO_get_close(BIO *);
+int BIO_pending(BIO *);
+int BIO_wpending(BIO *);
+int BIO_get_info_callback(BIO *, bio_info_cb **);
+int BIO_set_info_callback(BIO *, bio_info_cb *);
+long BIO_get_buffer_num_lines(BIO *);
+long BIO_set_read_buffer_size(BIO *, long);
+long BIO_set_write_buffer_size(BIO *, long);
+long BIO_set_buffer_size(BIO *, long);
+long BIO_set_buffer_read_data(BIO *, void *, long);
+
+/* The following was a macro in 0.9.8e. Once we drop support for RHEL/CentOS 5
+ we should move this back to FUNCTIONS. */
+int BIO_method_type(const BIO *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/cmac.py b/src/cryptography/hazmat/bindings/openssl/cmac.py
new file mode 100644
index 00000000..c8bcc824
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/cmac.py
@@ -0,0 +1,65 @@
+# 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
+
+INCLUDES = """
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+#include <openssl/cmac.h>
+#endif
+"""
+
+TYPES = """
+static const int Cryptography_HAS_CMAC;
+typedef ... CMAC_CTX;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+CMAC_CTX *CMAC_CTX_new(void);
+int CMAC_Init(CMAC_CTX *, const void *, size_t, const EVP_CIPHER *, ENGINE *);
+int CMAC_Update(CMAC_CTX *, const void *, size_t);
+int CMAC_Final(CMAC_CTX *, unsigned char *, size_t *);
+int CMAC_CTX_copy(CMAC_CTX *, const CMAC_CTX *);
+void CMAC_CTX_free(CMAC_CTX *);
+"""
+
+CUSTOMIZATIONS = """
+#if OPENSSL_VERSION_NUMBER < 0x10001000L
+
+static const long Cryptography_HAS_CMAC = 0;
+typedef void CMAC_CTX;
+CMAC_CTX *(*CMAC_CTX_new)(void) = NULL;
+int (*CMAC_Init)(CMAC_CTX *, const void *, size_t, const EVP_CIPHER *,
+ ENGINE *) = NULL;
+int (*CMAC_Update)(CMAC_CTX *, const void *, size_t) = NULL;
+int (*CMAC_Final)(CMAC_CTX *, unsigned char *, size_t *) = NULL;
+int (*CMAC_CTX_copy)(CMAC_CTX *, const CMAC_CTX *) = NULL;
+void (*CMAC_CTX_free)(CMAC_CTX *) = NULL;
+#else
+static const long Cryptography_HAS_CMAC = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_CMAC": [
+ "CMAC_CTX_new",
+ "CMAC_Init",
+ "CMAC_Update",
+ "CMAC_Final",
+ "CMAC_CTX_copy",
+ "CMAC_CTX_free",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/cms.py b/src/cryptography/hazmat/bindings/openssl/cms.py
new file mode 100644
index 00000000..cbf4b283
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/cms.py
@@ -0,0 +1,100 @@
+# 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
+
+INCLUDES = """
+#if !defined(OPENSSL_NO_CMS) && OPENSSL_VERSION_NUMBER >= 0x0090808fL
+/* The next define should really be in the OpenSSL header, but it is missing.
+ Failing to include this on Windows causes compilation failures. */
+#if defined(OPENSSL_SYS_WINDOWS)
+#include <windows.h>
+#endif
+#include <openssl/cms.h>
+#endif
+"""
+
+TYPES = """
+static const long Cryptography_HAS_CMS;
+
+typedef ... CMS_ContentInfo;
+typedef ... CMS_SignerInfo;
+typedef ... CMS_CertificateChoices;
+typedef ... CMS_RevocationInfoChoice;
+typedef ... CMS_RecipientInfo;
+typedef ... CMS_ReceiptRequest;
+typedef ... CMS_Receipt;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+BIO *BIO_new_CMS(BIO *, CMS_ContentInfo *);
+int i2d_CMS_bio_stream(BIO *, CMS_ContentInfo *, BIO *, int);
+int PEM_write_bio_CMS_stream(BIO *, CMS_ContentInfo *, BIO *, int);
+int CMS_final(CMS_ContentInfo *, BIO *, BIO *, unsigned int);
+CMS_ContentInfo *CMS_sign(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *,
+ BIO *, unsigned int);
+int CMS_verify(CMS_ContentInfo *, Cryptography_STACK_OF_X509 *, X509_STORE *,
+ BIO *, BIO *, unsigned int);
+CMS_ContentInfo *CMS_encrypt(Cryptography_STACK_OF_X509 *, BIO *,
+ const EVP_CIPHER *, unsigned int);
+int CMS_decrypt(CMS_ContentInfo *, EVP_PKEY *, X509 *, BIO *, BIO *,
+ unsigned int);
+CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *, X509 *, EVP_PKEY *,
+ const EVP_MD *, unsigned int);
+"""
+
+CUSTOMIZATIONS = """
+#if !defined(OPENSSL_NO_CMS) && OPENSSL_VERSION_NUMBER >= 0x0090808fL
+static const long Cryptography_HAS_CMS = 1;
+#else
+static const long Cryptography_HAS_CMS = 0;
+typedef void CMS_ContentInfo;
+typedef void CMS_SignerInfo;
+typedef void CMS_CertificateChoices;
+typedef void CMS_RevocationInfoChoice;
+typedef void CMS_RecipientInfo;
+typedef void CMS_ReceiptRequest;
+typedef void CMS_Receipt;
+BIO *(*BIO_new_CMS)(BIO *, CMS_ContentInfo *) = NULL;
+int (*i2d_CMS_bio_stream)(BIO *, CMS_ContentInfo *, BIO *, int) = NULL;
+int (*PEM_write_bio_CMS_stream)(BIO *, CMS_ContentInfo *, BIO *, int) = NULL;
+int (*CMS_final)(CMS_ContentInfo *, BIO *, BIO *, unsigned int) = NULL;
+CMS_ContentInfo *(*CMS_sign)(X509 *, EVP_PKEY *, Cryptography_STACK_OF_X509 *,
+ BIO *, unsigned int) = NULL;
+int (*CMS_verify)(CMS_ContentInfo *, Cryptography_STACK_OF_X509 *,
+ X509_STORE *, BIO *, BIO *, unsigned int) = NULL;
+CMS_ContentInfo *(*CMS_encrypt)(Cryptography_STACK_OF_X509 *, BIO *,
+ const EVP_CIPHER *, unsigned int) = NULL;
+int (*CMS_decrypt)(CMS_ContentInfo *, EVP_PKEY *, X509 *, BIO *, BIO *,
+ unsigned int) = NULL;
+CMS_SignerInfo *(*CMS_add1_signer)(CMS_ContentInfo *, X509 *, EVP_PKEY *,
+ const EVP_MD *, unsigned int) = NULL;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_CMS": [
+ "BIO_new_CMS",
+ "i2d_CMS_bio_stream",
+ "PEM_write_bio_CMS_stream",
+ "CMS_final",
+ "CMS_sign",
+ "CMS_verify",
+ "CMS_encrypt",
+ "CMS_decrypt",
+ "CMS_add1_signer",
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/conf.py b/src/cryptography/hazmat/bindings/openssl/conf.py
new file mode 100644
index 00000000..001a0707
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/conf.py
@@ -0,0 +1,35 @@
+# 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
+
+INCLUDES = """
+#include <openssl/conf.h>
+"""
+
+TYPES = """
+typedef ... CONF;
+"""
+
+FUNCTIONS = """
+void OPENSSL_config(const char *);
+void OPENSSL_no_config(void);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/crypto.py b/src/cryptography/hazmat/bindings/openssl/crypto.py
new file mode 100644
index 00000000..99e1a61d
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/crypto.py
@@ -0,0 +1,67 @@
+# 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
+
+INCLUDES = """
+#include <openssl/crypto.h>
+"""
+
+TYPES = """
+typedef ... CRYPTO_THREADID;
+
+static const int SSLEAY_VERSION;
+static const int SSLEAY_CFLAGS;
+static const int SSLEAY_PLATFORM;
+static const int SSLEAY_DIR;
+static const int SSLEAY_BUILT_ON;
+static const int CRYPTO_MEM_CHECK_ON;
+static const int CRYPTO_MEM_CHECK_OFF;
+static const int CRYPTO_MEM_CHECK_ENABLE;
+static const int CRYPTO_MEM_CHECK_DISABLE;
+static const int CRYPTO_LOCK;
+static const int CRYPTO_UNLOCK;
+static const int CRYPTO_READ;
+static const int CRYPTO_WRITE;
+static const int CRYPTO_LOCK_SSL;
+"""
+
+FUNCTIONS = """
+unsigned long SSLeay(void);
+const char *SSLeay_version(int);
+
+void CRYPTO_free(void *);
+int CRYPTO_mem_ctrl(int);
+int CRYPTO_is_mem_check_on(void);
+void CRYPTO_mem_leaks(struct bio_st *);
+void CRYPTO_cleanup_all_ex_data(void);
+int CRYPTO_num_locks(void);
+void CRYPTO_set_locking_callback(void(*)(int, int, const char *, int));
+void CRYPTO_set_id_callback(unsigned long (*)(void));
+unsigned long (*CRYPTO_get_id_callback(void))(void);
+void (*CRYPTO_get_locking_callback(void))(int, int, const char *, int);
+void CRYPTO_lock(int, int, const char *, int);
+
+void OPENSSL_free(void *);
+"""
+
+MACROS = """
+void CRYPTO_add(int *, int, int);
+void CRYPTO_malloc_init(void);
+void CRYPTO_malloc_debug_init(void);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/dh.py b/src/cryptography/hazmat/bindings/openssl/dh.py
new file mode 100644
index 00000000..e2e8976e
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/dh.py
@@ -0,0 +1,57 @@
+# 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
+
+INCLUDES = """
+#include <openssl/dh.h>
+"""
+
+TYPES = """
+typedef struct dh_st {
+ /* Prime number (shared) */
+ BIGNUM *p;
+ /* Generator of Z_p (shared) */
+ BIGNUM *g;
+ /* Private DH value x */
+ BIGNUM *priv_key;
+ /* Public DH value g^x */
+ BIGNUM *pub_key;
+ ...;
+} DH;
+"""
+
+FUNCTIONS = """
+DH *DH_new(void);
+void DH_free(DH *);
+int DH_size(const DH *);
+DH *DH_generate_parameters(int, int, void (*)(int, int, void *), void *);
+int DH_check(const DH *, int *);
+int DH_generate_key(DH *);
+int DH_compute_key(unsigned char *, const BIGNUM *, DH *);
+int DH_set_ex_data(DH *, int, void *);
+void *DH_get_ex_data(DH *, int);
+DH *d2i_DHparams(DH **, const unsigned char **, long);
+int i2d_DHparams(const DH *, unsigned char **);
+int DHparams_print_fp(FILE *, const DH *);
+int DHparams_print(BIO *, const DH *);
+"""
+
+MACROS = """
+int DH_generate_parameters_ex(DH *, int, int, BN_GENCB *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/dsa.py b/src/cryptography/hazmat/bindings/openssl/dsa.py
new file mode 100644
index 00000000..c9aa8882
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/dsa.py
@@ -0,0 +1,65 @@
+# 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
+
+INCLUDES = """
+#include <openssl/dsa.h>
+"""
+
+TYPES = """
+typedef struct dsa_st {
+ /* Prime number (public) */
+ BIGNUM *p;
+ /* Subprime (160-bit, q | p-1, public) */
+ BIGNUM *q;
+ /* Generator of subgroup (public) */
+ BIGNUM *g;
+ /* Private key x */
+ BIGNUM *priv_key;
+ /* Public key y = g^x */
+ BIGNUM *pub_key;
+ ...;
+} DSA;
+typedef struct {
+ BIGNUM *r;
+ BIGNUM *s;
+} DSA_SIG;
+"""
+
+FUNCTIONS = """
+DSA *DSA_generate_parameters(int, unsigned char *, int, int *, unsigned long *,
+ void (*)(int, int, void *), void *);
+int DSA_generate_key(DSA *);
+DSA *DSA_new(void);
+void DSA_free(DSA *);
+DSA_SIG *DSA_SIG_new(void);
+void DSA_SIG_free(DSA_SIG *);
+int i2d_DSA_SIG(const DSA_SIG *, unsigned char **);
+DSA_SIG *d2i_DSA_SIG(DSA_SIG **, const unsigned char **, long);
+int DSA_size(const DSA *);
+int DSA_sign(int, const unsigned char *, int, unsigned char *, unsigned int *,
+ DSA *);
+int DSA_verify(int, const unsigned char *, int, const unsigned char *, int,
+ DSA *);
+"""
+
+MACROS = """
+int DSA_generate_parameters_ex(DSA *, int, unsigned char *, int,
+ int *, unsigned long *, BN_GENCB *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/ec.py b/src/cryptography/hazmat/bindings/openssl/ec.py
new file mode 100644
index 00000000..26fc8ff0
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/ec.py
@@ -0,0 +1,490 @@
+# 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
+
+INCLUDES = """
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
+
+#include <openssl/obj_mac.h>
+"""
+
+TYPES = """
+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 OPENSSL_EC_NAMED_CURVE;
+
+typedef ... EC_KEY;
+typedef ... EC_GROUP;
+typedef ... EC_POINT;
+typedef ... EC_METHOD;
+typedef struct {
+ int nid;
+ const char *comment;
+} EC_builtin_curve;
+typedef enum { ... } point_conversion_form_t;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+EC_GROUP *EC_GROUP_new(const EC_METHOD *);
+void EC_GROUP_free(EC_GROUP *);
+void EC_GROUP_clear_free(EC_GROUP *);
+
+EC_GROUP *EC_GROUP_new_curve_GFp(
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+EC_GROUP *EC_GROUP_new_curve_GF2m(
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+EC_GROUP *EC_GROUP_new_by_curve_name(int);
+
+int EC_GROUP_set_curve_GFp(
+ EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int EC_GROUP_get_curve_GFp(
+ const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+int EC_GROUP_set_curve_GF2m(
+ EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+int EC_GROUP_get_curve_GF2m(
+ const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+int EC_GROUP_get_degree(const EC_GROUP *);
+
+const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
+const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
+int EC_GROUP_get_curve_name(const EC_GROUP *);
+
+size_t EC_get_builtin_curves(EC_builtin_curve *, size_t);
+
+void EC_KEY_free(EC_KEY *);
+
+int EC_KEY_get_flags(const EC_KEY *);
+void EC_KEY_set_flags(EC_KEY *, int);
+void EC_KEY_clear_flags(EC_KEY *, int);
+EC_KEY *EC_KEY_new_by_curve_name(int);
+EC_KEY *EC_KEY_copy(EC_KEY *, const EC_KEY *);
+EC_KEY *EC_KEY_dup(const EC_KEY *);
+int EC_KEY_up_ref(EC_KEY *);
+const EC_GROUP *EC_KEY_get0_group(const EC_KEY *);
+int EC_GROUP_get_order(const EC_GROUP *, BIGNUM *, BN_CTX *);
+int EC_KEY_set_group(EC_KEY *, const EC_GROUP *);
+const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *);
+int EC_KEY_set_private_key(EC_KEY *, const BIGNUM *);
+const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *);
+int EC_KEY_set_public_key(EC_KEY *, const EC_POINT *);
+unsigned int EC_KEY_get_enc_flags(const EC_KEY *);
+void EC_KEY_set_enc_flags(EC_KEY *eckey, unsigned int);
+point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *);
+void EC_KEY_set_conv_form(EC_KEY *, point_conversion_form_t);
+void *EC_KEY_get_key_method_data(
+ EC_KEY *,
+ void *(*)(void *),
+ void (*)(void *),
+ void (*)(void *)
+);
+void EC_KEY_insert_key_method_data(
+ EC_KEY *,
+ void *,
+ void *(*)(void *),
+ void (*)(void *),
+ void (*)(void *)
+);
+void EC_KEY_set_asn1_flag(EC_KEY *, int);
+int EC_KEY_precompute_mult(EC_KEY *, BN_CTX *);
+int EC_KEY_generate_key(EC_KEY *);
+int EC_KEY_check_key(const EC_KEY *);
+int EC_KEY_set_public_key_affine_coordinates(EC_KEY *, BIGNUM *, BIGNUM *);
+
+EC_POINT *EC_POINT_new(const EC_GROUP *);
+void EC_POINT_free(EC_POINT *);
+void EC_POINT_clear_free(EC_POINT *);
+int EC_POINT_copy(EC_POINT *, const EC_POINT *);
+EC_POINT *EC_POINT_dup(const EC_POINT *, const EC_GROUP *);
+const EC_METHOD *EC_POINT_method_of(const EC_POINT *);
+
+int EC_POINT_set_to_infinity(const EC_GROUP *, EC_POINT *);
+
+int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, int, BN_CTX *);
+
+int EC_POINT_set_affine_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int EC_POINT_get_affine_coordinates_GF2m(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+int EC_POINT_set_compressed_coordinates_GF2m(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, int, BN_CTX *);
+
+size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t,
+ unsigned char *, size_t, BN_CTX *);
+
+int EC_POINT_oct2point(const EC_GROUP *, EC_POINT *,
+ const unsigned char *, size_t, BN_CTX *);
+
+BIGNUM *EC_POINT_point2bn(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t form, BIGNUM *, BN_CTX *);
+
+EC_POINT *EC_POINT_bn2point(const EC_GROUP *, const BIGNUM *,
+ EC_POINT *, BN_CTX *);
+
+char *EC_POINT_point2hex(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t form, BN_CTX *);
+
+EC_POINT *EC_POINT_hex2point(const EC_GROUP *, const char *,
+ EC_POINT *, BN_CTX *);
+
+int EC_POINT_add(const EC_GROUP *, EC_POINT *, const EC_POINT *,
+ const EC_POINT *, BN_CTX *);
+
+int EC_POINT_dbl(const EC_GROUP *, EC_POINT *, const EC_POINT *, BN_CTX *);
+int EC_POINT_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int EC_POINT_is_at_infinity(const EC_GROUP *, const EC_POINT *);
+int EC_POINT_is_on_curve(const EC_GROUP *, const EC_POINT *, BN_CTX *);
+
+int EC_POINT_cmp(
+ const EC_GROUP *, const EC_POINT *, const EC_POINT *, BN_CTX *);
+
+int EC_POINT_make_affine(const EC_GROUP *, EC_POINT *, BN_CTX *);
+int EC_POINTs_make_affine(const EC_GROUP *, size_t, EC_POINT *[], BN_CTX *);
+
+int EC_POINTs_mul(
+ const EC_GROUP *, EC_POINT *, const BIGNUM *,
+ size_t, const EC_POINT *[], const BIGNUM *[], BN_CTX *);
+
+int EC_POINT_mul(const EC_GROUP *, EC_POINT *, const BIGNUM *,
+ const EC_POINT *, const BIGNUM *, BN_CTX *);
+
+int EC_GROUP_precompute_mult(EC_GROUP *, BN_CTX *);
+int EC_GROUP_have_precompute_mult(const EC_GROUP *);
+
+const EC_METHOD *EC_GFp_simple_method();
+const EC_METHOD *EC_GFp_mont_method();
+const EC_METHOD *EC_GFp_nist_method();
+
+const EC_METHOD *EC_GFp_nistp224_method();
+const EC_METHOD *EC_GFp_nistp256_method();
+const EC_METHOD *EC_GFp_nistp521_method();
+
+const EC_METHOD *EC_GF2m_simple_method();
+
+int EC_METHOD_get_field_type(const EC_METHOD *);
+"""
+
+CUSTOMIZATIONS = """
+#ifdef OPENSSL_NO_EC
+static const long Cryptography_HAS_EC = 0;
+
+typedef void EC_KEY;
+typedef void EC_GROUP;
+typedef void EC_POINT;
+typedef void EC_METHOD;
+typedef struct {
+ int nid;
+ const char *comment;
+} EC_builtin_curve;
+typedef long point_conversion_form_t;
+
+static const int OPENSSL_EC_NAMED_CURVE = 0;
+
+void (*EC_KEY_free)(EC_KEY *) = NULL;
+size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL;
+EC_KEY *(*EC_KEY_new_by_curve_name)(int) = NULL;
+EC_KEY *(*EC_KEY_copy)(EC_KEY *, const EC_KEY *) = NULL;
+EC_KEY *(*EC_KEY_dup)(const EC_KEY *) = NULL;
+int (*EC_KEY_up_ref)(EC_KEY *) = NULL;
+const EC_GROUP *(*EC_KEY_get0_group)(const EC_KEY *) = NULL;
+int (*EC_GROUP_get_order)(const EC_GROUP *, BIGNUM *, BN_CTX *) = NULL;
+int (*EC_KEY_set_group)(EC_KEY *, const EC_GROUP *) = NULL;
+const BIGNUM *(*EC_KEY_get0_private_key)(const EC_KEY *) = NULL;
+int (*EC_KEY_set_private_key)(EC_KEY *, const BIGNUM *) = NULL;
+const EC_POINT *(*EC_KEY_get0_public_key)(const EC_KEY *) = NULL;
+int (*EC_KEY_set_public_key)(EC_KEY *, const EC_POINT *) = NULL;
+unsigned int (*EC_KEY_get_enc_flags)(const EC_KEY *) = NULL;
+void (*EC_KEY_set_enc_flags)(EC_KEY *eckey, unsigned int) = NULL;
+point_conversion_form_t (*EC_KEY_get_conv_form)(const EC_KEY *) = NULL;
+void (*EC_KEY_set_conv_form)(EC_KEY *, point_conversion_form_t) = NULL;
+void *(*EC_KEY_get_key_method_data)(
+ EC_KEY *, void *(*)(void *), void (*)(void *), void (*)(void *)) = NULL;
+void (*EC_KEY_insert_key_method_data)(
+ EC_KEY *, void *,
+ void *(*)(void *), void (*)(void *), void (*)(void *)) = NULL;
+void (*EC_KEY_set_asn1_flag)(EC_KEY *, int) = NULL;
+int (*EC_KEY_precompute_mult)(EC_KEY *, BN_CTX *) = NULL;
+int (*EC_KEY_generate_key)(EC_KEY *) = NULL;
+int (*EC_KEY_check_key)(const EC_KEY *) = NULL;
+
+EC_GROUP *(*EC_GROUP_new)(const EC_METHOD *);
+void (*EC_GROUP_free)(EC_GROUP *);
+void (*EC_GROUP_clear_free)(EC_GROUP *);
+
+EC_GROUP *(*EC_GROUP_new_curve_GFp)(
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+EC_GROUP *(*EC_GROUP_new_by_curve_name)(int);
+
+int (*EC_GROUP_set_curve_GFp)(
+ EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int (*EC_GROUP_get_curve_GFp)(
+ const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+int (*EC_GROUP_get_degree)(const EC_GROUP *) = NULL;
+
+const EC_METHOD *(*EC_GROUP_method_of)(const EC_GROUP *) = NULL;
+const EC_POINT *(*EC_GROUP_get0_generator)(const EC_GROUP *) = NULL;
+int (*EC_GROUP_get_curve_name)(const EC_GROUP *) = NULL;
+
+EC_POINT *(*EC_POINT_new)(const EC_GROUP *) = NULL;
+void (*EC_POINT_free)(EC_POINT *) = NULL;
+void (*EC_POINT_clear_free)(EC_POINT *) = NULL;
+int (*EC_POINT_copy)(EC_POINT *, const EC_POINT *) = NULL;
+EC_POINT *(*EC_POINT_dup)(const EC_POINT *, const EC_GROUP *) = NULL;
+const EC_METHOD *(*EC_POINT_method_of)(const EC_POINT *) = NULL;
+int (*EC_POINT_set_to_infinity)(const EC_GROUP *, EC_POINT *) = NULL;
+int (*EC_POINT_set_Jprojective_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_get_Jprojective_coordinates_GFp)(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_set_affine_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_get_affine_coordinates_GFp)(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_set_compressed_coordinates_GFp)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, int, BN_CTX *) = NULL;
+
+size_t (*EC_POINT_point2oct)(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t,
+ unsigned char *, size_t, BN_CTX *) = NULL;
+
+int (*EC_POINT_oct2point)(const EC_GROUP *, EC_POINT *,
+ const unsigned char *, size_t, BN_CTX *) = NULL;
+
+BIGNUM *(*EC_POINT_point2bn)(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t form, BIGNUM *, BN_CTX *) = NULL;
+
+EC_POINT *(*EC_POINT_bn2point)(const EC_GROUP *, const BIGNUM *,
+ EC_POINT *, BN_CTX *) = NULL;
+
+char *(*EC_POINT_point2hex)(const EC_GROUP *, const EC_POINT *,
+ point_conversion_form_t form, BN_CTX *) = NULL;
+
+EC_POINT *(*EC_POINT_hex2point)(const EC_GROUP *, const char *,
+ EC_POINT *, BN_CTX *) = NULL;
+
+int (*EC_POINT_add)(const EC_GROUP *, EC_POINT *, const EC_POINT *,
+ const EC_POINT *, BN_CTX *) = NULL;
+
+int (*EC_POINT_dbl)(const EC_GROUP *, EC_POINT *, const EC_POINT *,
+ BN_CTX *) = NULL;
+
+int (*EC_POINT_invert)(const EC_GROUP *, EC_POINT *, BN_CTX *) = NULL;
+int (*EC_POINT_is_at_infinity)(const EC_GROUP *, const EC_POINT *) = NULL;
+
+int (*EC_POINT_is_on_curve)(const EC_GROUP *, const EC_POINT *,
+ BN_CTX *) = NULL;
+
+int (*EC_POINT_cmp)(
+ const EC_GROUP *, const EC_POINT *, const EC_POINT *, BN_CTX *) = NULL;
+
+int (*EC_POINT_make_affine)(const EC_GROUP *, EC_POINT *, BN_CTX *) = NULL;
+
+int (*EC_POINTs_make_affine)(const EC_GROUP *, size_t, EC_POINT *[],
+ BN_CTX *) = NULL;
+
+int (*EC_POINTs_mul)(
+ const EC_GROUP *, EC_POINT *, const BIGNUM *,
+ size_t, const EC_POINT *[], const BIGNUM *[], BN_CTX *) = NULL;
+
+int (*EC_POINT_mul)(const EC_GROUP *, EC_POINT *, const BIGNUM *,
+ const EC_POINT *, const BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_GROUP_precompute_mult)(EC_GROUP *, BN_CTX *) = NULL;
+int (*EC_GROUP_have_precompute_mult)(const EC_GROUP *) = NULL;
+
+const EC_METHOD *(*EC_GFp_simple_method)() = NULL;
+const EC_METHOD *(*EC_GFp_mont_method)() = NULL;
+const EC_METHOD *(*EC_GFp_nist_method)() = NULL;
+
+int (*EC_METHOD_get_field_type)(const EC_METHOD *) = NULL;
+
+#else
+static const long Cryptography_HAS_EC = 1;
+#endif
+
+#if defined(OPENSSL_NO_EC) || OPENSSL_VERSION_NUMBER < 0x1000100f
+static const long Cryptography_HAS_EC_1_0_1 = 0;
+
+int (*EC_KEY_get_flags)(const EC_KEY *) = NULL;
+void (*EC_KEY_set_flags)(EC_KEY *, int) = NULL;
+void (*EC_KEY_clear_flags)(EC_KEY *, int) = NULL;
+
+int (*EC_KEY_set_public_key_affine_coordinates)(
+ EC_KEY *, BIGNUM *, BIGNUM *) = NULL;
+#else
+static const long Cryptography_HAS_EC_1_0_1 = 1;
+#endif
+
+
+#if defined(OPENSSL_NO_EC) || OPENSSL_VERSION_NUMBER < 0x1000100f || \
+ defined(OPENSSL_NO_EC_NISTP_64_GCC_128)
+static const long Cryptography_HAS_EC_NISTP_64_GCC_128 = 0;
+
+const EC_METHOD *(*EC_GFp_nistp224_method)(void) = NULL;
+const EC_METHOD *(*EC_GFp_nistp256_method)(void) = NULL;
+const EC_METHOD *(*EC_GFp_nistp521_method)(void) = NULL;
+#else
+static const long Cryptography_HAS_EC_NISTP_64_GCC_128 = 1;
+#endif
+
+#if defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_EC2M)
+static const long Cryptography_HAS_EC2M = 0;
+
+const EC_METHOD *(*EC_GF2m_simple_method)() = NULL;
+
+int (*EC_POINT_set_affine_coordinates_GF2m)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, const BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_get_affine_coordinates_GF2m)(const EC_GROUP *,
+ const EC_POINT *, BIGNUM *, BIGNUM *, BN_CTX *) = NULL;
+
+int (*EC_POINT_set_compressed_coordinates_GF2m)(const EC_GROUP *, EC_POINT *,
+ const BIGNUM *, int, BN_CTX *) = NULL;
+
+int (*EC_GROUP_set_curve_GF2m)(
+ EC_GROUP *, const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+
+int (*EC_GROUP_get_curve_GF2m)(
+ const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+
+EC_GROUP *(*EC_GROUP_new_curve_GF2m)(
+ const BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *);
+#else
+static const long Cryptography_HAS_EC2M = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC": [
+ "OPENSSL_EC_NAMED_CURVE",
+ "EC_GROUP_new",
+ "EC_GROUP_free",
+ "EC_GROUP_clear_free",
+ "EC_GROUP_new_curve_GFp",
+ "EC_GROUP_new_by_curve_name",
+ "EC_GROUP_set_curve_GFp",
+ "EC_GROUP_get_curve_GFp",
+ "EC_GROUP_method_of",
+ "EC_GROUP_get0_generator",
+ "EC_GROUP_get_curve_name",
+ "EC_GROUP_get_degree",
+ "EC_KEY_free",
+ "EC_get_builtin_curves",
+ "EC_KEY_new_by_curve_name",
+ "EC_KEY_copy",
+ "EC_KEY_dup",
+ "EC_KEY_up_ref",
+ "EC_KEY_set_group",
+ "EC_KEY_get0_private_key",
+ "EC_KEY_set_private_key",
+ "EC_KEY_set_public_key",
+ "EC_KEY_get_enc_flags",
+ "EC_KEY_set_enc_flags",
+ "EC_KEY_set_conv_form",
+ "EC_KEY_get_key_method_data",
+ "EC_KEY_insert_key_method_data",
+ "EC_KEY_set_asn1_flag",
+ "EC_KEY_precompute_mult",
+ "EC_KEY_generate_key",
+ "EC_KEY_check_key",
+ "EC_POINT_new",
+ "EC_POINT_free",
+ "EC_POINT_clear_free",
+ "EC_POINT_copy",
+ "EC_POINT_dup",
+ "EC_POINT_method_of",
+ "EC_POINT_set_to_infinity",
+ "EC_POINT_set_Jprojective_coordinates_GFp",
+ "EC_POINT_get_Jprojective_coordinates_GFp",
+ "EC_POINT_set_affine_coordinates_GFp",
+ "EC_POINT_get_affine_coordinates_GFp",
+ "EC_POINT_set_compressed_coordinates_GFp",
+ "EC_POINT_point2oct",
+ "EC_POINT_oct2point",
+ "EC_POINT_point2bn",
+ "EC_POINT_bn2point",
+ "EC_POINT_point2hex",
+ "EC_POINT_hex2point",
+ "EC_POINT_add",
+ "EC_POINT_dbl",
+ "EC_POINT_invert",
+ "EC_POINT_is_at_infinity",
+ "EC_POINT_is_on_curve",
+ "EC_POINT_cmp",
+ "EC_POINT_make_affine",
+ "EC_POINTs_make_affine",
+ "EC_POINTs_mul",
+ "EC_POINT_mul",
+ "EC_GROUP_precompute_mult",
+ "EC_GROUP_have_precompute_mult",
+ "EC_GFp_simple_method",
+ "EC_GFp_mont_method",
+ "EC_GFp_nist_method",
+ "EC_METHOD_get_field_type",
+ ],
+
+ "Cryptography_HAS_EC_1_0_1": [
+ "EC_KEY_get_flags",
+ "EC_KEY_set_flags",
+ "EC_KEY_clear_flags",
+ "EC_KEY_set_public_key_affine_coordinates",
+ ],
+
+ "Cryptography_HAS_EC_NISTP_64_GCC_128": [
+ "EC_GFp_nistp224_method",
+ "EC_GFp_nistp256_method",
+ "EC_GFp_nistp521_method",
+ ],
+
+ "Cryptography_HAS_EC2M": [
+ "EC_GF2m_simple_method",
+ "EC_POINT_set_affine_coordinates_GF2m",
+ "EC_POINT_get_affine_coordinates_GF2m",
+ "EC_POINT_set_compressed_coordinates_GF2m",
+ "EC_GROUP_set_curve_GF2m",
+ "EC_GROUP_get_curve_GF2m",
+ "EC_GROUP_new_curve_GF2m",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/ecdh.py b/src/cryptography/hazmat/bindings/openssl/ecdh.py
new file mode 100644
index 00000000..960d46fb
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/ecdh.py
@@ -0,0 +1,68 @@
+# 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
+
+INCLUDES = """
+#ifndef OPENSSL_NO_ECDH
+#include <openssl/ecdh.h>
+#endif
+"""
+
+TYPES = """
+static const int Cryptography_HAS_ECDH;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+int ECDH_compute_key(void *, size_t, const EC_POINT *, EC_KEY *,
+ void *(*)(const void *, size_t, void *, size_t *));
+
+int ECDH_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *,
+ CRYPTO_EX_free *);
+
+int ECDH_set_ex_data(EC_KEY *, int, void *);
+
+void *ECDH_get_ex_data(EC_KEY *, int);
+"""
+
+CUSTOMIZATIONS = """
+#ifdef OPENSSL_NO_ECDH
+static const long Cryptography_HAS_ECDH = 0;
+
+int (*ECDH_compute_key)(void *, size_t, const EC_POINT *, EC_KEY *,
+ void *(*)(const void *, size_t, void *,
+ size_t *)) = NULL;
+
+int (*ECDH_get_ex_new_index)(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *,
+ CRYPTO_EX_free *) = NULL;
+
+int (*ECDH_set_ex_data)(EC_KEY *, int, void *) = NULL;
+
+void *(*ECDH_get_ex_data)(EC_KEY *, int) = NULL;
+
+#else
+static const long Cryptography_HAS_ECDH = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_ECDH": [
+ "ECDH_compute_key",
+ "ECDH_get_ex_new_index",
+ "ECDH_set_ex_data",
+ "ECDH_get_ex_data",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/ecdsa.py b/src/cryptography/hazmat/bindings/openssl/ecdsa.py
new file mode 100644
index 00000000..bfa67206
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/ecdsa.py
@@ -0,0 +1,130 @@
+# 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
+
+INCLUDES = """
+#ifndef OPENSSL_NO_ECDSA
+#include <openssl/ecdsa.h>
+#endif
+"""
+
+TYPES = """
+static const int Cryptography_HAS_ECDSA;
+
+typedef struct {
+ BIGNUM *r;
+ BIGNUM *s;
+} ECDSA_SIG;
+
+typedef ... CRYPTO_EX_new;
+typedef ... CRYPTO_EX_dup;
+typedef ... CRYPTO_EX_free;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+ECDSA_SIG *ECDSA_SIG_new();
+void ECDSA_SIG_free(ECDSA_SIG *);
+int i2d_ECDSA_SIG(const ECDSA_SIG *, unsigned char **);
+ECDSA_SIG *d2i_ECDSA_SIG(ECDSA_SIG **s, const unsigned char **, long);
+ECDSA_SIG *ECDSA_do_sign(const unsigned char *, int, EC_KEY *);
+ECDSA_SIG *ECDSA_do_sign_ex(const unsigned char *, int, const BIGNUM *,
+ const BIGNUM *, EC_KEY *);
+int ECDSA_do_verify(const unsigned char *, int, const ECDSA_SIG *, EC_KEY*);
+int ECDSA_sign_setup(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **);
+int ECDSA_sign(int, const unsigned char *, int, unsigned char *,
+ unsigned int *, EC_KEY *);
+int ECDSA_sign_ex(int, const unsigned char *, int dgstlen, unsigned char *,
+ unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *);
+int ECDSA_verify(int, const unsigned char *, int, const unsigned char *, int,
+ EC_KEY *);
+int ECDSA_size(const EC_KEY *);
+
+const ECDSA_METHOD* ECDSA_OpenSSL();
+void ECDSA_set_default_method(const ECDSA_METHOD *);
+const ECDSA_METHOD* ECDSA_get_default_method();
+int ECDSA_get_ex_new_index(long, void *, CRYPTO_EX_new *,
+ CRYPTO_EX_dup *, CRYPTO_EX_free *);
+int ECDSA_set_method(EC_KEY *, const ECDSA_METHOD *);
+int ECDSA_set_ex_data(EC_KEY *, int, void *);
+void *ECDSA_get_ex_data(EC_KEY *, int);
+"""
+
+CUSTOMIZATIONS = """
+#ifdef OPENSSL_NO_ECDSA
+static const long Cryptography_HAS_ECDSA = 0;
+
+typedef struct {
+ BIGNUM *r;
+ BIGNUM *s;
+} ECDSA_SIG;
+
+ECDSA_SIG* (*ECDSA_SIG_new)() = NULL;
+void (*ECDSA_SIG_free)(ECDSA_SIG *) = NULL;
+int (*i2d_ECDSA_SIG)(const ECDSA_SIG *, unsigned char **) = NULL;
+ECDSA_SIG* (*d2i_ECDSA_SIG)(ECDSA_SIG **s, const unsigned char **,
+ long) = NULL;
+ECDSA_SIG* (*ECDSA_do_sign)(const unsigned char *, int, EC_KEY *eckey) = NULL;
+ECDSA_SIG* (*ECDSA_do_sign_ex)(const unsigned char *, int, const BIGNUM *,
+ const BIGNUM *, EC_KEY *) = NULL;
+int (*ECDSA_do_verify)(const unsigned char *, int, const ECDSA_SIG *,
+ EC_KEY*) = NULL;
+int (*ECDSA_sign_setup)(EC_KEY *, BN_CTX *, BIGNUM **, BIGNUM **) = NULL;
+int (*ECDSA_sign)(int, const unsigned char *, int, unsigned char *,
+ unsigned int *, EC_KEY *) = NULL;
+int (*ECDSA_sign_ex)(int, const unsigned char *, int dgstlen, unsigned char *,
+ unsigned int *, const BIGNUM *, const BIGNUM *,
+ EC_KEY *) = NULL;
+int (*ECDSA_verify)(int, const unsigned char *, int, const unsigned char *,
+ int, EC_KEY *) = NULL;
+int (*ECDSA_size)(const EC_KEY *) = NULL;
+
+const ECDSA_METHOD* (*ECDSA_OpenSSL)() = NULL;
+void (*ECDSA_set_default_method)(const ECDSA_METHOD *) = NULL;
+const ECDSA_METHOD* (*ECDSA_get_default_method)() = NULL;
+int (*ECDSA_set_method)(EC_KEY *, const ECDSA_METHOD *) = NULL;
+int (*ECDSA_get_ex_new_index)(long, void *, CRYPTO_EX_new *,
+ CRYPTO_EX_dup *, CRYPTO_EX_free *) = NULL;
+int (*ECDSA_set_ex_data)(EC_KEY *, int, void *) = NULL;
+void* (*ECDSA_get_ex_data)(EC_KEY *, int) = NULL;
+#else
+static const long Cryptography_HAS_ECDSA = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_ECDSA": [
+ "ECDSA_SIG_new",
+ "ECDSA_SIG_free",
+ "i2d_ECDSA_SIG",
+ "d2i_ECDSA_SIG",
+ "ECDSA_do_sign",
+ "ECDSA_do_sign_ex",
+ "ECDSA_do_verify",
+ "ECDSA_sign_setup",
+ "ECDSA_sign",
+ "ECDSA_sign_ex",
+ "ECDSA_verify",
+ "ECDSA_size",
+ "ECDSA_OpenSSL",
+ "ECDSA_set_default_method",
+ "ECDSA_get_default_method",
+ "ECDSA_set_method",
+ "ECDSA_get_ex_new_index",
+ "ECDSA_set_ex_data",
+ "ECDSA_get_ex_data",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/engine.py b/src/cryptography/hazmat/bindings/openssl/engine.py
new file mode 100644
index 00000000..364232e0
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/engine.py
@@ -0,0 +1,165 @@
+# 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
+
+INCLUDES = """
+#include <openssl/engine.h>
+"""
+
+TYPES = """
+typedef ... ENGINE;
+typedef ... RSA_METHOD;
+typedef ... DSA_METHOD;
+typedef ... ECDH_METHOD;
+typedef ... ECDSA_METHOD;
+typedef ... DH_METHOD;
+typedef ... RAND_METHOD;
+typedef ... STORE_METHOD;
+typedef ... *ENGINE_GEN_INT_FUNC_PTR;
+typedef ... *ENGINE_CTRL_FUNC_PTR;
+typedef ... *ENGINE_LOAD_KEY_PTR;
+typedef ... *ENGINE_CIPHERS_PTR;
+typedef ... *ENGINE_DIGESTS_PTR;
+typedef ... ENGINE_CMD_DEFN;
+typedef ... UI_METHOD;
+
+static const unsigned int ENGINE_METHOD_RSA;
+static const unsigned int ENGINE_METHOD_DSA;
+static const unsigned int ENGINE_METHOD_RAND;
+static const unsigned int ENGINE_METHOD_ECDH;
+static const unsigned int ENGINE_METHOD_ECDSA;
+static const unsigned int ENGINE_METHOD_CIPHERS;
+static const unsigned int ENGINE_METHOD_DIGESTS;
+static const unsigned int ENGINE_METHOD_STORE;
+static const unsigned int ENGINE_METHOD_ALL;
+static const unsigned int ENGINE_METHOD_NONE;
+"""
+
+FUNCTIONS = """
+ENGINE *ENGINE_get_first(void);
+ENGINE *ENGINE_get_last(void);
+ENGINE *ENGINE_get_next(ENGINE *);
+ENGINE *ENGINE_get_prev(ENGINE *);
+int ENGINE_add(ENGINE *);
+int ENGINE_remove(ENGINE *);
+ENGINE *ENGINE_by_id(const char *);
+int ENGINE_init(ENGINE *);
+int ENGINE_finish(ENGINE *);
+void ENGINE_load_openssl(void);
+void ENGINE_load_dynamic(void);
+void ENGINE_load_cryptodev(void);
+void ENGINE_load_builtin_engines(void);
+void ENGINE_cleanup(void);
+ENGINE *ENGINE_get_default_RSA(void);
+ENGINE *ENGINE_get_default_DSA(void);
+ENGINE *ENGINE_get_default_ECDH(void);
+ENGINE *ENGINE_get_default_ECDSA(void);
+ENGINE *ENGINE_get_default_DH(void);
+ENGINE *ENGINE_get_default_RAND(void);
+ENGINE *ENGINE_get_cipher_engine(int);
+ENGINE *ENGINE_get_digest_engine(int);
+int ENGINE_set_default_RSA(ENGINE *);
+int ENGINE_set_default_DSA(ENGINE *);
+int ENGINE_set_default_ECDH(ENGINE *);
+int ENGINE_set_default_ECDSA(ENGINE *);
+int ENGINE_set_default_DH(ENGINE *);
+int ENGINE_set_default_RAND(ENGINE *);
+int ENGINE_set_default_ciphers(ENGINE *);
+int ENGINE_set_default_digests(ENGINE *);
+int ENGINE_set_default_string(ENGINE *, const char *);
+int ENGINE_set_default(ENGINE *, unsigned int);
+unsigned int ENGINE_get_table_flags(void);
+void ENGINE_set_table_flags(unsigned int);
+int ENGINE_register_RSA(ENGINE *);
+void ENGINE_unregister_RSA(ENGINE *);
+void ENGINE_register_all_RSA(void);
+int ENGINE_register_DSA(ENGINE *);
+void ENGINE_unregister_DSA(ENGINE *);
+void ENGINE_register_all_DSA(void);
+int ENGINE_register_ECDH(ENGINE *);
+void ENGINE_unregister_ECDH(ENGINE *);
+void ENGINE_register_all_ECDH(void);
+int ENGINE_register_ECDSA(ENGINE *);
+void ENGINE_unregister_ECDSA(ENGINE *);
+void ENGINE_register_all_ECDSA(void);
+int ENGINE_register_DH(ENGINE *);
+void ENGINE_unregister_DH(ENGINE *);
+void ENGINE_register_all_DH(void);
+int ENGINE_register_RAND(ENGINE *);
+void ENGINE_unregister_RAND(ENGINE *);
+void ENGINE_register_all_RAND(void);
+int ENGINE_register_STORE(ENGINE *);
+void ENGINE_unregister_STORE(ENGINE *);
+void ENGINE_register_all_STORE(void);
+int ENGINE_register_ciphers(ENGINE *);
+void ENGINE_unregister_ciphers(ENGINE *);
+void ENGINE_register_all_ciphers(void);
+int ENGINE_register_digests(ENGINE *);
+void ENGINE_unregister_digests(ENGINE *);
+void ENGINE_register_all_digests(void);
+int ENGINE_register_complete(ENGINE *);
+int ENGINE_register_all_complete(void);
+int ENGINE_ctrl(ENGINE *, int, long, void *, void (*)(void));
+int ENGINE_cmd_is_executable(ENGINE *, int);
+int ENGINE_ctrl_cmd(ENGINE *, const char *, long, void *, void (*)(void), int);
+int ENGINE_ctrl_cmd_string(ENGINE *, const char *, const char *, int);
+
+ENGINE *ENGINE_new(void);
+int ENGINE_free(ENGINE *);
+int ENGINE_up_ref(ENGINE *);
+int ENGINE_set_id(ENGINE *, const char *);
+int ENGINE_set_name(ENGINE *, const char *);
+int ENGINE_set_RSA(ENGINE *, const RSA_METHOD *);
+int ENGINE_set_DSA(ENGINE *, const DSA_METHOD *);
+int ENGINE_set_ECDH(ENGINE *, const ECDH_METHOD *);
+int ENGINE_set_ECDSA(ENGINE *, const ECDSA_METHOD *);
+int ENGINE_set_DH(ENGINE *, const DH_METHOD *);
+int ENGINE_set_RAND(ENGINE *, const RAND_METHOD *);
+int ENGINE_set_STORE(ENGINE *, const STORE_METHOD *);
+int ENGINE_set_destroy_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR);
+int ENGINE_set_init_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR);
+int ENGINE_set_finish_function(ENGINE *, ENGINE_GEN_INT_FUNC_PTR);
+int ENGINE_set_ctrl_function(ENGINE *, ENGINE_CTRL_FUNC_PTR);
+int ENGINE_set_load_privkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR);
+int ENGINE_set_load_pubkey_function(ENGINE *, ENGINE_LOAD_KEY_PTR);
+int ENGINE_set_ciphers(ENGINE *, ENGINE_CIPHERS_PTR);
+int ENGINE_set_digests(ENGINE *, ENGINE_DIGESTS_PTR);
+int ENGINE_set_flags(ENGINE *, int);
+int ENGINE_set_cmd_defns(ENGINE *, const ENGINE_CMD_DEFN *);
+const char *ENGINE_get_id(const ENGINE *);
+const char *ENGINE_get_name(const ENGINE *);
+const RSA_METHOD *ENGINE_get_RSA(const ENGINE *);
+const DSA_METHOD *ENGINE_get_DSA(const ENGINE *);
+const ECDH_METHOD *ENGINE_get_ECDH(const ENGINE *);
+const ECDSA_METHOD *ENGINE_get_ECDSA(const ENGINE *);
+const DH_METHOD *ENGINE_get_DH(const ENGINE *);
+const RAND_METHOD *ENGINE_get_RAND(const ENGINE *);
+const STORE_METHOD *ENGINE_get_STORE(const ENGINE *);
+
+const EVP_CIPHER *ENGINE_get_cipher(ENGINE *, int);
+const EVP_MD *ENGINE_get_digest(ENGINE *, int);
+int ENGINE_get_flags(const ENGINE *);
+const ENGINE_CMD_DEFN *ENGINE_get_cmd_defns(const ENGINE *);
+EVP_PKEY *ENGINE_load_private_key(ENGINE *, const char *, UI_METHOD *, void *);
+EVP_PKEY *ENGINE_load_public_key(ENGINE *, const char *, UI_METHOD *, void *);
+void ENGINE_add_conf_module(void);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/err.py b/src/cryptography/hazmat/bindings/openssl/err.py
new file mode 100644
index 00000000..4e44a2eb
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/err.py
@@ -0,0 +1,365 @@
+# 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
+
+INCLUDES = """
+#include <openssl/err.h>
+"""
+
+TYPES = """
+static const int Cryptography_HAS_REMOVE_THREAD_STATE;
+static const int Cryptography_HAS_098H_ERROR_CODES;
+static const int Cryptography_HAS_098C_CAMELLIA_CODES;
+static const int Cryptography_HAS_EC_CODES;
+static const int Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR;
+
+struct ERR_string_data_st {
+ unsigned long error;
+ const char *string;
+};
+typedef struct ERR_string_data_st ERR_STRING_DATA;
+
+static const int ERR_LIB_EVP;
+static const int ERR_LIB_EC;
+static const int ERR_LIB_PEM;
+static const int ERR_LIB_ASN1;
+static const int ERR_LIB_RSA;
+static const int ERR_LIB_PKCS12;
+
+static const int ASN1_F_ASN1_ENUMERATED_TO_BN;
+static const int ASN1_F_ASN1_EX_C2I;
+static const int ASN1_F_ASN1_FIND_END;
+static const int ASN1_F_ASN1_GENERALIZEDTIME_SET;
+static const int ASN1_F_ASN1_GENERATE_V3;
+static const int ASN1_F_ASN1_GET_OBJECT;
+static const int ASN1_F_ASN1_ITEM_I2D_FP;
+static const int ASN1_F_ASN1_ITEM_PACK;
+static const int ASN1_F_ASN1_ITEM_SIGN;
+static const int ASN1_F_ASN1_ITEM_UNPACK;
+static const int ASN1_F_ASN1_ITEM_VERIFY;
+static const int ASN1_F_ASN1_MBSTRING_NCOPY;
+static const int ASN1_F_ASN1_TEMPLATE_EX_D2I;
+static const int ASN1_F_ASN1_TEMPLATE_NEW;
+static const int ASN1_F_ASN1_TEMPLATE_NOEXP_D2I;
+static const int ASN1_F_ASN1_TIME_SET;
+static const int ASN1_F_ASN1_TYPE_GET_INT_OCTETSTRING;
+static const int ASN1_F_ASN1_TYPE_GET_OCTETSTRING;
+static const int ASN1_F_ASN1_UNPACK_STRING;
+static const int ASN1_F_ASN1_UTCTIME_SET;
+static const int ASN1_F_ASN1_VERIFY;
+static const int ASN1_F_BITSTR_CB;
+static const int ASN1_F_BN_TO_ASN1_ENUMERATED;
+static const int ASN1_F_BN_TO_ASN1_INTEGER;
+static const int ASN1_F_D2I_ASN1_TYPE_BYTES;
+static const int ASN1_F_D2I_ASN1_UINTEGER;
+static const int ASN1_F_D2I_ASN1_UTCTIME;
+static const int ASN1_F_D2I_NETSCAPE_RSA;
+static const int ASN1_F_D2I_NETSCAPE_RSA_2;
+static const int ASN1_F_D2I_PRIVATEKEY;
+static const int ASN1_F_D2I_X509;
+static const int ASN1_F_D2I_X509_CINF;
+static const int ASN1_F_D2I_X509_PKEY;
+static const int ASN1_F_I2D_ASN1_SET;
+static const int ASN1_F_I2D_ASN1_TIME;
+static const int ASN1_F_I2D_DSA_PUBKEY;
+static const int ASN1_F_LONG_C2I;
+static const int ASN1_F_OID_MODULE_INIT;
+static const int ASN1_F_PARSE_TAGGING;
+static const int ASN1_F_PKCS5_PBE_SET;
+static const int ASN1_F_X509_CINF_NEW;
+
+static const int ASN1_R_BOOLEAN_IS_WRONG_LENGTH;
+static const int ASN1_R_BUFFER_TOO_SMALL;
+static const int ASN1_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER;
+static const int ASN1_R_DATA_IS_WRONG;
+static const int ASN1_R_DECODE_ERROR;
+static const int ASN1_R_DECODING_ERROR;
+static const int ASN1_R_DEPTH_EXCEEDED;
+static const int ASN1_R_ENCODE_ERROR;
+static const int ASN1_R_ERROR_GETTING_TIME;
+static const int ASN1_R_ERROR_LOADING_SECTION;
+static const int ASN1_R_MSTRING_WRONG_TAG;
+static const int ASN1_R_NESTED_ASN1_STRING;
+static const int ASN1_R_NO_MATCHING_CHOICE_TYPE;
+static const int ASN1_R_UNKNOWN_MESSAGE_DIGEST_ALGORITHM;
+static const int ASN1_R_UNKNOWN_OBJECT_TYPE;
+static const int ASN1_R_UNKNOWN_PUBLIC_KEY_TYPE;
+static const int ASN1_R_UNKNOWN_TAG;
+static const int ASN1_R_UNKOWN_FORMAT;
+static const int ASN1_R_UNSUPPORTED_ANY_DEFINED_BY_TYPE;
+static const int ASN1_R_UNSUPPORTED_ENCRYPTION_ALGORITHM;
+static const int ASN1_R_UNSUPPORTED_PUBLIC_KEY_TYPE;
+static const int ASN1_R_UNSUPPORTED_TYPE;
+static const int ASN1_R_WRONG_TAG;
+static const int ASN1_R_WRONG_TYPE;
+
+static const int EVP_F_AES_INIT_KEY;
+static const int EVP_F_D2I_PKEY;
+static const int EVP_F_DSA_PKEY2PKCS8;
+static const int EVP_F_DSAPKEY2PKCS8;
+static const int EVP_F_ECDSA_PKEY2PKCS8;
+static const int EVP_F_ECKEY_PKEY2PKCS8;
+static const int EVP_F_EVP_CIPHER_CTX_CTRL;
+static const int EVP_F_EVP_CIPHER_CTX_SET_KEY_LENGTH;
+static const int EVP_F_EVP_CIPHERINIT_EX;
+static const int EVP_F_EVP_DECRYPTFINAL_EX;
+static const int EVP_F_EVP_DIGESTINIT_EX;
+static const int EVP_F_EVP_ENCRYPTFINAL_EX;
+static const int EVP_F_EVP_MD_CTX_COPY_EX;
+static const int EVP_F_EVP_OPENINIT;
+static const int EVP_F_EVP_PBE_ALG_ADD;
+static const int EVP_F_EVP_PBE_CIPHERINIT;
+static const int EVP_F_EVP_PKCS82PKEY;
+static const int EVP_F_EVP_PKEY2PKCS8_BROKEN;
+static const int EVP_F_EVP_PKEY_COPY_PARAMETERS;
+static const int EVP_F_EVP_PKEY_DECRYPT;
+static const int EVP_F_EVP_PKEY_ENCRYPT;
+static const int EVP_F_EVP_PKEY_GET1_DH;
+static const int EVP_F_EVP_PKEY_GET1_DSA;
+static const int EVP_F_EVP_PKEY_GET1_ECDSA;
+static const int EVP_F_EVP_PKEY_GET1_EC_KEY;
+static const int EVP_F_EVP_PKEY_GET1_RSA;
+static const int EVP_F_EVP_PKEY_NEW;
+static const int EVP_F_EVP_RIJNDAEL;
+static const int EVP_F_EVP_SIGNFINAL;
+static const int EVP_F_EVP_VERIFYFINAL;
+static const int EVP_F_PKCS5_PBE_KEYIVGEN;
+static const int EVP_F_PKCS5_V2_PBE_KEYIVGEN;
+static const int EVP_F_PKCS8_SET_BROKEN;
+static const int EVP_F_RC2_MAGIC_TO_METH;
+static const int EVP_F_RC5_CTRL;
+
+static const int EVP_R_AES_KEY_SETUP_FAILED;
+static const int EVP_R_ASN1_LIB;
+static const int EVP_R_BAD_BLOCK_LENGTH;
+static const int EVP_R_BAD_DECRYPT;
+static const int EVP_R_BAD_KEY_LENGTH;
+static const int EVP_R_BN_DECODE_ERROR;
+static const int EVP_R_BN_PUBKEY_ERROR;
+static const int EVP_R_CIPHER_PARAMETER_ERROR;
+static const int EVP_R_CTRL_NOT_IMPLEMENTED;
+static const int EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED;
+static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH;
+static const int EVP_R_DECODE_ERROR;
+static const int EVP_R_DIFFERENT_KEY_TYPES;
+static const int EVP_R_ENCODE_ERROR;
+static const int EVP_R_INITIALIZATION_ERROR;
+static const int EVP_R_INPUT_NOT_INITIALIZED;
+static const int EVP_R_INVALID_KEY_LENGTH;
+static const int EVP_R_IV_TOO_LARGE;
+static const int EVP_R_KEYGEN_FAILURE;
+static const int EVP_R_MISSING_PARAMETERS;
+static const int EVP_R_NO_CIPHER_SET;
+static const int EVP_R_NO_DIGEST_SET;
+static const int EVP_R_NO_DSA_PARAMETERS;
+static const int EVP_R_NO_SIGN_FUNCTION_CONFIGURED;
+static const int EVP_R_NO_VERIFY_FUNCTION_CONFIGURED;
+static const int EVP_R_PKCS8_UNKNOWN_BROKEN_TYPE;
+static const int EVP_R_PUBLIC_KEY_NOT_RSA;
+static const int EVP_R_UNKNOWN_PBE_ALGORITHM;
+static const int EVP_R_UNSUPORTED_NUMBER_OF_ROUNDS;
+static const int EVP_R_UNSUPPORTED_CIPHER;
+static const int EVP_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION;
+static const int EVP_R_UNSUPPORTED_KEYLENGTH;
+static const int EVP_R_UNSUPPORTED_SALT_TYPE;
+static const int EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM;
+static const int EVP_R_WRONG_FINAL_BLOCK_LENGTH;
+static const int EVP_R_WRONG_PUBLIC_KEY_TYPE;
+
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME;
+
+static const int EC_R_UNKNOWN_GROUP;
+
+static const int PEM_F_D2I_PKCS8PRIVATEKEY_BIO;
+static const int PEM_F_D2I_PKCS8PRIVATEKEY_FP;
+static const int PEM_F_DO_PK8PKEY;
+static const int PEM_F_DO_PK8PKEY_FP;
+static const int PEM_F_LOAD_IV;
+static const int PEM_F_PEM_ASN1_READ;
+static const int PEM_F_PEM_ASN1_READ_BIO;
+static const int PEM_F_PEM_ASN1_WRITE;
+static const int PEM_F_PEM_ASN1_WRITE_BIO;
+static const int PEM_F_PEM_DEF_CALLBACK;
+static const int PEM_F_PEM_DO_HEADER;
+static const int PEM_F_PEM_F_PEM_WRITE_PKCS8PRIVATEKEY;
+static const int PEM_F_PEM_GET_EVP_CIPHER_INFO;
+static const int PEM_F_PEM_PK8PKEY;
+static const int PEM_F_PEM_READ;
+static const int PEM_F_PEM_READ_BIO;
+static const int PEM_F_PEM_READ_BIO_PRIVATEKEY;
+static const int PEM_F_PEM_READ_PRIVATEKEY;
+static const int PEM_F_PEM_SEALFINAL;
+static const int PEM_F_PEM_SEALINIT;
+static const int PEM_F_PEM_SIGNFINAL;
+static const int PEM_F_PEM_WRITE;
+static const int PEM_F_PEM_WRITE_BIO;
+static const int PEM_F_PEM_X509_INFO_READ;
+static const int PEM_F_PEM_X509_INFO_READ_BIO;
+static const int PEM_F_PEM_X509_INFO_WRITE_BIO;
+
+static const int PEM_R_BAD_BASE64_DECODE;
+static const int PEM_R_BAD_DECRYPT;
+static const int PEM_R_BAD_END_LINE;
+static const int PEM_R_BAD_IV_CHARS;
+static const int PEM_R_BAD_PASSWORD_READ;
+static const int PEM_R_ERROR_CONVERTING_PRIVATE_KEY;
+static const int PEM_R_NO_START_LINE;
+static const int PEM_R_NOT_DEK_INFO;
+static const int PEM_R_NOT_ENCRYPTED;
+static const int PEM_R_NOT_PROC_TYPE;
+static const int PEM_R_PROBLEMS_GETTING_PASSWORD;
+static const int PEM_R_PUBLIC_KEY_NO_RSA;
+static const int PEM_R_READ_KEY;
+static const int PEM_R_SHORT_HEADER;
+static const int PEM_R_UNSUPPORTED_CIPHER;
+static const int PEM_R_UNSUPPORTED_ENCRYPTION;
+
+static const int PKCS12_F_PKCS12_PBE_CRYPT;
+
+static const int PKCS12_R_PKCS12_CIPHERFINAL_ERROR;
+
+static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE;
+static const int RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY;
+static const int RSA_R_BLOCK_TYPE_IS_NOT_01;
+static const int RSA_R_BLOCK_TYPE_IS_NOT_02;
+static const int RSA_R_PKCS_DECODING_ERROR;
+"""
+
+FUNCTIONS = """
+void ERR_load_crypto_strings(void);
+void ERR_load_SSL_strings(void);
+void ERR_free_strings(void);
+char* ERR_error_string(unsigned long, char *);
+void ERR_error_string_n(unsigned long, char *, size_t);
+const char* ERR_lib_error_string(unsigned long);
+const char* ERR_func_error_string(unsigned long);
+const char* ERR_reason_error_string(unsigned long);
+void ERR_print_errors(BIO *);
+void ERR_print_errors_fp(FILE *);
+unsigned long ERR_get_error(void);
+unsigned long ERR_peek_error(void);
+unsigned long ERR_peek_last_error(void);
+unsigned long ERR_get_error_line(const char **, int *);
+unsigned long ERR_peek_error_line(const char **, int *);
+unsigned long ERR_peek_last_error_line(const char **, int *);
+unsigned long ERR_get_error_line_data(const char **, int *,
+ const char **, int *);
+unsigned long ERR_peek_error_line_data(const char **,
+ int *, const char **, int *);
+unsigned long ERR_peek_last_error_line_data(const char **,
+ int *, const char **, int *);
+void ERR_put_error(int, int, int, const char *, int);
+void ERR_add_error_data(int, ...);
+int ERR_get_next_error_library(void);
+"""
+
+MACROS = """
+unsigned long ERR_PACK(int, int, int);
+int ERR_GET_LIB(unsigned long);
+int ERR_GET_FUNC(unsigned long);
+int ERR_GET_REASON(unsigned long);
+int ERR_FATAL_ERROR(unsigned long);
+/* introduced in 1.0.0 so we have to handle this specially to continue
+ * supporting 0.9.8
+ */
+void ERR_remove_thread_state(const CRYPTO_THREADID *);
+
+/* These were added in OpenSSL 0.9.8h. When we drop support for RHEL/CentOS 5
+ we should be able to move these back to TYPES. */
+static const int ASN1_F_B64_READ_ASN1;
+static const int ASN1_F_B64_WRITE_ASN1;
+static const int ASN1_F_SMIME_READ_ASN1;
+static const int ASN1_F_SMIME_TEXT;
+static const int ASN1_R_NO_CONTENT_TYPE;
+static const int ASN1_R_NO_MULTIPART_BODY_FAILURE;
+static const int ASN1_R_NO_MULTIPART_BOUNDARY;
+/* These were added in OpenSSL 0.9.8c. */
+static const int EVP_F_CAMELLIA_INIT_KEY;
+static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED;
+"""
+
+CUSTOMIZATIONS = """
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_REMOVE_THREAD_STATE = 1;
+#else
+static const long Cryptography_HAS_REMOVE_THREAD_STATE = 0;
+typedef uint32_t CRYPTO_THREADID;
+void (*ERR_remove_thread_state)(const CRYPTO_THREADID *) = NULL;
+#endif
+
+/* OpenSSL 0.9.8h+ */
+#if OPENSSL_VERSION_NUMBER >= 0x0090808fL
+static const long Cryptography_HAS_098H_ERROR_CODES = 1;
+#else
+static const long Cryptography_HAS_098H_ERROR_CODES = 0;
+static const int ASN1_F_B64_READ_ASN1 = 0;
+static const int ASN1_F_B64_WRITE_ASN1 = 0;
+static const int ASN1_F_SMIME_READ_ASN1 = 0;
+static const int ASN1_F_SMIME_TEXT = 0;
+static const int ASN1_R_NO_CONTENT_TYPE = 0;
+static const int ASN1_R_NO_MULTIPART_BODY_FAILURE = 0;
+static const int ASN1_R_NO_MULTIPART_BOUNDARY = 0;
+#endif
+
+/* OpenSSL 0.9.8c+ */
+#ifdef EVP_F_CAMELLIA_INIT_KEY
+static const long Cryptography_HAS_098C_CAMELLIA_CODES = 1;
+#else
+static const long Cryptography_HAS_098C_CAMELLIA_CODES = 0;
+static const int EVP_F_CAMELLIA_INIT_KEY = 0;
+static const int EVP_R_CAMELLIA_KEY_SETUP_FAILED = 0;
+#endif
+
+// OpenSSL without EC. e.g. RHEL
+#ifndef OPENSSL_NO_EC
+static const long Cryptography_HAS_EC_CODES = 1;
+#else
+static const long Cryptography_HAS_EC_CODES = 0;
+static const int EC_R_UNKNOWN_GROUP = 0;
+static const int EC_F_EC_GROUP_NEW_BY_CURVE_NAME = 0;
+#endif
+
+#ifdef RSA_R_PKCS_DECODING_ERROR
+static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 1;
+#else
+static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 0;
+static const long RSA_R_PKCS_DECODING_ERROR = 0;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_REMOVE_THREAD_STATE": [
+ "ERR_remove_thread_state"
+ ],
+ "Cryptography_HAS_098H_ERROR_CODES": [
+ "ASN1_F_B64_READ_ASN1",
+ "ASN1_F_B64_WRITE_ASN1",
+ "ASN1_F_SMIME_READ_ASN1",
+ "ASN1_F_SMIME_TEXT",
+ "ASN1_R_NO_CONTENT_TYPE",
+ "ASN1_R_NO_MULTIPART_BODY_FAILURE",
+ "ASN1_R_NO_MULTIPART_BOUNDARY",
+ ],
+ "Cryptography_HAS_098C_CAMELLIA_CODES": [
+ "EVP_F_CAMELLIA_INIT_KEY",
+ "EVP_R_CAMELLIA_KEY_SETUP_FAILED"
+ ],
+ "Cryptography_HAS_EC_CODES": [
+ "EC_R_UNKNOWN_GROUP",
+ "EC_F_EC_GROUP_NEW_BY_CURVE_NAME"
+ ],
+ "Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": [
+ "RSA_R_PKCS_DECODING_ERROR"
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/evp.py b/src/cryptography/hazmat/bindings/openssl/evp.py
new file mode 100644
index 00000000..033b083b
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/evp.py
@@ -0,0 +1,263 @@
+# 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
+
+INCLUDES = """
+#include <openssl/evp.h>
+"""
+
+TYPES = """
+typedef ... EVP_CIPHER;
+typedef struct {
+ const EVP_CIPHER *cipher;
+ ENGINE *engine;
+ int encrypt;
+ ...;
+} EVP_CIPHER_CTX;
+typedef ... EVP_MD;
+typedef struct env_md_ctx_st {
+ ...;
+} EVP_MD_CTX;
+
+typedef struct evp_pkey_st {
+ int type;
+ ...;
+} EVP_PKEY;
+typedef ... EVP_PKEY_CTX;
+static const int EVP_PKEY_RSA;
+static const int EVP_PKEY_DSA;
+static const int EVP_PKEY_EC;
+static const int EVP_MAX_MD_SIZE;
+static const int EVP_CTRL_GCM_SET_IVLEN;
+static const int EVP_CTRL_GCM_GET_TAG;
+static const int EVP_CTRL_GCM_SET_TAG;
+
+static const int Cryptography_HAS_GCM;
+static const int Cryptography_HAS_PBKDF2_HMAC;
+static const int Cryptography_HAS_PKEY_CTX;
+"""
+
+FUNCTIONS = """
+const EVP_CIPHER *EVP_get_cipherbyname(const char *);
+int EVP_EncryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *,
+ const unsigned char *, const unsigned char *);
+int EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *, int);
+int EVP_EncryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *,
+ const unsigned char *, int);
+int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *);
+int EVP_DecryptInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *,
+ const unsigned char *, const unsigned char *);
+int EVP_DecryptUpdate(EVP_CIPHER_CTX *, unsigned char *, int *,
+ const unsigned char *, int);
+int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *);
+int EVP_CipherInit_ex(EVP_CIPHER_CTX *, const EVP_CIPHER *, ENGINE *,
+ const unsigned char *, const unsigned char *, int);
+int EVP_CipherUpdate(EVP_CIPHER_CTX *, unsigned char *, int *,
+ const unsigned char *, int);
+int EVP_CipherFinal_ex(EVP_CIPHER_CTX *, unsigned char *, int *);
+int EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *);
+void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *);
+EVP_CIPHER_CTX *EVP_CIPHER_CTX_new(void);
+void EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *);
+int EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *, int);
+
+EVP_MD_CTX *EVP_MD_CTX_create(void);
+int EVP_MD_CTX_copy_ex(EVP_MD_CTX *, const EVP_MD_CTX *);
+int EVP_DigestInit_ex(EVP_MD_CTX *, const EVP_MD *, ENGINE *);
+int EVP_DigestUpdate(EVP_MD_CTX *, const void *, size_t);
+int EVP_DigestFinal_ex(EVP_MD_CTX *, unsigned char *, unsigned int *);
+int EVP_MD_CTX_cleanup(EVP_MD_CTX *);
+void EVP_MD_CTX_destroy(EVP_MD_CTX *);
+const EVP_MD *EVP_get_digestbyname(const char *);
+
+EVP_PKEY *EVP_PKEY_new(void);
+void EVP_PKEY_free(EVP_PKEY *);
+int EVP_PKEY_type(int);
+int EVP_PKEY_bits(EVP_PKEY *);
+int EVP_PKEY_size(EVP_PKEY *);
+RSA *EVP_PKEY_get1_RSA(EVP_PKEY *);
+DSA *EVP_PKEY_get1_DSA(EVP_PKEY *);
+DH *EVP_PKEY_get1_DH(EVP_PKEY *);
+
+int EVP_SignInit(EVP_MD_CTX *, const EVP_MD *);
+int EVP_SignUpdate(EVP_MD_CTX *, const void *, size_t);
+int EVP_SignFinal(EVP_MD_CTX *, unsigned char *, unsigned int *, EVP_PKEY *);
+
+int EVP_VerifyInit(EVP_MD_CTX *, const EVP_MD *);
+int EVP_VerifyUpdate(EVP_MD_CTX *, const void *, size_t);
+int EVP_VerifyFinal(EVP_MD_CTX *, const unsigned char *, unsigned int,
+ EVP_PKEY *);
+
+const EVP_MD *EVP_md5(void);
+
+int PKCS5_PBKDF2_HMAC_SHA1(const char *, int, const unsigned char *, int, int,
+ int, unsigned char *);
+
+int EVP_PKEY_set1_RSA(EVP_PKEY *, struct rsa_st *);
+int EVP_PKEY_set1_DSA(EVP_PKEY *, struct dsa_st *);
+int EVP_PKEY_set1_DH(EVP_PKEY *, DH *);
+
+int EVP_PKEY_get_attr_count(const EVP_PKEY *);
+int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *, int, int);
+int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *, ASN1_OBJECT *, int);
+X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *, int);
+X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *, int);
+int EVP_PKEY_add1_attr(EVP_PKEY *, X509_ATTRIBUTE *);
+int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *, const ASN1_OBJECT *, int,
+ const unsigned char *, int);
+int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *, int, int,
+ const unsigned char *, int);
+int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *, const char *, int,
+ const unsigned char *, int);
+
+int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *);
+"""
+
+MACROS = """
+void OpenSSL_add_all_algorithms(void);
+int EVP_PKEY_assign_RSA(EVP_PKEY *, RSA *);
+int EVP_PKEY_assign_DSA(EVP_PKEY *, DSA *);
+
+int EVP_PKEY_assign_EC_KEY(EVP_PKEY *, EC_KEY *);
+EC_KEY *EVP_PKEY_get1_EC_KEY(EVP_PKEY *);
+int EVP_PKEY_set1_EC_KEY(EVP_PKEY *, EC_KEY *);
+
+int EVP_CIPHER_CTX_block_size(const EVP_CIPHER_CTX *);
+int EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *, int, int, void *);
+
+int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int,
+ const EVP_MD *, int, unsigned char *);
+
+int EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *, const EVP_MD *);
+
+/* These aren't macros, but must be in this section because they're not
+ available in 0.9.8. */
+EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *, ENGINE *);
+EVP_PKEY_CTX *EVP_PKEY_CTX_new_id(int, ENGINE *);
+EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_CTX *);
+void EVP_PKEY_CTX_free(EVP_PKEY_CTX *);
+int EVP_PKEY_sign_init(EVP_PKEY_CTX *);
+int EVP_PKEY_sign(EVP_PKEY_CTX *, unsigned char *, size_t *,
+ const unsigned char *, size_t);
+int EVP_PKEY_verify_init(EVP_PKEY_CTX *);
+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 *);
+
+/* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5
+ we should move these back to FUNCTIONS. */
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *);
+int EVP_CIPHER_block_size(const EVP_CIPHER *);
+const EVP_MD *EVP_MD_CTX_md(const EVP_MD_CTX *);
+int EVP_MD_size(const EVP_MD *);
+
+/* Must be in macros because EVP_PKEY_CTX is undefined in 0.9.8 */
+int Cryptography_EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out,
+ size_t *outlen, const unsigned char *in,
+ size_t inlen);
+int Cryptography_EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out,
+ size_t *outlen, const unsigned char *in,
+ size_t inlen);
+"""
+
+CUSTOMIZATIONS = """
+#ifdef EVP_CTRL_GCM_SET_TAG
+const long Cryptography_HAS_GCM = 1;
+#else
+const long Cryptography_HAS_GCM = 0;
+const long EVP_CTRL_GCM_GET_TAG = -1;
+const long EVP_CTRL_GCM_SET_TAG = -1;
+const long EVP_CTRL_GCM_SET_IVLEN = -1;
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+const long Cryptography_HAS_PBKDF2_HMAC = 1;
+const long Cryptography_HAS_PKEY_CTX = 1;
+
+/* OpenSSL 0.9.8 defines EVP_PKEY_encrypt and EVP_PKEY_decrypt functions,
+ but they are a completely different signature from the ones in 1.0.0+.
+ These wrapper functions allows us to safely declare them on any version and
+ conditionally remove them on 0.9.8. */
+int Cryptography_EVP_PKEY_encrypt(EVP_PKEY_CTX *ctx, unsigned char *out,
+ size_t *outlen, const unsigned char *in,
+ size_t inlen) {
+ return EVP_PKEY_encrypt(ctx, out, outlen, in, inlen);
+}
+int Cryptography_EVP_PKEY_decrypt(EVP_PKEY_CTX *ctx, unsigned char *out,
+ size_t *outlen, const unsigned char *in,
+ size_t inlen) {
+ return EVP_PKEY_decrypt(ctx, out, outlen, in, inlen);
+}
+#else
+const long Cryptography_HAS_PBKDF2_HMAC = 0;
+int (*PKCS5_PBKDF2_HMAC)(const char *, int, const unsigned char *, int, int,
+ const EVP_MD *, int, unsigned char *) = NULL;
+const long Cryptography_HAS_PKEY_CTX = 0;
+typedef void EVP_PKEY_CTX;
+int (*EVP_PKEY_CTX_set_signature_md)(EVP_PKEY_CTX *, const EVP_MD *) = NULL;
+int (*EVP_PKEY_sign_init)(EVP_PKEY_CTX *) = NULL;
+int (*EVP_PKEY_sign)(EVP_PKEY_CTX *, unsigned char *, size_t *,
+ const unsigned char *, size_t) = NULL;
+int (*EVP_PKEY_verify_init)(EVP_PKEY_CTX *) = NULL;
+int (*EVP_PKEY_verify)(EVP_PKEY_CTX *, const unsigned char *, size_t,
+ const unsigned char *, size_t) = NULL;
+EVP_PKEY_CTX *(*EVP_PKEY_CTX_new)(EVP_PKEY *, ENGINE *) = NULL;
+EVP_PKEY_CTX *(*EVP_PKEY_CTX_new_id)(int, ENGINE *) = NULL;
+EVP_PKEY_CTX *(*EVP_PKEY_CTX_dup)(EVP_PKEY_CTX *) = NULL;
+void (*EVP_PKEY_CTX_free)(EVP_PKEY_CTX *) = NULL;
+int (*EVP_PKEY_encrypt_init)(EVP_PKEY_CTX *) = NULL;
+int (*EVP_PKEY_decrypt_init)(EVP_PKEY_CTX *) = NULL;
+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;
+#endif
+#ifdef OPENSSL_NO_EC
+int (*EVP_PKEY_assign_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
+EC_KEY *(*EVP_PKEY_get1_EC_KEY)(EVP_PKEY *) = NULL;
+int (*EVP_PKEY_set1_EC_KEY)(EVP_PKEY *, EC_KEY *) = NULL;
+#endif
+
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_GCM": [
+ "EVP_CTRL_GCM_GET_TAG",
+ "EVP_CTRL_GCM_SET_TAG",
+ "EVP_CTRL_GCM_SET_IVLEN",
+ ],
+ "Cryptography_HAS_PBKDF2_HMAC": [
+ "PKCS5_PBKDF2_HMAC"
+ ],
+ "Cryptography_HAS_PKEY_CTX": [
+ "EVP_PKEY_CTX_new",
+ "EVP_PKEY_CTX_new_id",
+ "EVP_PKEY_CTX_dup",
+ "EVP_PKEY_CTX_free",
+ "EVP_PKEY_sign",
+ "EVP_PKEY_sign_init",
+ "EVP_PKEY_verify",
+ "EVP_PKEY_verify_init",
+ "Cryptography_EVP_PKEY_encrypt",
+ "EVP_PKEY_encrypt_init",
+ "Cryptography_EVP_PKEY_decrypt",
+ "EVP_PKEY_decrypt_init",
+ "EVP_PKEY_CTX_set_signature_md",
+ ],
+ "Cryptography_HAS_EC": [
+ "EVP_PKEY_assign_EC_KEY",
+ "EVP_PKEY_get1_EC_KEY",
+ "EVP_PKEY_set1_EC_KEY",
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/hmac.py b/src/cryptography/hazmat/bindings/openssl/hmac.py
new file mode 100644
index 00000000..6a64b92c
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/hmac.py
@@ -0,0 +1,94 @@
+# 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
+
+INCLUDES = """
+#include <openssl/hmac.h>
+"""
+
+TYPES = """
+typedef struct { ...; } HMAC_CTX;
+"""
+
+FUNCTIONS = """
+void HMAC_CTX_init(HMAC_CTX *);
+void HMAC_CTX_cleanup(HMAC_CTX *);
+
+int Cryptography_HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *,
+ ENGINE *);
+int Cryptography_HMAC_Update(HMAC_CTX *, const unsigned char *, size_t);
+int Cryptography_HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *);
+int Cryptography_HMAC_CTX_copy(HMAC_CTX *, HMAC_CTX *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+int Cryptography_HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int key_len,
+ const EVP_MD *md, ENGINE *impl) {
+#if OPENSSL_VERSION_NUMBER >= 0x010000000
+ return HMAC_Init_ex(ctx, key, key_len, md, impl);
+#else
+ HMAC_Init_ex(ctx, key, key_len, md, impl);
+ return 1;
+#endif
+}
+
+int Cryptography_HMAC_Update(HMAC_CTX *ctx, const unsigned char *data,
+ size_t data_len) {
+#if OPENSSL_VERSION_NUMBER >= 0x010000000
+ return HMAC_Update(ctx, data, data_len);
+#else
+ HMAC_Update(ctx, data, data_len);
+ return 1;
+#endif
+}
+
+int Cryptography_HMAC_Final(HMAC_CTX *ctx, unsigned char *digest,
+ unsigned int *outlen) {
+#if OPENSSL_VERSION_NUMBER >= 0x010000000
+ return HMAC_Final(ctx, digest, outlen);
+#else
+ HMAC_Final(ctx, digest, outlen);
+ return 1;
+#endif
+}
+
+int Cryptography_HMAC_CTX_copy(HMAC_CTX *dst_ctx, HMAC_CTX *src_ctx) {
+#if OPENSSL_VERSION_NUMBER >= 0x010000000
+ return HMAC_CTX_copy(dst_ctx, src_ctx);
+#else
+ HMAC_CTX_init(dst_ctx);
+ if (!EVP_MD_CTX_copy_ex(&dst_ctx->i_ctx, &src_ctx->i_ctx)) {
+ goto err;
+ }
+ if (!EVP_MD_CTX_copy_ex(&dst_ctx->o_ctx, &src_ctx->o_ctx)) {
+ goto err;
+ }
+ if (!EVP_MD_CTX_copy_ex(&dst_ctx->md_ctx, &src_ctx->md_ctx)) {
+ goto err;
+ }
+ memcpy(dst_ctx->key, src_ctx->key, HMAC_MAX_MD_CBLOCK);
+ dst_ctx->key_length = src_ctx->key_length;
+ dst_ctx->md = src_ctx->md;
+ return 1;
+
+ err:
+ return 0;
+#endif
+}
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/nid.py b/src/cryptography/hazmat/bindings/openssl/nid.py
new file mode 100644
index 00000000..b2e61492
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/nid.py
@@ -0,0 +1,241 @@
+# 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
+
+INCLUDES = """
+#include <openssl/obj_mac.h>
+"""
+
+TYPES = """
+static const int Cryptography_HAS_ECDSA_SHA2_NIDS;
+
+static const int NID_undef;
+static const int NID_dsa;
+static const int NID_dsaWithSHA;
+static const int NID_dsaWithSHA1;
+static const int NID_md2;
+static const int NID_md4;
+static const int NID_md5;
+static const int NID_mdc2;
+static const int NID_ripemd160;
+static const int NID_sha;
+static const int NID_sha1;
+static const int NID_sha256;
+static const int NID_sha384;
+static const int NID_sha512;
+static const int NID_sha224;
+static const int NID_sha;
+static const int NID_ecdsa_with_SHA1;
+static const int NID_ecdsa_with_SHA224;
+static const int NID_ecdsa_with_SHA256;
+static const int NID_ecdsa_with_SHA384;
+static const int NID_ecdsa_with_SHA512;
+static const int NID_pbe_WithSHA1And3_Key_TripleDES_CBC;
+static const int NID_X9_62_c2pnb163v1;
+static const int NID_X9_62_c2pnb163v2;
+static const int NID_X9_62_c2pnb163v3;
+static const int NID_X9_62_c2pnb176v1;
+static const int NID_X9_62_c2tnb191v1;
+static const int NID_X9_62_c2tnb191v2;
+static const int NID_X9_62_c2tnb191v3;
+static const int NID_X9_62_c2onb191v4;
+static const int NID_X9_62_c2onb191v5;
+static const int NID_X9_62_c2pnb208w1;
+static const int NID_X9_62_c2tnb239v1;
+static const int NID_X9_62_c2tnb239v2;
+static const int NID_X9_62_c2tnb239v3;
+static const int NID_X9_62_c2onb239v4;
+static const int NID_X9_62_c2onb239v5;
+static const int NID_X9_62_c2pnb272w1;
+static const int NID_X9_62_c2pnb304w1;
+static const int NID_X9_62_c2tnb359v1;
+static const int NID_X9_62_c2pnb368w1;
+static const int NID_X9_62_c2tnb431r1;
+static const int NID_X9_62_prime192v1;
+static const int NID_X9_62_prime192v2;
+static const int NID_X9_62_prime192v3;
+static const int NID_X9_62_prime239v1;
+static const int NID_X9_62_prime239v2;
+static const int NID_X9_62_prime239v3;
+static const int NID_X9_62_prime256v1;
+static const int NID_secp112r1;
+static const int NID_secp112r2;
+static const int NID_secp128r1;
+static const int NID_secp128r2;
+static const int NID_secp160k1;
+static const int NID_secp160r1;
+static const int NID_secp160r2;
+static const int NID_sect163k1;
+static const int NID_sect163r1;
+static const int NID_sect163r2;
+static const int NID_secp192k1;
+static const int NID_secp224k1;
+static const int NID_secp224r1;
+static const int NID_secp256k1;
+static const int NID_secp384r1;
+static const int NID_secp521r1;
+static const int NID_sect113r1;
+static const int NID_sect113r2;
+static const int NID_sect131r1;
+static const int NID_sect131r2;
+static const int NID_sect193r1;
+static const int NID_sect193r2;
+static const int NID_sect233k1;
+static const int NID_sect233r1;
+static const int NID_sect239k1;
+static const int NID_sect283k1;
+static const int NID_sect283r1;
+static const int NID_sect409k1;
+static const int NID_sect409r1;
+static const int NID_sect571k1;
+static const int NID_sect571r1;
+static const int NID_wap_wsg_idm_ecid_wtls1;
+static const int NID_wap_wsg_idm_ecid_wtls3;
+static const int NID_wap_wsg_idm_ecid_wtls4;
+static const int NID_wap_wsg_idm_ecid_wtls5;
+static const int NID_wap_wsg_idm_ecid_wtls6;
+static const int NID_wap_wsg_idm_ecid_wtls7;
+static const int NID_wap_wsg_idm_ecid_wtls8;
+static const int NID_wap_wsg_idm_ecid_wtls9;
+static const int NID_wap_wsg_idm_ecid_wtls10;
+static const int NID_wap_wsg_idm_ecid_wtls11;
+static const int NID_wap_wsg_idm_ecid_wtls12;
+static const int NID_ipsec3;
+static const int NID_ipsec4;
+static const char *const SN_X9_62_c2pnb163v1;
+static const char *const SN_X9_62_c2pnb163v2;
+static const char *const SN_X9_62_c2pnb163v3;
+static const char *const SN_X9_62_c2pnb176v1;
+static const char *const SN_X9_62_c2tnb191v1;
+static const char *const SN_X9_62_c2tnb191v2;
+static const char *const SN_X9_62_c2tnb191v3;
+static const char *const SN_X9_62_c2onb191v4;
+static const char *const SN_X9_62_c2onb191v5;
+static const char *const SN_X9_62_c2pnb208w1;
+static const char *const SN_X9_62_c2tnb239v1;
+static const char *const SN_X9_62_c2tnb239v2;
+static const char *const SN_X9_62_c2tnb239v3;
+static const char *const SN_X9_62_c2onb239v4;
+static const char *const SN_X9_62_c2onb239v5;
+static const char *const SN_X9_62_c2pnb272w1;
+static const char *const SN_X9_62_c2pnb304w1;
+static const char *const SN_X9_62_c2tnb359v1;
+static const char *const SN_X9_62_c2pnb368w1;
+static const char *const SN_X9_62_c2tnb431r1;
+static const char *const SN_X9_62_prime192v1;
+static const char *const SN_X9_62_prime192v2;
+static const char *const SN_X9_62_prime192v3;
+static const char *const SN_X9_62_prime239v1;
+static const char *const SN_X9_62_prime239v2;
+static const char *const SN_X9_62_prime239v3;
+static const char *const SN_X9_62_prime256v1;
+static const char *const SN_secp112r1;
+static const char *const SN_secp112r2;
+static const char *const SN_secp128r1;
+static const char *const SN_secp128r2;
+static const char *const SN_secp160k1;
+static const char *const SN_secp160r1;
+static const char *const SN_secp160r2;
+static const char *const SN_sect163k1;
+static const char *const SN_sect163r1;
+static const char *const SN_sect163r2;
+static const char *const SN_secp192k1;
+static const char *const SN_secp224k1;
+static const char *const SN_secp224r1;
+static const char *const SN_secp256k1;
+static const char *const SN_secp384r1;
+static const char *const SN_secp521r1;
+static const char *const SN_sect113r1;
+static const char *const SN_sect113r2;
+static const char *const SN_sect131r1;
+static const char *const SN_sect131r2;
+static const char *const SN_sect193r1;
+static const char *const SN_sect193r2;
+static const char *const SN_sect233k1;
+static const char *const SN_sect233r1;
+static const char *const SN_sect239k1;
+static const char *const SN_sect283k1;
+static const char *const SN_sect283r1;
+static const char *const SN_sect409k1;
+static const char *const SN_sect409r1;
+static const char *const SN_sect571k1;
+static const char *const SN_sect571r1;
+static const char *const SN_wap_wsg_idm_ecid_wtls1;
+static const char *const SN_wap_wsg_idm_ecid_wtls3;
+static const char *const SN_wap_wsg_idm_ecid_wtls4;
+static const char *const SN_wap_wsg_idm_ecid_wtls5;
+static const char *const SN_wap_wsg_idm_ecid_wtls6;
+static const char *const SN_wap_wsg_idm_ecid_wtls7;
+static const char *const SN_wap_wsg_idm_ecid_wtls8;
+static const char *const SN_wap_wsg_idm_ecid_wtls9;
+static const char *const SN_wap_wsg_idm_ecid_wtls10;
+static const char *const SN_wap_wsg_idm_ecid_wtls11;
+static const char *const SN_wap_wsg_idm_ecid_wtls12;
+static const char *const SN_ipsec3;
+static const char *const SN_ipsec4;
+
+static const int NID_subject_key_identifier;
+static const int NID_authority_key_identifier;
+static const int NID_policy_constraints;
+static const int NID_ext_key_usage;
+static const int NID_info_access;
+static const int NID_key_usage;
+static const int NID_subject_alt_name;
+static const int NID_issuer_alt_name;
+static const int NID_basic_constraints;
+static const int NID_issuing_distribution_point;
+static const int NID_certificate_issuer;
+static const int NID_name_constraints;
+static const int NID_crl_distribution_points;
+static const int NID_certificate_policies;
+static const int NID_inhibit_any_policy;
+
+static const int NID_private_key_usage_period;
+static const int NID_crl_number;
+static const int NID_crl_reason;
+static const int NID_invalidity_date;
+static const int NID_delta_crl;
+static const int NID_any_policy;
+static const int NID_policy_mappings;
+static const int NID_target_information;
+static const int NID_no_rev_avail;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+/* OpenSSL 0.9.8g+ */
+#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
+static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 1;
+#else
+static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 0;
+static const int NID_ecdsa_with_SHA224 = 0;
+static const int NID_ecdsa_with_SHA256 = 0;
+static const int NID_ecdsa_with_SHA384 = 0;
+static const int NID_ecdsa_with_SHA512 = 0;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_ECDSA_SHA2_NIDS": [
+ "NID_ecdsa_with_SHA224",
+ "NID_ecdsa_with_SHA256",
+ "NID_ecdsa_with_SHA384",
+ "NID_ecdsa_with_SHA512",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/objects.py b/src/cryptography/hazmat/bindings/openssl/objects.py
new file mode 100644
index 00000000..557c0158
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/objects.py
@@ -0,0 +1,45 @@
+# 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
+
+INCLUDES = """
+#include <openssl/objects.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+ASN1_OBJECT *OBJ_nid2obj(int);
+const char *OBJ_nid2ln(int);
+const char *OBJ_nid2sn(int);
+int OBJ_obj2nid(const ASN1_OBJECT *);
+int OBJ_ln2nid(const char *);
+int OBJ_sn2nid(const char *);
+int OBJ_txt2nid(const char *);
+ASN1_OBJECT *OBJ_txt2obj(const char *, int);
+int OBJ_obj2txt(char *, int, const ASN1_OBJECT *, int);
+int OBJ_cmp(const ASN1_OBJECT *, const ASN1_OBJECT *);
+ASN1_OBJECT *OBJ_dup(const ASN1_OBJECT *);
+int OBJ_create(const char *, const char *, const char *);
+void OBJ_cleanup(void);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/opensslv.py b/src/cryptography/hazmat/bindings/openssl/opensslv.py
new file mode 100644
index 00000000..ef6e057b
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/opensslv.py
@@ -0,0 +1,36 @@
+# 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
+
+INCLUDES = """
+#include <openssl/opensslv.h>
+"""
+
+TYPES = """
+/* Note that these will be resolved when cryptography is compiled and are NOT
+ guaranteed to be the version that it actually loads. */
+static const int OPENSSL_VERSION_NUMBER;
+static const char *const OPENSSL_VERSION_TEXT;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/osrandom_engine.py b/src/cryptography/hazmat/bindings/openssl/osrandom_engine.py
new file mode 100644
index 00000000..462997cc
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/osrandom_engine.py
@@ -0,0 +1,218 @@
+# 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
+
+INCLUDES = """
+#ifdef _WIN32
+#include <Wincrypt.h>
+#else
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+"""
+
+TYPES = """
+static const char *const Cryptography_osrandom_engine_name;
+static const char *const Cryptography_osrandom_engine_id;
+"""
+
+FUNCTIONS = """
+int Cryptography_add_osrandom_engine(void);
+"""
+
+MACROS = """
+"""
+
+WIN32_CUSTOMIZATIONS = """
+static HCRYPTPROV hCryptProv = 0;
+
+static int osrandom_init(ENGINE *e) {
+ if (hCryptProv > 0) {
+ return 1;
+ }
+ if (CryptAcquireContext(&hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ if (hCryptProv == 0) {
+ return 0;
+ }
+
+ if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
+ ERR_put_error(
+ ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom_engine.py", 0
+ );
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ if (CryptReleaseContext(hCryptProv, 0)) {
+ hCryptProv = 0;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ if (hCryptProv == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+"""
+
+POSIX_CUSTOMIZATIONS = """
+static int urandom_fd = -1;
+
+static int osrandom_finish(ENGINE *e);
+
+static int osrandom_init(ENGINE *e) {
+ if (urandom_fd > -1) {
+ return 1;
+ }
+ urandom_fd = open("/dev/urandom", O_RDONLY);
+ if (urandom_fd > -1) {
+ int flags = fcntl(urandom_fd, F_GETFD);
+ if (flags == -1) {
+ osrandom_finish(e);
+ return 0;
+ } else if (fcntl(urandom_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ osrandom_finish(e);
+ return 0;
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ ssize_t n;
+ while (size > 0) {
+ do {
+ n = read(urandom_fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+ if (n <= 0) {
+ ERR_put_error(
+ ERR_LIB_RAND, 0, ERR_R_RAND_LIB, "osrandom_engine.py", 0
+ );
+ return 0;
+ }
+ buffer += n;
+ size -= n;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ int n;
+ do {
+ n = close(urandom_fd);
+ } while (n < 0 && errno == EINTR);
+ urandom_fd = -1;
+ if (n < 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ if (urandom_fd == -1) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+"""
+
+CUSTOMIZATIONS = """
+static const char *Cryptography_osrandom_engine_id = "osrandom";
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine";
+
+#if defined(_WIN32)
+%(WIN32_CUSTOMIZATIONS)s
+#else
+%(POSIX_CUSTOMIZATIONS)s
+#endif
+
+/* This replicates the behavior of the OpenSSL FIPS RNG, which returns a
+ -1 in the event that there is an error when calling RAND_pseudo_bytes. */
+static int osrandom_pseudo_rand_bytes(unsigned char *buffer, int size) {
+ int res = osrandom_rand_bytes(buffer, size);
+ if (res == 0) {
+ return -1;
+ } else {
+ return res;
+ }
+}
+
+static RAND_METHOD osrandom_rand = {
+ NULL,
+ osrandom_rand_bytes,
+ NULL,
+ NULL,
+ osrandom_pseudo_rand_bytes,
+ osrandom_rand_status,
+};
+
+/* Returns 1 if successfully added, 2 if engine has previously been added,
+ and 0 for error. */
+int Cryptography_add_osrandom_engine(void) {
+ ENGINE *e;
+ e = ENGINE_by_id(Cryptography_osrandom_engine_id);
+ if (e != NULL) {
+ ENGINE_free(e);
+ return 2;
+ } else {
+ ERR_clear_error();
+ }
+
+ e = ENGINE_new();
+ if (e == NULL) {
+ return 0;
+ }
+ if(!ENGINE_set_id(e, Cryptography_osrandom_engine_id) ||
+ !ENGINE_set_name(e, Cryptography_osrandom_engine_name) ||
+ !ENGINE_set_RAND(e, &osrandom_rand) ||
+ !ENGINE_set_init_function(e, osrandom_init) ||
+ !ENGINE_set_finish_function(e, osrandom_finish)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_add(e)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_free(e)) {
+ return 0;
+ }
+
+ return 1;
+}
+""" % {
+ "WIN32_CUSTOMIZATIONS": WIN32_CUSTOMIZATIONS,
+ "POSIX_CUSTOMIZATIONS": POSIX_CUSTOMIZATIONS,
+}
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/pem.py b/src/cryptography/hazmat/bindings/openssl/pem.py
new file mode 100644
index 00000000..752f1987
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/pem.py
@@ -0,0 +1,89 @@
+# 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
+
+INCLUDES = """
+#include <openssl/pem.h>
+"""
+
+TYPES = """
+typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
+"""
+
+FUNCTIONS = """
+X509 *PEM_read_bio_X509(BIO *, X509 **, pem_password_cb *, void *);
+int PEM_write_bio_X509(BIO *, X509 *);
+
+int PEM_write_bio_PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+ unsigned char *, int, pem_password_cb *, void *);
+
+EVP_PKEY *PEM_read_bio_PrivateKey(BIO *, EVP_PKEY **, pem_password_cb *,
+ void *);
+
+int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+ char *, int, pem_password_cb *, void *);
+int PEM_write_bio_PKCS8PrivateKey_nid(BIO *, EVP_PKEY *, int, char *, int,
+ pem_password_cb *, void *);
+
+int i2d_PKCS8PrivateKey_bio(BIO *, EVP_PKEY *, const EVP_CIPHER *,
+ char *, int, pem_password_cb *, void *);
+int i2d_PKCS8PrivateKey_nid_bio(BIO *, EVP_PKEY *, int,
+ char *, int, pem_password_cb *, void *);
+
+PKCS7 *d2i_PKCS7_bio(BIO *, PKCS7 **);
+EVP_PKEY *d2i_PKCS8PrivateKey_bio(BIO *, EVP_PKEY **, pem_password_cb *,
+ void *);
+
+int PEM_write_bio_X509_REQ(BIO *, X509_REQ *);
+
+X509_REQ *PEM_read_bio_X509_REQ(BIO *, X509_REQ **, pem_password_cb *, void *);
+
+X509_CRL *PEM_read_bio_X509_CRL(BIO *, X509_CRL **, pem_password_cb *, void *);
+
+int PEM_write_bio_X509_CRL(BIO *, X509_CRL *);
+
+PKCS7 *PEM_read_bio_PKCS7(BIO *, PKCS7 **, pem_password_cb *, void *);
+DH *PEM_read_bio_DHparams(BIO *, DH **, pem_password_cb *, void *);
+
+DSA *PEM_read_bio_DSAPrivateKey(BIO *, DSA **, pem_password_cb *, void *);
+
+RSA *PEM_read_bio_RSAPrivateKey(BIO *, RSA **, pem_password_cb *, void *);
+
+int PEM_write_bio_DSAPrivateKey(BIO *, DSA *, const EVP_CIPHER *,
+ unsigned char *, int,
+ pem_password_cb *, void *);
+
+int PEM_write_bio_RSAPrivateKey(BIO *, RSA *, const EVP_CIPHER *,
+ unsigned char *, int,
+ pem_password_cb *, void *);
+
+DSA *PEM_read_bio_DSA_PUBKEY(BIO *, DSA **, pem_password_cb *, void *);
+
+RSA *PEM_read_bio_RSAPublicKey(BIO *, RSA **, pem_password_cb *, void *);
+
+int PEM_write_bio_DSA_PUBKEY(BIO *, DSA *);
+
+int PEM_write_bio_RSAPublicKey(BIO *, const RSA *);
+
+EVP_PKEY *PEM_read_bio_PUBKEY(BIO *, EVP_PKEY **, pem_password_cb *, void *);
+int PEM_write_bio_PUBKEY(BIO *, EVP_PKEY *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/pkcs12.py b/src/cryptography/hazmat/bindings/openssl/pkcs12.py
new file mode 100644
index 00000000..a8f106f6
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/pkcs12.py
@@ -0,0 +1,41 @@
+# 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
+
+INCLUDES = """
+#include <openssl/pkcs12.h>
+"""
+
+TYPES = """
+typedef ... PKCS12;
+"""
+
+FUNCTIONS = """
+void PKCS12_free(PKCS12 *);
+
+PKCS12 *d2i_PKCS12_bio(BIO *, PKCS12 **);
+int i2d_PKCS12_bio(BIO *, PKCS12 *);
+"""
+
+MACROS = """
+int PKCS12_parse(PKCS12 *, const char *, EVP_PKEY **, X509 **,
+ Cryptography_STACK_OF_X509 **);
+PKCS12 *PKCS12_create(char *, char *, EVP_PKEY *, X509 *,
+ Cryptography_STACK_OF_X509 *, int, int, int, int, int);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/pkcs7.py b/src/cryptography/hazmat/bindings/openssl/pkcs7.py
new file mode 100644
index 00000000..1343e566
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/pkcs7.py
@@ -0,0 +1,41 @@
+# 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
+
+INCLUDES = """
+#include <openssl/pkcs7.h>
+"""
+
+TYPES = """
+typedef struct {
+ ASN1_OBJECT *type;
+ ...;
+} PKCS7;
+"""
+
+FUNCTIONS = """
+void PKCS7_free(PKCS7 *);
+"""
+
+MACROS = """
+int PKCS7_type_is_signed(PKCS7 *);
+int PKCS7_type_is_enveloped(PKCS7 *);
+int PKCS7_type_is_signedAndEnveloped(PKCS7 *);
+int PKCS7_type_is_data(PKCS7 *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/rand.py b/src/cryptography/hazmat/bindings/openssl/rand.py
new file mode 100644
index 00000000..7b1be9df
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/rand.py
@@ -0,0 +1,45 @@
+# 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
+
+INCLUDES = """
+#include <openssl/rand.h>
+"""
+
+TYPES = """
+"""
+
+FUNCTIONS = """
+void ERR_load_RAND_strings(void);
+void RAND_seed(const void *, int);
+void RAND_add(const void *, int, double);
+int RAND_status(void);
+int RAND_egd(const char *);
+int RAND_egd_bytes(const char *, int);
+int RAND_query_egd_bytes(const char *, unsigned char *, int);
+const char *RAND_file_name(char *, size_t);
+int RAND_load_file(const char *, long);
+int RAND_write_file(const char *);
+void RAND_cleanup(void);
+int RAND_bytes(unsigned char *, int);
+int RAND_pseudo_bytes(unsigned char *, int);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/rsa.py b/src/cryptography/hazmat/bindings/openssl/rsa.py
new file mode 100644
index 00000000..cb8e701e
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/rsa.py
@@ -0,0 +1,108 @@
+# 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
+
+INCLUDES = """
+#include <openssl/rsa.h>
+"""
+
+TYPES = """
+typedef struct rsa_st {
+ BIGNUM *n;
+ BIGNUM *e;
+ BIGNUM *d;
+ BIGNUM *p;
+ BIGNUM *q;
+ BIGNUM *dmp1;
+ BIGNUM *dmq1;
+ BIGNUM *iqmp;
+ ...;
+} RSA;
+typedef ... BN_GENCB;
+static const int RSA_PKCS1_PADDING;
+static const int RSA_SSLV23_PADDING;
+static const int RSA_NO_PADDING;
+static const int RSA_PKCS1_OAEP_PADDING;
+static const int RSA_X931_PADDING;
+static const int RSA_PKCS1_PSS_PADDING;
+static const int RSA_F4;
+
+static const int Cryptography_HAS_PSS_PADDING;
+static const int Cryptography_HAS_MGF1_MD;
+"""
+
+FUNCTIONS = """
+RSA *RSA_new(void);
+void RSA_free(RSA *);
+int RSA_size(const RSA *);
+int RSA_generate_key_ex(RSA *, int, BIGNUM *, BN_GENCB *);
+int RSA_check_key(const RSA *);
+RSA *RSAPublicKey_dup(RSA *);
+int RSA_blinding_on(RSA *, BN_CTX *);
+void RSA_blinding_off(RSA *);
+int RSA_public_encrypt(int, const unsigned char *, unsigned char *,
+ RSA *, int);
+int RSA_private_encrypt(int, const unsigned char *, unsigned char *,
+ RSA *, int);
+int RSA_public_decrypt(int, const unsigned char *, unsigned char *,
+ RSA *, int);
+int RSA_private_decrypt(int, const unsigned char *, unsigned char *,
+ RSA *, int);
+int RSA_print(BIO *, const RSA *, int);
+int RSA_verify_PKCS1_PSS(RSA *, const unsigned char *, const EVP_MD *,
+ const unsigned char *, int);
+int RSA_padding_add_PKCS1_PSS(RSA *, unsigned char *, const unsigned char *,
+ const EVP_MD *, int);
+int RSA_padding_add_PKCS1_OAEP(unsigned char *, int, const unsigned char *,
+ int, const unsigned char *, int);
+int RSA_padding_check_PKCS1_OAEP(unsigned char *, int, const unsigned char *,
+ int, int, const unsigned char *, int);
+"""
+
+MACROS = """
+int EVP_PKEY_CTX_set_rsa_padding(EVP_PKEY_CTX *, int);
+int EVP_PKEY_CTX_set_rsa_pss_saltlen(EVP_PKEY_CTX *, int);
+int EVP_PKEY_CTX_set_rsa_mgf1_md(EVP_PKEY_CTX *, EVP_MD *);
+"""
+
+CUSTOMIZATIONS = """
+#if OPENSSL_VERSION_NUMBER >= 0x10000000
+static const long Cryptography_HAS_PSS_PADDING = 1;
+#else
+/* see evp.py for the definition of Cryptography_HAS_PKEY_CTX */
+static const long Cryptography_HAS_PSS_PADDING = 0;
+int (*EVP_PKEY_CTX_set_rsa_padding)(EVP_PKEY_CTX *, int) = NULL;
+int (*EVP_PKEY_CTX_set_rsa_pss_saltlen)(EVP_PKEY_CTX *, int) = NULL;
+static const long RSA_PKCS1_PSS_PADDING = 0;
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x1000100f
+static const long Cryptography_HAS_MGF1_MD = 1;
+#else
+static const long Cryptography_HAS_MGF1_MD = 0;
+int (*EVP_PKEY_CTX_set_rsa_mgf1_md)(EVP_PKEY_CTX *, EVP_MD *) = NULL;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_PKEY_CTX": [
+ "EVP_PKEY_CTX_set_rsa_padding",
+ "EVP_PKEY_CTX_set_rsa_pss_saltlen",
+ ],
+ "Cryptography_HAS_PSS_PADDING": [
+ "RSA_PKCS1_PSS_PADDING",
+ ],
+ "Cryptography_HAS_MGF1_MD": [
+ "EVP_PKEY_CTX_set_rsa_mgf1_md",
+ ],
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/ssl.py b/src/cryptography/hazmat/bindings/openssl/ssl.py
new file mode 100644
index 00000000..7d805e78
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/ssl.py
@@ -0,0 +1,620 @@
+# 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
+
+INCLUDES = """
+#include <openssl/ssl.h>
+
+typedef STACK_OF(SSL_CIPHER) Cryptography_STACK_OF_SSL_CIPHER;
+"""
+
+TYPES = """
+/*
+ * Internally invented symbols to tell which versions of SSL/TLS are supported.
+*/
+static const long Cryptography_HAS_SSL2;
+static const long Cryptography_HAS_TLSv1_1;
+static const long Cryptography_HAS_TLSv1_2;
+static const long Cryptography_HAS_SECURE_RENEGOTIATION;
+
+/* Internally invented symbol to tell us if SNI is supported */
+static const long Cryptography_HAS_TLSEXT_HOSTNAME;
+
+/* Internally invented symbol to tell us if SSL_MODE_RELEASE_BUFFERS is
+ * supported
+ */
+static const long Cryptography_HAS_RELEASE_BUFFERS;
+
+/* Internally invented symbol to tell us if SSL_OP_NO_COMPRESSION is
+ * supported
+ */
+static const long Cryptography_HAS_OP_NO_COMPRESSION;
+
+static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING;
+static const long Cryptography_HAS_SSL_SET_SSL_CTX;
+static const long Cryptography_HAS_SSL_OP_NO_TICKET;
+static const long Cryptography_HAS_NETBSD_D1_METH;
+static const long Cryptography_HAS_NEXTPROTONEG;
+static const long Cryptography_HAS_ALPN;
+
+static const long SSL_FILETYPE_PEM;
+static const long SSL_FILETYPE_ASN1;
+static const long SSL_ERROR_NONE;
+static const long SSL_ERROR_ZERO_RETURN;
+static const long SSL_ERROR_WANT_READ;
+static const long SSL_ERROR_WANT_WRITE;
+static const long SSL_ERROR_WANT_X509_LOOKUP;
+static const long SSL_ERROR_SYSCALL;
+static const long SSL_ERROR_SSL;
+static const long SSL_SENT_SHUTDOWN;
+static const long SSL_RECEIVED_SHUTDOWN;
+static const long SSL_OP_NO_SSLv2;
+static const long SSL_OP_NO_SSLv3;
+static const long SSL_OP_NO_TLSv1;
+static const long SSL_OP_NO_TLSv1_1;
+static const long SSL_OP_NO_TLSv1_2;
+static const long SSL_OP_NO_COMPRESSION;
+static const long SSL_OP_SINGLE_DH_USE;
+static const long SSL_OP_EPHEMERAL_RSA;
+static const long SSL_OP_MICROSOFT_SESS_ID_BUG;
+static const long SSL_OP_NETSCAPE_CHALLENGE_BUG;
+static const long SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+static const long SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
+static const long SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
+static const long SSL_OP_MSIE_SSLV2_RSA_PADDING;
+static const long SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
+static const long SSL_OP_TLS_D5_BUG;
+static const long SSL_OP_TLS_BLOCK_PADDING_BUG;
+static const long SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+static const long SSL_OP_CIPHER_SERVER_PREFERENCE;
+static const long SSL_OP_TLS_ROLLBACK_BUG;
+static const long SSL_OP_PKCS1_CHECK_1;
+static const long SSL_OP_PKCS1_CHECK_2;
+static const long SSL_OP_NETSCAPE_CA_DN_BUG;
+static const long SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG;
+static const long SSL_OP_NO_QUERY_MTU;
+static const long SSL_OP_COOKIE_EXCHANGE;
+static const long SSL_OP_NO_TICKET;
+static const long SSL_OP_ALL;
+static const long SSL_OP_SINGLE_ECDH_USE;
+static const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+static const long SSL_OP_LEGACY_SERVER_CONNECT;
+static const long SSL_VERIFY_PEER;
+static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+static const long SSL_VERIFY_CLIENT_ONCE;
+static const long SSL_VERIFY_NONE;
+static const long SSL_SESS_CACHE_OFF;
+static const long SSL_SESS_CACHE_CLIENT;
+static const long SSL_SESS_CACHE_SERVER;
+static const long SSL_SESS_CACHE_BOTH;
+static const long SSL_SESS_CACHE_NO_AUTO_CLEAR;
+static const long SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
+static const long SSL_SESS_CACHE_NO_INTERNAL_STORE;
+static const long SSL_SESS_CACHE_NO_INTERNAL;
+static const long SSL_ST_CONNECT;
+static const long SSL_ST_ACCEPT;
+static const long SSL_ST_MASK;
+static const long SSL_ST_INIT;
+static const long SSL_ST_BEFORE;
+static const long SSL_ST_OK;
+static const long SSL_ST_RENEGOTIATE;
+static const long SSL_CB_LOOP;
+static const long SSL_CB_EXIT;
+static const long SSL_CB_READ;
+static const long SSL_CB_WRITE;
+static const long SSL_CB_ALERT;
+static const long SSL_CB_READ_ALERT;
+static const long SSL_CB_WRITE_ALERT;
+static const long SSL_CB_ACCEPT_LOOP;
+static const long SSL_CB_ACCEPT_EXIT;
+static const long SSL_CB_CONNECT_LOOP;
+static const long SSL_CB_CONNECT_EXIT;
+static const long SSL_CB_HANDSHAKE_START;
+static const long SSL_CB_HANDSHAKE_DONE;
+static const long SSL_MODE_RELEASE_BUFFERS;
+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 struct {
+ int master_key_length;
+ unsigned char master_key[...];
+ ...;
+} SSL_SESSION;
+
+typedef struct {
+ unsigned char server_random[...];
+ unsigned char client_random[...];
+ ...;
+} SSL3_STATE;
+
+typedef struct {
+ SSL3_STATE *s3;
+ SSL_SESSION *session;
+ int type;
+ ...;
+} SSL;
+
+static const long TLSEXT_NAMETYPE_host_name;
+
+typedef ... SSL_CIPHER;
+typedef ... Cryptography_STACK_OF_SSL_CIPHER;
+typedef ... COMP_METHOD;
+"""
+
+FUNCTIONS = """
+void SSL_load_error_strings(void);
+int SSL_library_init(void);
+
+/* SSL */
+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_depth(SSL *, int);
+int SSL_get_verify_depth(const SSL *);
+int (*SSL_get_verify_callback(const SSL *))(int, X509_STORE_CTX *);
+void SSL_set_info_callback(SSL *ssl, void (*)(const SSL *, int, int));
+void (*SSL_get_info_callback(const SSL *))(const SSL *, int, int);
+SSL *SSL_new(SSL_CTX *);
+void SSL_free(SSL *);
+int SSL_set_fd(SSL *, int);
+void SSL_set_bio(SSL *, BIO *, BIO *);
+void SSL_set_connect_state(SSL *);
+void SSL_set_accept_state(SSL *);
+void SSL_set_shutdown(SSL *, int);
+int SSL_get_shutdown(const SSL *);
+int SSL_pending(const SSL *);
+int SSL_write(SSL *, const void *, int);
+int SSL_read(SSL *, void *, int);
+X509 *SSL_get_peer_certificate(const SSL *);
+int SSL_get_ex_data_X509_STORE_CTX_idx(void);
+
+Cryptography_STACK_OF_X509 *SSL_get_peer_cert_chain(const SSL *);
+Cryptography_STACK_OF_X509_NAME *SSL_get_client_CA_list(const SSL *);
+
+int SSL_get_error(const SSL *, int);
+int SSL_do_handshake(SSL *);
+int SSL_shutdown(SSL *);
+const char *SSL_get_cipher_list(const SSL *, int);
+Cryptography_STACK_OF_SSL_CIPHER *SSL_get_ciphers(const SSL *);
+
+const COMP_METHOD *SSL_get_current_compression(SSL *);
+const COMP_METHOD *SSL_get_current_expansion(SSL *);
+const char *SSL_COMP_get_name(const COMP_METHOD *);
+
+/* context */
+void SSL_CTX_free(SSL_CTX *);
+long SSL_CTX_set_timeout(SSL_CTX *, long);
+int SSL_CTX_set_default_verify_paths(SSL_CTX *);
+void SSL_CTX_set_verify(SSL_CTX *, int, int (*)(int, X509_STORE_CTX *));
+void SSL_CTX_set_verify_depth(SSL_CTX *, int);
+int (*SSL_CTX_get_verify_callback(const SSL_CTX *))(int, X509_STORE_CTX *);
+int SSL_CTX_get_verify_mode(const SSL_CTX *);
+int SSL_CTX_get_verify_depth(const SSL_CTX *);
+int SSL_CTX_set_cipher_list(SSL_CTX *, const char *);
+int SSL_CTX_load_verify_locations(SSL_CTX *, const char *, const char *);
+void SSL_CTX_set_default_passwd_cb(SSL_CTX *, pem_password_cb *);
+void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *, void *);
+int SSL_CTX_use_certificate(SSL_CTX *, X509 *);
+int SSL_CTX_use_certificate_file(SSL_CTX *, const char *, int);
+int SSL_CTX_use_certificate_chain_file(SSL_CTX *, const char *);
+int SSL_CTX_use_PrivateKey(SSL_CTX *, EVP_PKEY *);
+int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
+void SSL_CTX_set_cert_store(SSL_CTX *, X509_STORE *);
+X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *);
+int SSL_CTX_add_client_CA(SSL_CTX *, X509 *);
+
+void SSL_CTX_set_client_CA_list(SSL_CTX *, Cryptography_STACK_OF_X509_NAME *);
+
+/* SSL_SESSION */
+void SSL_SESSION_free(SSL_SESSION *);
+
+/* Information about actually used cipher */
+const char *SSL_CIPHER_get_name(const SSL_CIPHER *);
+int SSL_CIPHER_get_bits(const SSL_CIPHER *, int *);
+char *SSL_CIPHER_get_version(const SSL_CIPHER *);
+
+size_t SSL_get_finished(const SSL *, void *, size_t);
+size_t SSL_get_peer_finished(const SSL *, void *, size_t);
+"""
+
+MACROS = """
+unsigned long SSL_set_mode(SSL *, unsigned long);
+unsigned long SSL_get_mode(SSL *);
+
+unsigned long SSL_set_options(SSL *, unsigned long);
+unsigned long SSL_get_options(SSL *);
+
+int SSL_want_read(const SSL *);
+int SSL_want_write(const SSL *);
+
+long SSL_total_renegotiations(SSL *);
+long SSL_get_secure_renegotiation_support(SSL *);
+
+/* Defined as unsigned long because SSL_OP_ALL is greater than signed 32-bit
+ and Windows defines long as 32-bit. */
+unsigned long SSL_CTX_set_options(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_options(SSL_CTX *);
+unsigned long SSL_CTX_set_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_session_cache_mode(SSL_CTX *, unsigned long);
+unsigned long SSL_CTX_get_session_cache_mode(SSL_CTX *);
+unsigned long SSL_CTX_set_tmp_dh(SSL_CTX *, DH *);
+unsigned long SSL_CTX_set_tmp_ecdh(SSL_CTX *, EC_KEY *);
+unsigned long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
+
+/*- These aren't macros these functions are all const X on openssl > 1.0.x -*/
+
+/* methods */
+
+/* SSLv2 support is compiled out of some versions of OpenSSL. These will
+ * get special support when we generate the bindings so that if they are
+ * available they will be wrapped, but if they are not they won't cause
+ * problems (like link errors).
+ */
+const SSL_METHOD *SSLv2_method(void);
+const SSL_METHOD *SSLv2_server_method(void);
+const SSL_METHOD *SSLv2_client_method(void);
+
+/*
+ * TLSv1_1 and TLSv1_2 are recent additions. Only sufficiently new versions of
+ * OpenSSL support them.
+ */
+const SSL_METHOD *TLSv1_1_method(void);
+const SSL_METHOD *TLSv1_1_server_method(void);
+const SSL_METHOD *TLSv1_1_client_method(void);
+
+const SSL_METHOD *TLSv1_2_method(void);
+const SSL_METHOD *TLSv1_2_server_method(void);
+const SSL_METHOD *TLSv1_2_client_method(void);
+
+const SSL_METHOD *SSLv3_method(void);
+const SSL_METHOD *SSLv3_server_method(void);
+const SSL_METHOD *SSLv3_client_method(void);
+
+const SSL_METHOD *TLSv1_method(void);
+const SSL_METHOD *TLSv1_server_method(void);
+const SSL_METHOD *TLSv1_client_method(void);
+
+const SSL_METHOD *DTLSv1_method(void);
+const SSL_METHOD *DTLSv1_server_method(void);
+const SSL_METHOD *DTLSv1_client_method(void);
+
+const SSL_METHOD *SSLv23_method(void);
+const SSL_METHOD *SSLv23_server_method(void);
+const SSL_METHOD *SSLv23_client_method(void);
+
+/*- These aren't macros these arguments are all const X on openssl > 1.0.x -*/
+SSL_CTX *SSL_CTX_new(SSL_METHOD *);
+long SSL_CTX_get_timeout(const SSL_CTX *);
+
+const SSL_CIPHER *SSL_get_current_cipher(const SSL *);
+
+/* SNI APIs were introduced in OpenSSL 1.0.0. To continue to support
+ * earlier versions some special handling of these is necessary.
+ */
+const char *SSL_get_servername(const SSL *, const int);
+void SSL_set_tlsext_host_name(SSL *, char *);
+void SSL_CTX_set_tlsext_servername_callback(
+ SSL_CTX *,
+ int (*)(const SSL *, int *, void *));
+
+long SSL_session_reused(SSL *);
+
+/* The following were macros in 0.9.8e. Once we drop support for RHEL/CentOS 5
+ we should move these back to FUNCTIONS. */
+void SSL_CTX_set_info_callback(SSL_CTX *, void (*)(const SSL *, int, int));
+void (*SSL_CTX_get_info_callback(SSL_CTX *))(const SSL *, int, int);
+/* This function does not exist in 0.9.8e. Once we drop support for
+ RHEL/CentOS 5 this can be moved back to FUNCTIONS. */
+SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *);
+
+const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX*);
+
+/* NPN APIs were introduced in OpenSSL 1.0.1. To continue to support earlier
+ * versions some special handling of these is necessary.
+ */
+void SSL_CTX_set_next_protos_advertised_cb(SSL_CTX *,
+ int (*)(SSL *,
+ const unsigned char **,
+ unsigned int *,
+ void *),
+ void *);
+void SSL_CTX_set_next_proto_select_cb(SSL_CTX *,
+ int (*)(SSL *,
+ unsigned char **,
+ unsigned char *,
+ const unsigned char *,
+ unsigned int,
+ void *),
+ void *);
+int SSL_select_next_proto(unsigned char **, unsigned char *,
+ const unsigned char *, unsigned int,
+ const unsigned char *, unsigned int);
+void SSL_get0_next_proto_negotiated(const SSL *,
+ const unsigned char **, unsigned *);
+
+int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *);
+SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int);
+
+/* ALPN APIs were introduced in OpenSSL 1.0.2. To continue to support earlier
+ * versions some special handling of these is necessary.
+ */
+int SSL_CTX_set_alpn_protos(SSL_CTX *, const unsigned char*, unsigned);
+int SSL_set_alpn_protos(SSL *, const unsigned char*, unsigned);
+void SSL_CTX_set_alpn_select_cb(SSL_CTX *,
+ int (*) (SSL *,
+ const unsigned char **,
+ unsigned char *,
+ const unsigned char *,
+ unsigned int,
+ void *),
+ void *);
+void SSL_get0_alpn_selected(const SSL *, const unsigned char **, unsigned *);
+"""
+
+CUSTOMIZATIONS = """
+/** Secure renegotiation is supported in OpenSSL >= 0.9.8m
+ * But some Linux distributions have back ported some features.
+ */
+#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+static const long Cryptography_HAS_SECURE_RENEGOTIATION = 0;
+long (*SSL_get_secure_renegotiation_support)(SSL *) = NULL;
+const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0;
+const long SSL_OP_LEGACY_SERVER_CONNECT = 0;
+#else
+static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1;
+#endif
+#ifdef OPENSSL_NO_SSL2
+static const long Cryptography_HAS_SSL2 = 0;
+SSL_METHOD* (*SSLv2_method)(void) = NULL;
+SSL_METHOD* (*SSLv2_client_method)(void) = NULL;
+SSL_METHOD* (*SSLv2_server_method)(void) = NULL;
+#else
+static const long Cryptography_HAS_SSL2 = 1;
+#endif
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 1;
+#else
+static const long Cryptography_HAS_TLSEXT_HOSTNAME = 0;
+void (*SSL_set_tlsext_host_name)(SSL *, char *) = NULL;
+const char* (*SSL_get_servername)(const SSL *, const int) = NULL;
+void (*SSL_CTX_set_tlsext_servername_callback)(
+ SSL_CTX *,
+ int (*)(const SSL *, int *, void *)) = NULL;
+#endif
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+static const long Cryptography_HAS_RELEASE_BUFFERS = 1;
+#else
+static const long Cryptography_HAS_RELEASE_BUFFERS = 0;
+const long SSL_MODE_RELEASE_BUFFERS = 0;
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 1;
+#else
+static const long Cryptography_HAS_OP_NO_COMPRESSION = 0;
+const long SSL_OP_NO_COMPRESSION = 0;
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_1
+static const long Cryptography_HAS_TLSv1_1 = 1;
+#else
+static const long Cryptography_HAS_TLSv1_1 = 0;
+static const long SSL_OP_NO_TLSv1_1 = 0;
+SSL_METHOD* (*TLSv1_1_method)(void) = NULL;
+SSL_METHOD* (*TLSv1_1_client_method)(void) = NULL;
+SSL_METHOD* (*TLSv1_1_server_method)(void) = NULL;
+#endif
+
+#ifdef SSL_OP_NO_TLSv1_2
+static const long Cryptography_HAS_TLSv1_2 = 1;
+#else
+static const long Cryptography_HAS_TLSv1_2 = 0;
+static const long SSL_OP_NO_TLSv1_2 = 0;
+SSL_METHOD* (*TLSv1_2_method)(void) = NULL;
+SSL_METHOD* (*TLSv1_2_client_method)(void) = NULL;
+SSL_METHOD* (*TLSv1_2_server_method)(void) = NULL;
+#endif
+
+#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
+static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 1;
+#else
+static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
+const long SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
+#endif
+
+#ifdef OPENSSL_NO_EC
+long (*SSL_CTX_set_tmp_ecdh)(SSL_CTX *, EC_KEY *) = NULL;
+#endif
+
+#ifdef SSL_OP_NO_TICKET
+static const long Cryptography_HAS_SSL_OP_NO_TICKET = 1;
+#else
+static const long Cryptography_HAS_SSL_OP_NO_TICKET = 0;
+const long SSL_OP_NO_TICKET = 0;
+#endif
+
+/* OpenSSL 0.9.8f+ */
+#if OPENSSL_VERSION_NUMBER >= 0x00908070L
+static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1;
+#else
+static const long Cryptography_HAS_SSL_SET_SSL_CTX = 0;
+static const long TLSEXT_NAMETYPE_host_name = 0;
+SSL_CTX *(*SSL_set_SSL_CTX)(SSL *, SSL_CTX *) = NULL;
+#endif
+
+/* NetBSD shipped without including d1_meth.c. This workaround checks to see
+ if the version of NetBSD we're currently running on is old enough to
+ have the bug and provides an empty implementation so we can link and
+ then remove the function from the ffi object. */
+#ifdef __NetBSD__
+# include <sys/param.h>
+# if (__NetBSD_Version__ < 699003800)
+static const long Cryptography_HAS_NETBSD_D1_METH = 0;
+const SSL_METHOD *DTLSv1_method(void) {
+ return NULL;
+}
+# else
+static const long Cryptography_HAS_NETBSD_D1_METH = 1;
+# endif
+#else
+static const long Cryptography_HAS_NETBSD_D1_METH = 1;
+#endif
+
+/* Workaround for #794 caused by cffi const** bug. */
+const SSL_METHOD* Cryptography_SSL_CTX_get_method(const SSL_CTX* ctx) {
+ return ctx->method;
+}
+
+/* Because OPENSSL defines macros that claim lack of support for things, rather
+ * than macros that claim support for things, we need to do a version check in
+ * addition to a definition check. NPN was added in 1.0.1: for any version
+ * before that, there is no compatibility.
+ */
+#if defined(OPENSSL_NO_NEXTPROTONEG) || OPENSSL_VERSION_NUMBER < 0x1000100fL
+static const long Cryptography_HAS_NEXTPROTONEG = 0;
+void (*SSL_CTX_set_next_protos_advertised_cb)(SSL_CTX *,
+ int (*)(SSL *,
+ const unsigned char **,
+ unsigned int *,
+ void *),
+ void *) = NULL;
+void (*SSL_CTX_set_next_proto_select_cb)(SSL_CTX *,
+ int (*)(SSL *,
+ unsigned char **,
+ unsigned char *,
+ const unsigned char *,
+ unsigned int,
+ void *),
+ void *) = NULL;
+int (*SSL_select_next_proto)(unsigned char **, unsigned char *,
+ const unsigned char *, unsigned int,
+ const unsigned char *, unsigned int) = NULL;
+void (*SSL_get0_next_proto_negotiated)(const SSL *,
+ const unsigned char **,
+ unsigned *) = NULL;
+#else
+static const long Cryptography_HAS_NEXTPROTONEG = 1;
+#endif
+
+/* ALPN was added in OpenSSL 1.0.2. */
+#if OPENSSL_VERSION_NUMBER < 0x10002001L
+int (*SSL_CTX_set_alpn_protos)(SSL_CTX *,
+ const unsigned char*,
+ unsigned) = NULL;
+int (*SSL_set_alpn_protos)(SSL *, const unsigned char*, unsigned) = NULL;
+void (*SSL_CTX_set_alpn_select_cb)(SSL_CTX *,
+ int (*) (SSL *,
+ const unsigned char **,
+ unsigned char *,
+ const unsigned char *,
+ unsigned int,
+ void *),
+ void *) = NULL;
+void (*SSL_get0_alpn_selected)(const SSL *,
+ const unsigned char **,
+ unsigned *) = NULL;
+static const long Cryptography_HAS_ALPN = 0;
+#else
+static const long Cryptography_HAS_ALPN = 1;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_TLSv1_1": [
+ "SSL_OP_NO_TLSv1_1",
+ "TLSv1_1_method",
+ "TLSv1_1_server_method",
+ "TLSv1_1_client_method",
+ ],
+
+ "Cryptography_HAS_TLSv1_2": [
+ "SSL_OP_NO_TLSv1_2",
+ "TLSv1_2_method",
+ "TLSv1_2_server_method",
+ "TLSv1_2_client_method",
+ ],
+
+ "Cryptography_HAS_SSL2": [
+ "SSLv2_method",
+ "SSLv2_client_method",
+ "SSLv2_server_method",
+ ],
+
+ "Cryptography_HAS_TLSEXT_HOSTNAME": [
+ "SSL_set_tlsext_host_name",
+ "SSL_get_servername",
+ "SSL_CTX_set_tlsext_servername_callback",
+ ],
+
+ "Cryptography_HAS_RELEASE_BUFFERS": [
+ "SSL_MODE_RELEASE_BUFFERS",
+ ],
+
+ "Cryptography_HAS_OP_NO_COMPRESSION": [
+ "SSL_OP_NO_COMPRESSION",
+ ],
+
+ "Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING": [
+ "SSL_OP_MSIE_SSLV2_RSA_PADDING",
+ ],
+
+ "Cryptography_HAS_EC": [
+ "SSL_CTX_set_tmp_ecdh",
+ ],
+
+ "Cryptography_HAS_SSL_OP_NO_TICKET": [
+ "SSL_OP_NO_TICKET",
+ ],
+
+ "Cryptography_HAS_SSL_SET_SSL_CTX": [
+ "SSL_set_SSL_CTX",
+ "TLSEXT_NAMETYPE_host_name",
+ ],
+
+ "Cryptography_HAS_NETBSD_D1_METH": [
+ "DTLSv1_method",
+ ],
+
+ "Cryptography_HAS_NEXTPROTONEG": [
+ "SSL_CTX_set_next_protos_advertised_cb",
+ "SSL_CTX_set_next_proto_select_cb",
+ "SSL_select_next_proto",
+ "SSL_get0_next_proto_negotiated",
+ ],
+
+ "Cryptography_HAS_SECURE_RENEGOTIATION": [
+ "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION",
+ "SSL_OP_LEGACY_SERVER_CONNECT",
+ "SSL_get_secure_renegotiation_support",
+ ],
+
+ "Cryptography_HAS_ALPN": [
+ "SSL_CTX_set_alpn_protos",
+ "SSL_set_alpn_protos",
+ "SSL_CTX_set_alpn_select_cb",
+ "SSL_get0_alpn_selected",
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/x509.py b/src/cryptography/hazmat/bindings/openssl/x509.py
new file mode 100644
index 00000000..95bc7c3b
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/x509.py
@@ -0,0 +1,273 @@
+# 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
+
+INCLUDES = """
+#include <openssl/ssl.h>
+
+/*
+ * This is part of a work-around for the difficulty cffi has in dealing with
+ * `STACK_OF(foo)` as the name of a type. We invent a new, simpler name that
+ * will be an alias for this type and use the alias throughout. This works
+ * together with another opaque typedef for the same name in the TYPES section.
+ * Note that the result is an opaque type.
+ */
+typedef STACK_OF(X509) Cryptography_STACK_OF_X509;
+typedef STACK_OF(X509_CRL) Cryptography_STACK_OF_X509_CRL;
+typedef STACK_OF(X509_REVOKED) Cryptography_STACK_OF_X509_REVOKED;
+"""
+
+TYPES = """
+typedef ... Cryptography_STACK_OF_X509;
+typedef ... Cryptography_STACK_OF_X509_CRL;
+typedef ... Cryptography_STACK_OF_X509_REVOKED;
+
+typedef struct {
+ ASN1_OBJECT *algorithm;
+ ...;
+} X509_ALGOR;
+
+typedef ... X509_ATTRIBUTE;
+
+typedef struct {
+ X509_ALGOR *signature;
+ ...;
+} X509_CINF;
+
+typedef struct {
+ ASN1_OBJECT *object;
+ ASN1_BOOLEAN critical;
+ ASN1_OCTET_STRING *value;
+} X509_EXTENSION;
+
+typedef ... X509_EXTENSIONS;
+
+typedef ... X509_REQ;
+
+typedef struct {
+ ASN1_INTEGER *serialNumber;
+ ASN1_TIME *revocationDate;
+ X509_EXTENSIONS *extensions;
+ int sequence;
+ ...;
+} X509_REVOKED;
+
+typedef struct {
+ Cryptography_STACK_OF_X509_REVOKED *revoked;
+ ...;
+} X509_CRL_INFO;
+
+typedef struct {
+ X509_CRL_INFO *crl;
+ ...;
+} X509_CRL;
+
+typedef struct {
+ X509_CINF *cert_info;
+ ...;
+} X509;
+
+typedef ... NETSCAPE_SPKI;
+"""
+
+FUNCTIONS = """
+X509 *X509_new(void);
+void X509_free(X509 *);
+X509 *X509_dup(X509 *);
+
+int X509_print_ex(BIO *, X509 *, unsigned long, unsigned long);
+
+int X509_set_version(X509 *, long);
+
+EVP_PKEY *X509_get_pubkey(X509 *);
+int X509_set_pubkey(X509 *, EVP_PKEY *);
+
+unsigned char *X509_alias_get0(X509 *, int *);
+int X509_sign(X509 *, EVP_PKEY *, const EVP_MD *);
+
+int X509_digest(const X509 *, const EVP_MD *, unsigned char *, unsigned int *);
+
+ASN1_TIME *X509_gmtime_adj(ASN1_TIME *, long);
+
+unsigned long X509_subject_name_hash(X509 *);
+
+X509_NAME *X509_get_subject_name(X509 *);
+int X509_set_subject_name(X509 *, X509_NAME *);
+
+X509_NAME *X509_get_issuer_name(X509 *);
+int X509_set_issuer_name(X509 *, X509_NAME *);
+
+int X509_get_ext_count(X509 *);
+int X509_add_ext(X509 *, X509_EXTENSION *, int);
+X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *);
+X509_EXTENSION *X509_get_ext(X509 *, int);
+int X509_EXTENSION_get_critical(X509_EXTENSION *);
+ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *);
+void X509_EXTENSION_free(X509_EXTENSION *);
+
+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_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_ex(BIO *, X509_REQ *, unsigned long, unsigned long);
+
+int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int);
+ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *);
+
+X509_REVOKED *X509_REVOKED_new(void);
+void X509_REVOKED_free(X509_REVOKED *);
+
+int X509_REVOKED_set_serialNumber(X509_REVOKED *, ASN1_INTEGER *);
+
+int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long);
+
+X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **);
+X509_CRL *X509_CRL_new(void);
+void X509_CRL_free(X509_CRL *);
+int X509_CRL_add0_revoked(X509_CRL *, X509_REVOKED *);
+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 NETSCAPE_SPKI_verify(NETSCAPE_SPKI *, EVP_PKEY *);
+int NETSCAPE_SPKI_sign(NETSCAPE_SPKI *, EVP_PKEY *, const EVP_MD *);
+char *NETSCAPE_SPKI_b64_encode(NETSCAPE_SPKI *);
+EVP_PKEY *NETSCAPE_SPKI_get_pubkey(NETSCAPE_SPKI *);
+int NETSCAPE_SPKI_set_pubkey(NETSCAPE_SPKI *, EVP_PKEY *);
+NETSCAPE_SPKI *NETSCAPE_SPKI_new(void);
+void NETSCAPE_SPKI_free(NETSCAPE_SPKI *);
+
+/* ASN1 serialization */
+int i2d_X509_bio(BIO *, X509 *);
+X509 *d2i_X509_bio(BIO *, X509 **);
+
+int i2d_X509_REQ_bio(BIO *, X509_REQ *);
+X509_REQ *d2i_X509_REQ_bio(BIO *, X509_REQ **);
+
+int i2d_PrivateKey_bio(BIO *, EVP_PKEY *);
+EVP_PKEY *d2i_PrivateKey_bio(BIO *, EVP_PKEY **);
+int i2d_PUBKEY_bio(BIO *, EVP_PKEY *);
+EVP_PKEY *d2i_PUBKEY_bio(BIO *, EVP_PKEY **);
+
+ASN1_INTEGER *X509_get_serialNumber(X509 *);
+int X509_set_serialNumber(X509 *, ASN1_INTEGER *);
+
+const char *X509_verify_cert_error_string(long);
+
+const char *X509_get_default_cert_area(void);
+const char *X509_get_default_cert_dir(void);
+const char *X509_get_default_cert_file(void);
+const char *X509_get_default_cert_dir_env(void);
+const char *X509_get_default_cert_file_env(void);
+const char *X509_get_default_private_dir(void);
+
+int i2d_RSA_PUBKEY(RSA *, unsigned char **);
+RSA *d2i_RSA_PUBKEY(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPublicKey(RSA **, const unsigned char **, long);
+RSA *d2i_RSAPrivateKey(RSA **, const unsigned char **, long);
+int i2d_DSA_PUBKEY(DSA *, unsigned char **);
+DSA *d2i_DSA_PUBKEY(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPublicKey(DSA **, const unsigned char **, long);
+DSA *d2i_DSAPrivateKey(DSA **, const unsigned char **, long);
+
+RSA *d2i_RSAPrivateKey_bio(BIO *, RSA **);
+int i2d_RSAPrivateKey_bio(BIO *, RSA *);
+RSA *d2i_RSAPublicKey_bio(BIO *, RSA **);
+int i2d_RSAPublicKey_bio(BIO *, RSA *);
+RSA *d2i_RSA_PUBKEY_bio(BIO *, RSA **);
+int i2d_RSA_PUBKEY_bio(BIO *, RSA *);
+DSA *d2i_DSA_PUBKEY_bio(BIO *, DSA **);
+int i2d_DSA_PUBKEY_bio(BIO *, DSA *);
+DSA *d2i_DSAPrivateKey_bio(BIO *, DSA **);
+int i2d_DSAPrivateKey_bio(BIO *, DSA *);
+"""
+
+MACROS = """
+long X509_get_version(X509 *);
+
+ASN1_TIME *X509_get_notBefore(X509 *);
+ASN1_TIME *X509_get_notAfter(X509 *);
+
+long X509_REQ_get_version(X509_REQ *);
+X509_NAME *X509_REQ_get_subject_name(X509_REQ *);
+
+Cryptography_STACK_OF_X509 *sk_X509_new_null(void);
+void sk_X509_free(Cryptography_STACK_OF_X509 *);
+int sk_X509_num(Cryptography_STACK_OF_X509 *);
+int sk_X509_push(Cryptography_STACK_OF_X509 *, X509 *);
+X509 *sk_X509_value(Cryptography_STACK_OF_X509 *, int);
+
+X509_EXTENSIONS *sk_X509_EXTENSION_new_null(void);
+int sk_X509_EXTENSION_num(X509_EXTENSIONS *);
+X509_EXTENSION *sk_X509_EXTENSION_value(X509_EXTENSIONS *, int);
+int sk_X509_EXTENSION_push(X509_EXTENSIONS *, X509_EXTENSION *);
+X509_EXTENSION *sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int);
+void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
+
+int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *);
+X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int);
+
+int i2d_RSAPublicKey(RSA *, unsigned char **);
+int i2d_RSAPrivateKey(RSA *, unsigned char **);
+int i2d_DSAPublicKey(DSA *, unsigned char **);
+int i2d_DSAPrivateKey(DSA *, unsigned char **);
+
+/* These aren't macros these arguments are all const X on openssl > 1.0.x */
+int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
+int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
+
+/* These use STACK_OF(X509_EXTENSION) in 0.9.8e. Once we drop support for
+ RHEL/CentOS 5 we should move these back to FUNCTIONS. */
+int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
+X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
+
+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_bio(BIO *, EC_KEY **);
+int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
+"""
+
+CUSTOMIZATIONS = """
+/* OpenSSL 0.9.8e does not have this definition. */
+#if OPENSSL_VERSION_NUMBER <= 0x0090805fL
+typedef STACK_OF(X509_EXTENSION) X509_EXTENSIONS;
+#endif
+#ifdef OPENSSL_NO_EC
+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_bio)(BIO *, EC_KEY **) = NULL;
+int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC": [
+ "i2d_EC_PUBKEY",
+ "d2i_EC_PUBKEY",
+ "d2i_EC_PUBKEY_bio",
+ "i2d_EC_PUBKEY_bio",
+ "d2i_ECPrivateKey_bio",
+ "i2d_ECPrivateKey_bio",
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/x509_vfy.py b/src/cryptography/hazmat/bindings/openssl/x509_vfy.py
new file mode 100644
index 00000000..601926c9
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/x509_vfy.py
@@ -0,0 +1,336 @@
+# 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
+
+INCLUDES = """
+#include <openssl/x509_vfy.h>
+
+/*
+ * This is part of a work-around for the difficulty cffi has in dealing with
+ * `STACK_OF(foo)` as the name of a type. We invent a new, simpler name that
+ * will be an alias for this type and use the alias throughout. This works
+ * together with another opaque typedef for the same name in the TYPES section.
+ * Note that the result is an opaque type.
+ */
+typedef STACK_OF(ASN1_OBJECT) Cryptography_STACK_OF_ASN1_OBJECT;
+"""
+
+TYPES = """
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES;
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS;
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST;
+static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN;
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES;
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS;
+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;
+
+/* 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. */
+
+/* Verification error codes */
+static const int X509_V_OK;
+static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT;
+static const int X509_V_ERR_UNABLE_TO_GET_CRL;
+static const int X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE;
+static const int X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE;
+static const int X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY;
+static const int X509_V_ERR_CERT_SIGNATURE_FAILURE;
+static const int X509_V_ERR_CRL_SIGNATURE_FAILURE;
+static const int X509_V_ERR_CERT_NOT_YET_VALID;
+static const int X509_V_ERR_CERT_HAS_EXPIRED;
+static const int X509_V_ERR_CRL_NOT_YET_VALID;
+static const int X509_V_ERR_CRL_HAS_EXPIRED;
+static const int X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
+static const int X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD;
+static const int X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD;
+static const int X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD;
+static const int X509_V_ERR_OUT_OF_MEM;
+static const int X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT;
+static const int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+static const int X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
+static const int X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE;
+static const int X509_V_ERR_CERT_CHAIN_TOO_LONG;
+static const int X509_V_ERR_CERT_REVOKED;
+static const int X509_V_ERR_INVALID_CA;
+static const int X509_V_ERR_PATH_LENGTH_EXCEEDED;
+static const int X509_V_ERR_INVALID_PURPOSE;
+static const int X509_V_ERR_CERT_UNTRUSTED;
+static const int X509_V_ERR_CERT_REJECTED;
+static const int X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
+static const int X509_V_ERR_AKID_SKID_MISMATCH;
+static const int X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH;
+static const int X509_V_ERR_KEYUSAGE_NO_CERTSIGN;
+static const int X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER;
+static const int X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
+static const int X509_V_ERR_KEYUSAGE_NO_CRL_SIGN;
+static const int X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION;
+static const int X509_V_ERR_INVALID_NON_CA;
+static const int X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED;
+static const int X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE;
+static const int X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
+static const int X509_V_ERR_INVALID_EXTENSION;
+static const int X509_V_ERR_INVALID_POLICY_EXTENSION;
+static const int X509_V_ERR_NO_EXPLICIT_POLICY;
+static const int X509_V_ERR_DIFFERENT_CRL_SCOPE;
+static const int X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE;
+static const int X509_V_ERR_UNNESTED_RESOURCE;
+static const int X509_V_ERR_PERMITTED_VIOLATION;
+static const int X509_V_ERR_EXCLUDED_VIOLATION;
+static const int X509_V_ERR_SUBTREE_MINMAX;
+static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE;
+static const int X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
+static const int X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
+static const int X509_V_ERR_CRL_PATH_VALIDATION_ERROR;
+static const int X509_V_ERR_SUITE_B_INVALID_VERSION;
+static const int X509_V_ERR_SUITE_B_INVALID_ALGORITHM;
+static const int X509_V_ERR_SUITE_B_INVALID_CURVE;
+static const int X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM;
+static const int X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED;
+static const int X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256;
+static const int X509_V_ERR_HOSTNAME_MISMATCH;
+static const int X509_V_ERR_EMAIL_MISMATCH;
+static const int X509_V_ERR_IP_ADDRESS_MISMATCH;
+static const int X509_V_ERR_APPLICATION_VERIFICATION;
+
+/* Verification parameters */
+static const long X509_V_FLAG_CB_ISSUER_CHECK;
+static const long X509_V_FLAG_USE_CHECK_TIME;
+static const long X509_V_FLAG_CRL_CHECK;
+static const long X509_V_FLAG_CRL_CHECK_ALL;
+static const long X509_V_FLAG_IGNORE_CRITICAL;
+static const long X509_V_FLAG_X509_STRICT;
+static const long X509_V_FLAG_ALLOW_PROXY_CERTS;
+static const long X509_V_FLAG_POLICY_CHECK;
+static const long X509_V_FLAG_EXPLICIT_POLICY;
+static const long X509_V_FLAG_INHIBIT_ANY;
+static const long X509_V_FLAG_INHIBIT_MAP;
+static const long X509_V_FLAG_NOTIFY_POLICY;
+static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT;
+static const long X509_V_FLAG_USE_DELTAS;
+static const long X509_V_FLAG_CHECK_SS_SIGNATURE;
+static const long X509_V_FLAG_TRUSTED_FIRST;
+static const long X509_V_FLAG_SUITEB_128_LOS_ONLY;
+static const long X509_V_FLAG_SUITEB_192_LOS;
+static const long X509_V_FLAG_SUITEB_128_LOS;
+static const long X509_V_FLAG_PARTIAL_CHAIN;
+"""
+
+FUNCTIONS = """
+int X509_verify_cert(X509_STORE_CTX *);
+
+/* X509_STORE */
+X509_STORE *X509_STORE_new(void);
+void X509_STORE_free(X509_STORE *);
+int X509_STORE_add_cert(X509_STORE *, X509 *);
+
+/* X509_STORE_CTX */
+X509_STORE_CTX *X509_STORE_CTX_new(void);
+void X509_STORE_CTX_cleanup(X509_STORE_CTX *);
+void X509_STORE_CTX_free(X509_STORE_CTX *);
+int X509_STORE_CTX_init(X509_STORE_CTX *, X509_STORE *, X509 *,
+ Cryptography_STACK_OF_X509 *);
+void X509_STORE_CTX_trusted_stack(X509_STORE_CTX *,
+ Cryptography_STACK_OF_X509 *);
+void X509_STORE_CTX_set_cert(X509_STORE_CTX *, X509 *);
+void X509_STORE_CTX_set_chain(X509_STORE_CTX *,Cryptography_STACK_OF_X509 *);
+X509_VERIFY_PARAM *X509_STORE_CTX_get0_param(X509_STORE_CTX *);
+void X509_STORE_CTX_set0_param(X509_STORE_CTX *, X509_VERIFY_PARAM *);
+int X509_STORE_CTX_set_default(X509_STORE_CTX *, const char *);
+void X509_STORE_CTX_set_verify_cb(X509_STORE_CTX *,
+ int (*)(int, X509_STORE_CTX *));
+Cryptography_STACK_OF_X509 *X509_STORE_CTX_get_chain(X509_STORE_CTX *);
+Cryptography_STACK_OF_X509 *X509_STORE_CTX_get1_chain(X509_STORE_CTX *);
+int X509_STORE_CTX_get_error(X509_STORE_CTX *);
+void X509_STORE_CTX_set_error(X509_STORE_CTX *, int);
+int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *);
+X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *);
+int X509_STORE_CTX_set_ex_data(X509_STORE_CTX *, int, void *);
+void *X509_STORE_CTX_get_ex_data(X509_STORE_CTX *, int);
+
+/* X509_VERIFY_PARAM */
+X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
+int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *, unsigned long);
+int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *, unsigned long);
+unsigned long X509_VERIFY_PARAM_get_flags(X509_VERIFY_PARAM *);
+int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *, int);
+int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *, int);
+void X509_VERIFY_PARAM_set_time(X509_VERIFY_PARAM *, time_t);
+int X509_VERIFY_PARAM_add0_policy(X509_VERIFY_PARAM *, ASN1_OBJECT *);
+int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *,
+ Cryptography_STACK_OF_ASN1_OBJECT *);
+void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *, int);
+int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *);
+"""
+
+MACROS = """
+/* X509_STORE_CTX */
+void X509_STORE_CTX_set0_crls(X509_STORE_CTX *,
+ Cryptography_STACK_OF_X509_CRL *);
+
+/* X509_VERIFY_PARAM */
+int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *, const char *,
+ size_t);
+void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *, unsigned int);
+int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *, const char *,
+ size_t);
+int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t);
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *, const char *);
+"""
+
+CUSTOMIZATIONS = """
+/* OpenSSL 1.0.2+ verification error codes */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 1;
+#else
+static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_VERSION = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_ALGORITHM = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_CURVE = 0;
+static const long X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM = 0;
+static const long X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED = 0;
+static const long X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 = 0;
+static const long X509_V_ERR_HOSTNAME_MISMATCH = 0;
+static const long X509_V_ERR_EMAIL_MISMATCH = 0;
+static const long X509_V_ERR_IP_ADDRESS_MISMATCH = 0;
+#endif
+
+/* OpenSSL 1.0.2+ verification parameters */
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 1;
+#else
+static const long Cryptography_HAS_102_VERIFICATION_PARAMS = 0;
+/* X509_V_FLAG_TRUSTED_FIRST is also new in 1.0.2+, but it is added separately
+ below because it shows up in some earlier 3rd party OpenSSL packages. */
+static const long X509_V_FLAG_SUITEB_128_LOS_ONLY = 0;
+static const long X509_V_FLAG_SUITEB_192_LOS = 0;
+static const long X509_V_FLAG_SUITEB_128_LOS = 0;
+
+int (*X509_VERIFY_PARAM_set1_host)(X509_VERIFY_PARAM *, const char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_email)(X509_VERIFY_PARAM *, const char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_ip)(X509_VERIFY_PARAM *, const unsigned char *,
+ size_t) = NULL;
+int (*X509_VERIFY_PARAM_set1_ip_asc)(X509_VERIFY_PARAM *, const char *) = NULL;
+void (*X509_VERIFY_PARAM_set_hostflags)(X509_VERIFY_PARAM *,
+ unsigned int) = NULL;
+#endif
+
+/* OpenSSL 1.0.2+ or Solaris's backport */
+#ifdef X509_V_FLAG_PARTIAL_CHAIN
+static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 1;
+#else
+static const long Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN = 0;
+static const long X509_V_FLAG_PARTIAL_CHAIN = 0;
+#endif
+
+/* OpenSSL 1.0.2+, *or* Fedora 20's flavor of OpenSSL 1.0.1e... */
+#ifdef X509_V_FLAG_TRUSTED_FIRST
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 1;
+#else
+static const long Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST = 0;
+static const long X509_V_FLAG_TRUSTED_FIRST = 0;
+#endif
+
+/* OpenSSL 1.0.0+ verification error codes */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 1;
+#else
+static const long Cryptography_HAS_100_VERIFICATION_ERROR_CODES = 0;
+static const long X509_V_ERR_DIFFERENT_CRL_SCOPE = 0;
+static const long X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE = 0;
+static const long X509_V_ERR_PERMITTED_VIOLATION = 0;
+static const long X509_V_ERR_EXCLUDED_VIOLATION = 0;
+static const long X509_V_ERR_SUBTREE_MINMAX = 0;
+static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE = 0;
+static const long X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX = 0;
+static const long X509_V_ERR_UNSUPPORTED_NAME_SYNTAX = 0;
+static const long X509_V_ERR_CRL_PATH_VALIDATION_ERROR = 0;
+#endif
+
+/* OpenSSL 1.0.0+ verification parameters */
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 1;
+#else
+static const long Cryptography_HAS_100_VERIFICATION_PARAMS = 0;
+static const long X509_V_FLAG_EXTENDED_CRL_SUPPORT = 0;
+static const long X509_V_FLAG_USE_DELTAS = 0;
+#endif
+
+/* OpenSSL 0.9.8recent+ */
+#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
+static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 1;
+#else
+static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
+static const long X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
+#endif
+"""
+
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_102_VERIFICATION_ERROR_CODES": [
+ 'X509_V_ERR_SUITE_B_INVALID_VERSION',
+ 'X509_V_ERR_SUITE_B_INVALID_ALGORITHM',
+ 'X509_V_ERR_SUITE_B_INVALID_CURVE',
+ 'X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM',
+ 'X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED',
+ 'X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256',
+ 'X509_V_ERR_HOSTNAME_MISMATCH',
+ 'X509_V_ERR_EMAIL_MISMATCH',
+ 'X509_V_ERR_IP_ADDRESS_MISMATCH'
+ ],
+ "Cryptography_HAS_102_VERIFICATION_PARAMS": [
+ "X509_V_FLAG_SUITEB_128_LOS_ONLY",
+ "X509_V_FLAG_SUITEB_192_LOS",
+ "X509_V_FLAG_SUITEB_128_LOS",
+ "X509_VERIFY_PARAM_set1_host",
+ "X509_VERIFY_PARAM_set1_email",
+ "X509_VERIFY_PARAM_set1_ip",
+ "X509_VERIFY_PARAM_set1_ip_asc",
+ "X509_VERIFY_PARAM_set_hostflags",
+ ],
+ "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": [
+ "X509_V_FLAG_TRUSTED_FIRST",
+ ],
+ "Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": [
+ "X509_V_FLAG_PARTIAL_CHAIN",
+ ],
+ "Cryptography_HAS_100_VERIFICATION_ERROR_CODES": [
+ 'X509_V_ERR_DIFFERENT_CRL_SCOPE',
+ 'X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE',
+ 'X509_V_ERR_UNNESTED_RESOURCE',
+ 'X509_V_ERR_PERMITTED_VIOLATION',
+ 'X509_V_ERR_EXCLUDED_VIOLATION',
+ 'X509_V_ERR_SUBTREE_MINMAX',
+ 'X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE',
+ 'X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX',
+ 'X509_V_ERR_UNSUPPORTED_NAME_SYNTAX',
+ 'X509_V_ERR_CRL_PATH_VALIDATION_ERROR',
+ ],
+ "Cryptography_HAS_100_VERIFICATION_PARAMS": [
+ "Cryptography_HAS_100_VERIFICATION_PARAMS",
+ "X509_V_FLAG_EXTENDED_CRL_SUPPORT",
+ "X509_V_FLAG_USE_DELTAS",
+ ],
+ "Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE": [
+ "X509_V_FLAG_CHECK_SS_SIGNATURE",
+ ]
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/x509name.py b/src/cryptography/hazmat/bindings/openssl/x509name.py
new file mode 100644
index 00000000..50abee2a
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/x509name.py
@@ -0,0 +1,61 @@
+# 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
+
+INCLUDES = """
+#include <openssl/x509.h>
+
+/*
+ * See the comment above Cryptography_STACK_OF_X509 in x509.py
+ */
+typedef STACK_OF(X509_NAME) Cryptography_STACK_OF_X509_NAME;
+"""
+
+TYPES = """
+typedef ... X509_NAME;
+typedef ... X509_NAME_ENTRY;
+typedef ... Cryptography_STACK_OF_X509_NAME;
+"""
+
+FUNCTIONS = """
+int X509_NAME_entry_count(X509_NAME *);
+X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int);
+ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *);
+ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *);
+unsigned long X509_NAME_hash(X509_NAME *);
+
+int i2d_X509_NAME(X509_NAME *, unsigned char **);
+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);
+void X509_NAME_ENTRY_free(X509_NAME_ENTRY *);
+int X509_NAME_get_index_by_NID(X509_NAME *, int, int);
+int X509_NAME_cmp(const X509_NAME *, const X509_NAME *);
+char *X509_NAME_oneline(X509_NAME *, char *, int);
+X509_NAME *X509_NAME_dup(X509_NAME *);
+void X509_NAME_free(X509_NAME *);
+"""
+
+MACROS = """
+Cryptography_STACK_OF_X509_NAME *sk_X509_NAME_new_null(void);
+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 *);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/openssl/x509v3.py b/src/cryptography/hazmat/bindings/openssl/x509v3.py
new file mode 100644
index 00000000..cf4be1fe
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/x509v3.py
@@ -0,0 +1,103 @@
+# 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
+
+INCLUDES = """
+#include <openssl/x509v3.h>
+"""
+
+TYPES = """
+typedef struct {
+ X509 *issuer_cert;
+ X509 *subject_cert;
+ ...;
+} X509V3_CTX;
+
+typedef void * (*X509V3_EXT_D2I)(void *, const unsigned char **, long);
+
+typedef struct {
+ ASN1_ITEM_EXP *it;
+ X509V3_EXT_D2I d2i;
+ ...;
+} X509V3_EXT_METHOD;
+
+static const int GEN_OTHERNAME;
+static const int GEN_EMAIL;
+static const int GEN_X400;
+static const int GEN_DNS;
+static const int GEN_URI;
+static const int GEN_DIRNAME;
+static const int GEN_EDIPARTY;
+static const int GEN_IPADD;
+static const int GEN_RID;
+
+typedef struct {
+ ...;
+} OTHERNAME;
+
+typedef struct {
+ ...;
+} EDIPARTYNAME;
+
+typedef struct {
+ int type;
+ union {
+ char *ptr;
+ OTHERNAME *otherName; /* otherName */
+ ASN1_IA5STRING *rfc822Name;
+ ASN1_IA5STRING *dNSName;
+ ASN1_TYPE *x400Address;
+ X509_NAME *directoryName;
+ EDIPARTYNAME *ediPartyName;
+ ASN1_IA5STRING *uniformResourceIdentifier;
+ ASN1_OCTET_STRING *iPAddress;
+ ASN1_OBJECT *registeredID;
+
+ /* Old names */
+ ASN1_OCTET_STRING *ip; /* iPAddress */
+ X509_NAME *dirn; /* dirn */
+ ASN1_IA5STRING *ia5; /* rfc822Name, dNSName, */
+ /* uniformResourceIdentifier */
+ ASN1_OBJECT *rid; /* registeredID */
+ ASN1_TYPE *other; /* x400Address */
+ } d;
+ ...;
+} GENERAL_NAME;
+
+typedef struct stack_st_GENERAL_NAME GENERAL_NAMES;
+"""
+
+FUNCTIONS = """
+void X509V3_set_ctx(X509V3_CTX *, X509 *, X509 *, X509_REQ *, X509_CRL *, int);
+X509_EXTENSION *X509V3_EXT_nconf(CONF *, X509V3_CTX *, char *, char *);
+int GENERAL_NAME_print(BIO *, GENERAL_NAME *);
+void GENERAL_NAMES_free(GENERAL_NAMES *);
+void *X509V3_EXT_d2i(X509_EXTENSION *);
+"""
+
+MACROS = """
+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);
+
+/* These aren't macros these functions are all const X on openssl > 1.0.x */
+const X509V3_EXT_METHOD *X509V3_EXT_get(X509_EXTENSION *);
+const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int);
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/src/cryptography/hazmat/bindings/utils.py b/src/cryptography/hazmat/bindings/utils.py
new file mode 100644
index 00000000..55b61292
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/utils.py
@@ -0,0 +1,144 @@
+# 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 binascii
+import sys
+import threading
+
+from cffi import FFI
+from cffi.verifier import Verifier
+
+
+class LazyLibrary(object):
+ def __init__(self, ffi):
+ self._ffi = ffi
+ self._lib = None
+ self._lock = threading.Lock()
+
+ def __getattr__(self, name):
+ if self._lib is None:
+ with self._lock:
+ if self._lib is None:
+ self._lib = self._ffi.verifier.load_library()
+
+ return getattr(self._lib, name)
+
+
+def load_library_for_binding(ffi, module_prefix, modules):
+ lib = ffi.verifier.load_library()
+
+ for name in modules:
+ module_name = module_prefix + name
+ module = sys.modules[module_name]
+ for condition, names in module.CONDITIONAL_NAMES.items():
+ if not getattr(lib, condition):
+ for name in names:
+ delattr(lib, name)
+
+ return lib
+
+
+def build_ffi_for_binding(module_prefix, modules, pre_include="",
+ post_include="", libraries=[], extra_compile_args=[],
+ extra_link_args=[]):
+ """
+ Modules listed in ``modules`` should have the following attributes:
+
+ * ``INCLUDES``: A string containing C includes.
+ * ``TYPES``: A string containing C declarations for types.
+ * ``FUNCTIONS``: A string containing C declarations for functions.
+ * ``MACROS``: A string containing C declarations for any macros.
+ * ``CUSTOMIZATIONS``: A string containing arbitrary top-level C code, this
+ can be used to do things like test for a define and provide an
+ alternate implementation based on that.
+ * ``CONDITIONAL_NAMES``: A dict mapping strings of condition names from the
+ library to a list of names which will not be present without the
+ condition.
+ """
+ types = []
+ includes = []
+ functions = []
+ macros = []
+ customizations = []
+ for name in modules:
+ module_name = module_prefix + name
+ __import__(module_name)
+ module = sys.modules[module_name]
+
+ types.append(module.TYPES)
+ macros.append(module.MACROS)
+ functions.append(module.FUNCTIONS)
+ includes.append(module.INCLUDES)
+ customizations.append(module.CUSTOMIZATIONS)
+
+ # We include functions here so that if we got any of their definitions
+ # wrong, the underlying C compiler will explode. In C you are allowed
+ # to re-declare a function if it has the same signature. That is:
+ # int foo(int);
+ # int foo(int);
+ # is legal, but the following will fail to compile:
+ # int foo(int);
+ # int foo(short);
+ verify_source = "\n".join(
+ [pre_include] +
+ includes +
+ [post_include] +
+ functions +
+ customizations
+ )
+ ffi = build_ffi(
+ cdef_source="\n".join(types + functions + macros),
+ verify_source=verify_source,
+ libraries=libraries,
+ extra_compile_args=extra_compile_args,
+ extra_link_args=extra_link_args,
+ )
+
+ return ffi
+
+
+def build_ffi(cdef_source, verify_source, libraries=[], extra_compile_args=[],
+ extra_link_args=[]):
+ ffi = FFI()
+ ffi.cdef(cdef_source)
+
+ ffi.verifier = Verifier(
+ ffi,
+ verify_source,
+ tmpdir='',
+ modulename=_create_modulename(cdef_source, verify_source, sys.version),
+ libraries=libraries,
+ ext_package="cryptography",
+ extra_compile_args=extra_compile_args,
+ extra_link_args=extra_link_args,
+ )
+ return ffi
+
+
+def _create_modulename(cdef_sources, source, sys_version):
+ """
+ cffi creates a modulename internally that incorporates the cffi version.
+ This will cause cryptography's wheels to break when the version of cffi
+ the user has does not match what was used when building the wheel. To
+ resolve this we build our own modulename that uses most of the same code
+ from cffi but elides the version key.
+ """
+ key = '\x00'.join([sys_version[:3], source, cdef_sources])
+ key = key.encode('utf-8')
+ k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff)
+ k1 = k1.lstrip('0x').rstrip('L')
+ k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff)
+ k2 = k2.lstrip('0').rstrip('L')
+ return '_Cryptography_cffi_{0}{1}'.format(k1, k2)
diff --git a/src/cryptography/hazmat/primitives/__init__.py b/src/cryptography/hazmat/primitives/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/primitives/asymmetric/__init__.py b/src/cryptography/hazmat/primitives/asymmetric/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py
new file mode 100644
index 00000000..83e01377
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -0,0 +1,108 @@
+# 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 six
+
+from cryptography import utils
+
+
+def generate_parameters(key_size, backend):
+ return backend.generate_dsa_parameters(key_size)
+
+
+def generate_private_key(key_size, backend):
+ return backend.generate_dsa_private_key_and_parameters(key_size)
+
+
+def _check_dsa_parameters(parameters):
+ if utils.bit_length(parameters.p) not in [1024, 2048, 3072]:
+ raise ValueError("p must be exactly 1024, 2048, or 3072 bits long")
+ if utils.bit_length(parameters.q) not in [160, 256]:
+ raise ValueError("q must be exactly 160 or 256 bits long")
+
+ if not (1 < parameters.g < parameters.p):
+ raise ValueError("g, p don't satisfy 1 < g < p.")
+
+
+def _check_dsa_private_numbers(numbers):
+ parameters = numbers.public_numbers.parameter_numbers
+ _check_dsa_parameters(parameters)
+ if numbers.x <= 0 or numbers.x >= parameters.q:
+ raise ValueError("x must be > 0 and < q.")
+
+ if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p):
+ raise ValueError("y must be equal to (g ** x % p).")
+
+
+class DSAParameterNumbers(object):
+ def __init__(self, p, q, g):
+ if (
+ not isinstance(p, six.integer_types) or
+ not isinstance(q, six.integer_types) or
+ not isinstance(g, six.integer_types)
+ ):
+ raise TypeError(
+ "DSAParameterNumbers p, q, and g arguments must be integers."
+ )
+
+ self._p = p
+ self._q = q
+ self._g = g
+
+ p = utils.read_only_property("_p")
+ q = utils.read_only_property("_q")
+ g = utils.read_only_property("_g")
+
+ def parameters(self, backend):
+ return backend.load_dsa_parameter_numbers(self)
+
+
+class DSAPublicNumbers(object):
+ def __init__(self, y, parameter_numbers):
+ if not isinstance(y, six.integer_types):
+ raise TypeError("DSAPublicNumbers y argument must be an integer.")
+
+ if not isinstance(parameter_numbers, DSAParameterNumbers):
+ raise TypeError(
+ "parameter_numbers must be a DSAParameterNumbers instance."
+ )
+
+ self._y = y
+ self._parameter_numbers = parameter_numbers
+
+ y = utils.read_only_property("_y")
+ parameter_numbers = utils.read_only_property("_parameter_numbers")
+
+ def public_key(self, backend):
+ return backend.load_dsa_public_numbers(self)
+
+
+class DSAPrivateNumbers(object):
+ def __init__(self, x, public_numbers):
+ if not isinstance(x, six.integer_types):
+ raise TypeError("DSAPrivateNumbers x argument must be an integer.")
+
+ if not isinstance(public_numbers, DSAPublicNumbers):
+ raise TypeError(
+ "public_numbers must be a DSAPublicNumbers instance."
+ )
+ self._public_numbers = public_numbers
+ self._x = x
+
+ x = utils.read_only_property("_x")
+ public_numbers = utils.read_only_property("_public_numbers")
+
+ def private_key(self, backend):
+ return backend.load_dsa_private_numbers(self)
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py
new file mode 100644
index 00000000..ced732fb
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -0,0 +1,195 @@
+# 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 six
+
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT571R1(object):
+ name = "sect571r1"
+ key_size = 571
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT409R1(object):
+ name = "sect409r1"
+ key_size = 409
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT283R1(object):
+ name = "sect283r1"
+ key_size = 283
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT233R1(object):
+ name = "sect233r1"
+ key_size = 233
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT163R2(object):
+ name = "sect163r2"
+ key_size = 163
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT571K1(object):
+ name = "sect571k1"
+ key_size = 571
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT409K1(object):
+ name = "sect409k1"
+ key_size = 409
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT283K1(object):
+ name = "sect283k1"
+ key_size = 283
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT233K1(object):
+ name = "sect233k1"
+ key_size = 233
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECT163K1(object):
+ name = "sect163k1"
+ key_size = 163
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP521R1(object):
+ name = "secp521r1"
+ key_size = 521
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP384R1(object):
+ name = "secp384r1"
+ key_size = 384
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP256R1(object):
+ name = "secp256r1"
+ key_size = 256
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP224R1(object):
+ name = "secp224r1"
+ key_size = 224
+
+
+@utils.register_interface(interfaces.EllipticCurve)
+class SECP192R1(object):
+ name = "secp192r1"
+ key_size = 192
+
+
+_CURVE_TYPES = {
+ "prime192v1": SECP192R1,
+ "prime256v1": SECP256R1,
+
+ "secp192r1": SECP192R1,
+ "secp224r1": SECP224R1,
+ "secp256r1": SECP256R1,
+ "secp384r1": SECP384R1,
+ "secp521r1": SECP521R1,
+
+ "sect163k1": SECT163K1,
+ "sect233k1": SECT233K1,
+ "sect283k1": SECT283K1,
+ "sect409k1": SECT409K1,
+ "sect571k1": SECT571K1,
+
+ "sect163r2": SECT163R2,
+ "sect233r1": SECT233R1,
+ "sect283r1": SECT283R1,
+ "sect409r1": SECT409R1,
+ "sect571r1": SECT571R1,
+}
+
+
+@utils.register_interface(interfaces.EllipticCurveSignatureAlgorithm)
+class ECDSA(object):
+ def __init__(self, algorithm):
+ self._algorithm = algorithm
+
+ algorithm = utils.read_only_property("_algorithm")
+
+
+def generate_private_key(curve, backend):
+ return backend.generate_elliptic_curve_private_key(curve)
+
+
+class EllipticCurvePublicNumbers(object):
+ def __init__(self, x, y, curve):
+ if (
+ not isinstance(x, six.integer_types) or
+ not isinstance(y, six.integer_types)
+ ):
+ raise TypeError("x and y must be integers.")
+
+ if not isinstance(curve, interfaces.EllipticCurve):
+ raise TypeError("curve must provide the EllipticCurve interface.")
+
+ self._y = y
+ self._x = x
+ self._curve = curve
+
+ def public_key(self, backend):
+ try:
+ return backend.load_elliptic_curve_public_numbers(self)
+ except AttributeError:
+ return backend.elliptic_curve_public_key_from_numbers(self)
+
+ curve = utils.read_only_property("_curve")
+ x = utils.read_only_property("_x")
+ y = utils.read_only_property("_y")
+
+
+class EllipticCurvePrivateNumbers(object):
+ def __init__(self, private_value, public_numbers):
+ if not isinstance(private_value, six.integer_types):
+ raise TypeError("private_value must be an integer.")
+
+ if not isinstance(public_numbers, EllipticCurvePublicNumbers):
+ raise TypeError(
+ "public_numbers must be an EllipticCurvePublicNumbers "
+ "instance."
+ )
+
+ self._private_value = private_value
+ self._public_numbers = public_numbers
+
+ def private_key(self, backend):
+ try:
+ return backend.load_elliptic_curve_private_numbers(self)
+ except AttributeError:
+ return backend.elliptic_curve_private_key_from_numbers(self)
+
+ private_value = utils.read_only_property("_private_value")
+ public_numbers = utils.read_only_property("_public_numbers")
diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py
new file mode 100644
index 00000000..3967e065
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -0,0 +1,65 @@
+# 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 six
+
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.AsymmetricPadding)
+class PKCS1v15(object):
+ name = "EMSA-PKCS1-v1_5"
+
+
+@utils.register_interface(interfaces.AsymmetricPadding)
+class PSS(object):
+ MAX_LENGTH = object()
+ name = "EMSA-PSS"
+
+ def __init__(self, mgf, salt_length):
+ self._mgf = mgf
+
+ if (not isinstance(salt_length, six.integer_types) and
+ salt_length is not self.MAX_LENGTH):
+ raise TypeError("salt_length must be an integer.")
+
+ if salt_length is not self.MAX_LENGTH and salt_length < 0:
+ raise ValueError("salt_length must be zero or greater.")
+
+ self._salt_length = salt_length
+
+
+@utils.register_interface(interfaces.AsymmetricPadding)
+class OAEP(object):
+ name = "EME-OAEP"
+
+ def __init__(self, mgf, algorithm, label):
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+
+ self._mgf = mgf
+ self._algorithm = algorithm
+ self._label = label
+
+
+class MGF1(object):
+ MAX_LENGTH = object()
+
+ def __init__(self, algorithm):
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+
+ self._algorithm = algorithm
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
new file mode 100644
index 00000000..db38ed55
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -0,0 +1,191 @@
+# 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 six
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.backends.interfaces import RSABackend
+
+
+def generate_private_key(public_exponent, key_size, backend):
+ if not isinstance(backend, RSABackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement RSABackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ _verify_rsa_parameters(public_exponent, key_size)
+ return backend.generate_rsa_private_key(public_exponent, key_size)
+
+
+def _verify_rsa_parameters(public_exponent, key_size):
+ if public_exponent < 3:
+ raise ValueError("public_exponent must be >= 3.")
+
+ if public_exponent & 1 == 0:
+ raise ValueError("public_exponent must be odd.")
+
+ if key_size < 512:
+ raise ValueError("key_size must be at least 512-bits.")
+
+
+def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
+ public_exponent, modulus):
+ if modulus < 3:
+ raise ValueError("modulus must be >= 3.")
+
+ if p >= modulus:
+ raise ValueError("p must be < modulus.")
+
+ if q >= modulus:
+ raise ValueError("q must be < modulus.")
+
+ if dmp1 >= modulus:
+ raise ValueError("dmp1 must be < modulus.")
+
+ if dmq1 >= modulus:
+ raise ValueError("dmq1 must be < modulus.")
+
+ if iqmp >= modulus:
+ raise ValueError("iqmp must be < modulus.")
+
+ if private_exponent >= modulus:
+ raise ValueError("private_exponent must be < modulus.")
+
+ if public_exponent < 3 or public_exponent >= modulus:
+ raise ValueError("public_exponent must be >= 3 and < modulus.")
+
+ if public_exponent & 1 == 0:
+ raise ValueError("public_exponent must be odd.")
+
+ if dmp1 & 1 == 0:
+ raise ValueError("dmp1 must be odd.")
+
+ if dmq1 & 1 == 0:
+ raise ValueError("dmq1 must be odd.")
+
+ if p * q != modulus:
+ raise ValueError("p*q must equal modulus.")
+
+
+def _check_public_key_components(e, n):
+ if n < 3:
+ raise ValueError("n must be >= 3.")
+
+ if e < 3 or e >= n:
+ raise ValueError("e must be >= 3 and < n.")
+
+ if e & 1 == 0:
+ raise ValueError("e must be odd.")
+
+
+def _modinv(e, m):
+ """
+ Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
+ """
+ x1, y1, x2, y2 = 1, 0, 0, 1
+ a, b = e, m
+ while b > 0:
+ q, r = divmod(a, b)
+ xn, yn = x1 - q * x2, y1 - q * y2
+ a, b, x1, y1, x2, y2 = b, r, x2, y2, xn, yn
+ return x1 % m
+
+
+def rsa_crt_iqmp(p, q):
+ """
+ Compute the CRT (q ** -1) % p value from RSA primes p and q.
+ """
+ return _modinv(q, p)
+
+
+def rsa_crt_dmp1(private_exponent, p):
+ """
+ Compute the CRT private_exponent % (p - 1) value from the RSA
+ private_exponent and p.
+ """
+ return private_exponent % (p - 1)
+
+
+def rsa_crt_dmq1(private_exponent, q):
+ """
+ Compute the CRT private_exponent % (q - 1) value from the RSA
+ private_exponent and q.
+ """
+ return private_exponent % (q - 1)
+
+
+class RSAPrivateNumbers(object):
+ def __init__(self, p, q, d, dmp1, dmq1, iqmp,
+ public_numbers):
+ if (
+ not isinstance(p, six.integer_types) or
+ not isinstance(q, six.integer_types) or
+ not isinstance(d, six.integer_types) or
+ not isinstance(dmp1, six.integer_types) or
+ not isinstance(dmq1, six.integer_types) or
+ not isinstance(iqmp, six.integer_types)
+ ):
+ raise TypeError(
+ "RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
+ " all be an integers."
+ )
+
+ if not isinstance(public_numbers, RSAPublicNumbers):
+ raise TypeError(
+ "RSAPrivateNumbers public_numbers must be an RSAPublicNumbers"
+ " instance."
+ )
+
+ self._p = p
+ self._q = q
+ self._d = d
+ self._dmp1 = dmp1
+ self._dmq1 = dmq1
+ self._iqmp = iqmp
+ self._public_numbers = public_numbers
+
+ p = utils.read_only_property("_p")
+ q = utils.read_only_property("_q")
+ d = utils.read_only_property("_d")
+ dmp1 = utils.read_only_property("_dmp1")
+ dmq1 = utils.read_only_property("_dmq1")
+ iqmp = utils.read_only_property("_iqmp")
+ public_numbers = utils.read_only_property("_public_numbers")
+
+ def private_key(self, backend):
+ return backend.load_rsa_private_numbers(self)
+
+
+class RSAPublicNumbers(object):
+ def __init__(self, e, n):
+ if (
+ not isinstance(e, six.integer_types) or
+ not isinstance(n, six.integer_types)
+ ):
+ raise TypeError("RSAPublicNumbers arguments must be integers.")
+
+ self._e = e
+ self._n = n
+
+ e = utils.read_only_property("_e")
+ n = utils.read_only_property("_n")
+
+ def public_key(self, backend):
+ return backend.load_rsa_public_numbers(self)
+
+ def __repr__(self):
+ return "<RSAPublicNumbers(e={0}, n={1})>".format(self._e, self._n)
diff --git a/src/cryptography/hazmat/primitives/ciphers/__init__.py b/src/cryptography/hazmat/primitives/ciphers/__init__.py
new file mode 100644
index 00000000..e5a8ca52
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/ciphers/__init__.py
@@ -0,0 +1,21 @@
+# 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
+
+from cryptography.hazmat.primitives.ciphers.base import Cipher
+
+
+__all__ = [
+ "Cipher",
+]
diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
new file mode 100644
index 00000000..bd8437c2
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -0,0 +1,147 @@
+# 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
+
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+
+def _verify_key_size(algorithm, key):
+ # Verify that the key size matches the expected key size
+ if len(key) * 8 not in algorithm.key_sizes:
+ raise ValueError("Invalid key size ({0}) for {1}.".format(
+ len(key) * 8, algorithm.name
+ ))
+ return key
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class AES(object):
+ name = "AES"
+ block_size = 128
+ key_sizes = frozenset([128, 192, 256])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class Camellia(object):
+ name = "camellia"
+ block_size = 128
+ key_sizes = frozenset([128, 192, 256])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class TripleDES(object):
+ name = "3DES"
+ block_size = 64
+ key_sizes = frozenset([64, 128, 192])
+
+ def __init__(self, key):
+ if len(key) == 8:
+ key += key + key
+ elif len(key) == 16:
+ key += key[:8]
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class Blowfish(object):
+ name = "Blowfish"
+ block_size = 64
+ key_sizes = frozenset(range(32, 449, 8))
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class CAST5(object):
+ name = "CAST5"
+ block_size = 64
+ key_sizes = frozenset(range(40, 129, 8))
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.CipherAlgorithm)
+class ARC4(object):
+ name = "RC4"
+ key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.CipherAlgorithm)
+class IDEA(object):
+ name = "IDEA"
+ block_size = 64
+ key_sizes = frozenset([128])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+@utils.register_interface(interfaces.BlockCipherAlgorithm)
+@utils.register_interface(interfaces.CipherAlgorithm)
+class SEED(object):
+ name = "SEED"
+ block_size = 128
+ key_sizes = frozenset([128])
+
+ def __init__(self, key):
+ self.key = _verify_key_size(self, key)
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py
new file mode 100644
index 00000000..e3fe5adc
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/ciphers/base.py
@@ -0,0 +1,132 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm,
+ _Reasons
+)
+from cryptography.hazmat.backends.interfaces import CipherBackend
+from cryptography.hazmat.primitives import interfaces
+
+
+class Cipher(object):
+ def __init__(self, algorithm, mode, backend):
+ if not isinstance(backend, CipherBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement CipherBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.CipherAlgorithm):
+ raise TypeError(
+ "Expected interface of interfaces.CipherAlgorithm."
+ )
+
+ if mode is not None:
+ mode.validate_for_algorithm(algorithm)
+
+ self.algorithm = algorithm
+ self.mode = mode
+ self._backend = backend
+
+ def encryptor(self):
+ if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
+ if self.mode.tag is not None:
+ raise ValueError(
+ "Authentication tag must be None when encrypting."
+ )
+ ctx = self._backend.create_symmetric_encryption_ctx(
+ self.algorithm, self.mode
+ )
+ return self._wrap_ctx(ctx, encrypt=True)
+
+ def decryptor(self):
+ if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
+ if self.mode.tag is None:
+ raise ValueError(
+ "Authentication tag must be provided when decrypting."
+ )
+ ctx = self._backend.create_symmetric_decryption_ctx(
+ self.algorithm, self.mode
+ )
+ return self._wrap_ctx(ctx, encrypt=False)
+
+ def _wrap_ctx(self, ctx, encrypt):
+ if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
+ if encrypt:
+ return _AEADEncryptionContext(ctx)
+ else:
+ return _AEADCipherContext(ctx)
+ else:
+ return _CipherContext(ctx)
+
+
+@utils.register_interface(interfaces.CipherContext)
+class _CipherContext(object):
+ def __init__(self, ctx):
+ self._ctx = ctx
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ return self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ data = self._ctx.finalize()
+ self._ctx = None
+ return data
+
+
+@utils.register_interface(interfaces.AEADCipherContext)
+@utils.register_interface(interfaces.CipherContext)
+class _AEADCipherContext(object):
+ def __init__(self, ctx):
+ self._ctx = ctx
+ self._tag = None
+ self._updated = False
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ self._updated = True
+ return self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ data = self._ctx.finalize()
+ self._tag = self._ctx.tag
+ self._ctx = None
+ return data
+
+ def authenticate_additional_data(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ if self._updated:
+ raise AlreadyUpdated("Update has been called on this context.")
+ self._ctx.authenticate_additional_data(data)
+
+
+@utils.register_interface(interfaces.AEADEncryptionContext)
+class _AEADEncryptionContext(_AEADCipherContext):
+ @property
+ def tag(self):
+ if self._ctx is not None:
+ raise NotYetFinalized("You must finalize encryption before "
+ "getting the tag.")
+ return self._tag
diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py
new file mode 100644
index 00000000..d995b876
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/ciphers/modes.py
@@ -0,0 +1,125 @@
+# 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
+
+from cryptography import utils
+from cryptography.hazmat.primitives import interfaces
+
+
+def _check_iv_length(self, algorithm):
+ if len(self.initialization_vector) * 8 != algorithm.block_size:
+ raise ValueError("Invalid IV size ({0}) for {1}.".format(
+ len(self.initialization_vector), self.name
+ ))
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+class CBC(object):
+ name = "CBC"
+
+ def __init__(self, initialization_vector):
+ self._initialization_vector = initialization_vector
+
+ initialization_vector = utils.read_only_property("_initialization_vector")
+ validate_for_algorithm = _check_iv_length
+
+
+@utils.register_interface(interfaces.Mode)
+class ECB(object):
+ name = "ECB"
+
+ def validate_for_algorithm(self, algorithm):
+ pass
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+class OFB(object):
+ name = "OFB"
+
+ def __init__(self, initialization_vector):
+ self._initialization_vector = initialization_vector
+
+ initialization_vector = utils.read_only_property("_initialization_vector")
+ validate_for_algorithm = _check_iv_length
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+class CFB(object):
+ name = "CFB"
+
+ def __init__(self, initialization_vector):
+ self._initialization_vector = initialization_vector
+
+ initialization_vector = utils.read_only_property("_initialization_vector")
+ validate_for_algorithm = _check_iv_length
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+class CFB8(object):
+ name = "CFB8"
+
+ def __init__(self, initialization_vector):
+ self._initialization_vector = initialization_vector
+
+ initialization_vector = utils.read_only_property("_initialization_vector")
+ validate_for_algorithm = _check_iv_length
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithNonce)
+class CTR(object):
+ name = "CTR"
+
+ def __init__(self, nonce):
+ self._nonce = nonce
+
+ nonce = utils.read_only_property("_nonce")
+
+ def validate_for_algorithm(self, algorithm):
+ if len(self.nonce) * 8 != algorithm.block_size:
+ raise ValueError("Invalid nonce size ({0}) for {1}.".format(
+ len(self.nonce), self.name
+ ))
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+@utils.register_interface(interfaces.ModeWithAuthenticationTag)
+class GCM(object):
+ name = "GCM"
+
+ def __init__(self, initialization_vector, tag=None, min_tag_length=16):
+ # len(initialization_vector) must in [1, 2 ** 64), but it's impossible
+ # to actually construct a bytes object that large, so we don't check
+ # for it
+ if min_tag_length < 4:
+ raise ValueError("min_tag_length must be >= 4")
+ if tag is not None and len(tag) < min_tag_length:
+ raise ValueError(
+ "Authentication tag must be {0} bytes or longer.".format(
+ min_tag_length)
+ )
+
+ self._initialization_vector = initialization_vector
+ self._tag = tag
+
+ tag = utils.read_only_property("_tag")
+ initialization_vector = utils.read_only_property("_initialization_vector")
+
+ def validate_for_algorithm(self, algorithm):
+ pass
diff --git a/src/cryptography/hazmat/primitives/cmac.py b/src/cryptography/hazmat/primitives/cmac.py
new file mode 100644
index 00000000..6f722031
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/cmac.py
@@ -0,0 +1,75 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import CMACBackend
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.MACContext)
+class CMAC(object):
+ def __init__(self, algorithm, backend, ctx=None):
+ if not isinstance(backend, CMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement CMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.BlockCipherAlgorithm):
+ raise TypeError(
+ "Expected instance of interfaces.BlockCipherAlgorithm."
+ )
+ self._algorithm = algorithm
+
+ self._backend = backend
+ if ctx is None:
+ self._ctx = self._backend.create_cmac_ctx(self._algorithm)
+ else:
+ self._ctx = ctx
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+ self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
+
+ def verify(self, signature):
+ if not isinstance(signature, bytes):
+ raise TypeError("signature must be bytes.")
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ ctx, self._ctx = self._ctx, None
+ ctx.verify(signature)
+
+ def copy(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ return CMAC(
+ self._algorithm,
+ backend=self._backend,
+ ctx=self._ctx.copy()
+ )
diff --git a/src/cryptography/hazmat/primitives/constant_time.py b/src/cryptography/hazmat/primitives/constant_time.py
new file mode 100644
index 00000000..a14eda85
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/constant_time.py
@@ -0,0 +1,47 @@
+# 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 hmac
+import os
+
+from cryptography.hazmat.bindings.utils import LazyLibrary, build_ffi
+
+
+with open(os.path.join(os.path.dirname(__file__), "src/constant_time.h")) as f:
+ TYPES = f.read()
+
+with open(os.path.join(os.path.dirname(__file__), "src/constant_time.c")) as f:
+ FUNCTIONS = f.read()
+
+
+_ffi = build_ffi(cdef_source=TYPES, verify_source=FUNCTIONS)
+_lib = LazyLibrary(_ffi)
+
+
+if hasattr(hmac, "compare_digest"):
+ def bytes_eq(a, b):
+ if not isinstance(a, bytes) or not isinstance(b, bytes):
+ raise TypeError("a and b must be bytes.")
+
+ return hmac.compare_digest(a, b)
+
+else:
+ def bytes_eq(a, b):
+ if not isinstance(a, bytes) or not isinstance(b, bytes):
+ raise TypeError("a and b must be bytes.")
+
+ return _lib.Cryptography_constant_time_bytes_eq(
+ a, len(a), b, len(b)
+ ) == 1
diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py
new file mode 100644
index 00000000..8c2284e3
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/hashes.py
@@ -0,0 +1,121 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HashBackend
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.HashContext)
+class Hash(object):
+ def __init__(self, algorithm, backend, ctx=None):
+ if not isinstance(backend, HashBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HashBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+ self._algorithm = algorithm
+
+ self._backend = backend
+
+ if ctx is None:
+ self._ctx = self._backend.create_hash_ctx(self.algorithm)
+ else:
+ self._ctx = ctx
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+ self._ctx.update(data)
+
+ def copy(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ return Hash(
+ self.algorithm, backend=self._backend, ctx=self._ctx.copy()
+ )
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class SHA1(object):
+ name = "sha1"
+ digest_size = 20
+ block_size = 64
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class SHA224(object):
+ name = "sha224"
+ digest_size = 28
+ block_size = 64
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class SHA256(object):
+ name = "sha256"
+ digest_size = 32
+ block_size = 64
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class SHA384(object):
+ name = "sha384"
+ digest_size = 48
+ block_size = 128
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class SHA512(object):
+ name = "sha512"
+ digest_size = 64
+ block_size = 128
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class RIPEMD160(object):
+ name = "ripemd160"
+ digest_size = 20
+ block_size = 64
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class Whirlpool(object):
+ name = "whirlpool"
+ digest_size = 64
+ block_size = 64
+
+
+@utils.register_interface(interfaces.HashAlgorithm)
+class MD5(object):
+ name = "md5"
+ digest_size = 16
+ block_size = 64
diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py
new file mode 100644
index 00000000..47a048ff
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/hmac.py
@@ -0,0 +1,78 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HMACBackend
+from cryptography.hazmat.primitives import interfaces
+
+
+@utils.register_interface(interfaces.MACContext)
+@utils.register_interface(interfaces.HashContext)
+class HMAC(object):
+ def __init__(self, key, algorithm, backend, ctx=None):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+ self._algorithm = algorithm
+
+ self._backend = backend
+ self._key = key
+ if ctx is None:
+ self._ctx = self._backend.create_hmac_ctx(key, self.algorithm)
+ else:
+ self._ctx = ctx
+
+ algorithm = utils.read_only_property("_algorithm")
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+ self._ctx.update(data)
+
+ def copy(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ return HMAC(
+ self._key,
+ self.algorithm,
+ backend=self._backend,
+ ctx=self._ctx.copy()
+ )
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ digest = self._ctx.finalize()
+ self._ctx = None
+ return digest
+
+ def verify(self, signature):
+ if not isinstance(signature, bytes):
+ raise TypeError("signature must be bytes.")
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ ctx, self._ctx = self._ctx, None
+ ctx.verify(signature)
diff --git a/src/cryptography/hazmat/primitives/interfaces.py b/src/cryptography/hazmat/primitives/interfaces.py
new file mode 100644
index 00000000..370fd68a
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/interfaces.py
@@ -0,0 +1,499 @@
+# 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 abc
+
+import six
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CipherAlgorithm(object):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this mode (e.g. "AES", "Camellia").
+ """
+
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The size of the key being used as an integer in bits (e.g. 128, 256).
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class BlockCipherAlgorithm(object):
+ @abc.abstractproperty
+ def block_size(self):
+ """
+ The size of a block as an integer in bits (e.g. 64, 128).
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Mode(object):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this mode (e.g. "ECB", "CBC").
+ """
+
+ @abc.abstractmethod
+ def validate_for_algorithm(self, algorithm):
+ """
+ Checks that all the necessary invariants of this (mode, algorithm)
+ combination are met.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ModeWithInitializationVector(object):
+ @abc.abstractproperty
+ def initialization_vector(self):
+ """
+ The value of the initialization vector for this mode as bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ModeWithNonce(object):
+ @abc.abstractproperty
+ def nonce(self):
+ """
+ The value of the nonce for this mode as bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ModeWithAuthenticationTag(object):
+ @abc.abstractproperty
+ def tag(self):
+ """
+ The value of the tag supplied to the constructor of this mode.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CipherContext(object):
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Processes the provided bytes through the cipher and returns the results
+ as bytes.
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ Returns the results of processing the final block as bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AEADCipherContext(object):
+ @abc.abstractmethod
+ def authenticate_additional_data(self, data):
+ """
+ Authenticates the provided bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AEADEncryptionContext(object):
+ @abc.abstractproperty
+ def tag(self):
+ """
+ Returns tag bytes. This is only available after encryption is
+ finalized.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class PaddingContext(object):
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Pads the provided bytes and returns any available data as bytes.
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ Finalize the padding, returns bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class HashAlgorithm(object):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this algorithm (e.g. "sha256", "md5").
+ """
+
+ @abc.abstractproperty
+ def digest_size(self):
+ """
+ The size of the resulting digest in bytes.
+ """
+
+ @abc.abstractproperty
+ def block_size(self):
+ """
+ The internal block size of the hash algorithm in bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class HashContext(object):
+ @abc.abstractproperty
+ def algorithm(self):
+ """
+ A HashAlgorithm that will be used by this context.
+ """
+
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Processes the provided bytes through the hash.
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ Finalizes the hash context and returns the hash digest as bytes.
+ """
+
+ @abc.abstractmethod
+ def copy(self):
+ """
+ Return a HashContext that is a copy of the current context.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RSAPrivateKey(object):
+ @abc.abstractmethod
+ def signer(self, padding, algorithm):
+ """
+ Returns an AsymmetricSignatureContext used for signing data.
+ """
+
+ @abc.abstractmethod
+ def decrypt(self, ciphertext, padding):
+ """
+ Decrypts the provided ciphertext.
+ """
+
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the public modulus.
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The RSAPublicKey associated with this private key.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RSAPrivateKeyWithNumbers(RSAPrivateKey):
+ @abc.abstractmethod
+ def private_numbers(self):
+ """
+ Returns an RSAPrivateNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RSAPublicKey(object):
+ @abc.abstractmethod
+ def verifier(self, signature, padding, algorithm):
+ """
+ Returns an AsymmetricVerificationContext used for verifying signatures.
+ """
+
+ @abc.abstractmethod
+ def encrypt(self, plaintext, padding):
+ """
+ Encrypts the given plaintext.
+ """
+
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the public modulus.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RSAPublicKeyWithNumbers(RSAPublicKey):
+ @abc.abstractmethod
+ def public_numbers(self):
+ """
+ Returns an RSAPublicNumbers
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAParameters(object):
+ @abc.abstractmethod
+ def generate_private_key(self):
+ """
+ Generates and returns a DSAPrivateKey.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAParametersWithNumbers(DSAParameters):
+ @abc.abstractmethod
+ def parameter_numbers(self):
+ """
+ Returns a DSAParameterNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAPrivateKey(object):
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the prime modulus.
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The DSAPublicKey associated with this private key.
+ """
+
+ @abc.abstractmethod
+ def parameters(self):
+ """
+ The DSAParameters object associated with this private key.
+ """
+
+ @abc.abstractmethod
+ def signer(self, signature_algorithm):
+ """
+ Returns an AsymmetricSignatureContext used for signing data.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAPrivateKeyWithNumbers(DSAPrivateKey):
+ @abc.abstractmethod
+ def private_numbers(self):
+ """
+ Returns a DSAPrivateNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAPublicKey(object):
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the prime modulus.
+ """
+
+ @abc.abstractmethod
+ def parameters(self):
+ """
+ The DSAParameters object associated with this public key.
+ """
+
+ @abc.abstractmethod
+ def verifier(self, signature, signature_algorithm):
+ """
+ Returns an AsymmetricVerificationContext used for signing data.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class DSAPublicKeyWithNumbers(DSAPublicKey):
+ @abc.abstractmethod
+ def public_numbers(self):
+ """
+ Returns a DSAPublicNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AsymmetricSignatureContext(object):
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Processes the provided bytes and returns nothing.
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ Returns the signature as bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AsymmetricVerificationContext(object):
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Processes the provided bytes and returns nothing.
+ """
+
+ @abc.abstractmethod
+ def verify(self):
+ """
+ Raises an exception if the bytes provided to update do not match the
+ signature or the signature does not match the public key.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class AsymmetricPadding(object):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this padding (e.g. "PSS", "PKCS1").
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class KeyDerivationFunction(object):
+ @abc.abstractmethod
+ def derive(self, key_material):
+ """
+ Deterministically generates and returns a new key based on the existing
+ key material.
+ """
+
+ @abc.abstractmethod
+ def verify(self, key_material, expected_key):
+ """
+ Checks whether the key generated by the key material matches the
+ expected derived key. Raises an exception if they do not match.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurve(object):
+ @abc.abstractproperty
+ def name(self):
+ """
+ The name of the curve. e.g. secp256r1.
+ """
+
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ The bit length of the base point of the curve.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurveSignatureAlgorithm(object):
+ @abc.abstractproperty
+ def algorithm(self):
+ """
+ The digest algorithm used with this signature.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurvePrivateKey(object):
+ @abc.abstractmethod
+ def signer(self, signature_algorithm):
+ """
+ Returns an AsymmetricSignatureContext used for signing data.
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The EllipticCurvePublicKey for this private key.
+ """
+
+ @abc.abstractproperty
+ def curve(self):
+ """
+ The EllipticCurve that this key is on.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurvePrivateKeyWithNumbers(EllipticCurvePrivateKey):
+ @abc.abstractmethod
+ def private_numbers(self):
+ """
+ Returns an EllipticCurvePrivateNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurvePublicKey(object):
+ @abc.abstractmethod
+ def verifier(self, signature, signature_algorithm):
+ """
+ Returns an AsymmetricVerificationContext used for signing data.
+ """
+
+ @abc.abstractproperty
+ def curve(self):
+ """
+ The EllipticCurve that this key is on.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class EllipticCurvePublicKeyWithNumbers(EllipticCurvePublicKey):
+ @abc.abstractmethod
+ def public_numbers(self):
+ """
+ Returns an EllipticCurvePublicNumbers.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class MACContext(object):
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ Processes the provided bytes.
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ Returns the message authentication code as bytes.
+ """
+
+ @abc.abstractmethod
+ def copy(self):
+ """
+ Return a MACContext that is a copy of the current context.
+ """
+
+ @abc.abstractmethod
+ def verify(self, signature):
+ """
+ Checks if the generated message authentication code matches the
+ signature.
+ """
+
+# DeprecatedIn07
+CMACContext = MACContext
diff --git a/src/cryptography/hazmat/primitives/kdf/__init__.py b/src/cryptography/hazmat/primitives/kdf/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py
new file mode 100644
index 00000000..04d02b26
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py
@@ -0,0 +1,124 @@
+# 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 six
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HMACBackend
+from cryptography.hazmat.primitives import constant_time, hmac, interfaces
+
+
+@utils.register_interface(interfaces.KeyDerivationFunction)
+class HKDF(object):
+ def __init__(self, algorithm, length, salt, info, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ self._algorithm = algorithm
+
+ if not isinstance(salt, bytes) and salt is not None:
+ raise TypeError("salt must be bytes.")
+
+ if salt is None:
+ salt = b"\x00" * (self._algorithm.digest_size // 8)
+
+ self._salt = salt
+
+ self._backend = backend
+
+ self._hkdf_expand = HKDFExpand(self._algorithm, length, info, backend)
+
+ def _extract(self, key_material):
+ h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
+ h.update(key_material)
+ return h.finalize()
+
+ def derive(self, key_material):
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
+
+ return self._hkdf_expand.derive(self._extract(key_material))
+
+ def verify(self, key_material, expected_key):
+ if not constant_time.bytes_eq(self.derive(key_material), expected_key):
+ raise InvalidKey
+
+
+@utils.register_interface(interfaces.KeyDerivationFunction)
+class HKDFExpand(object):
+ def __init__(self, algorithm, length, info, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ self._algorithm = algorithm
+
+ self._backend = backend
+
+ max_length = 255 * (algorithm.digest_size // 8)
+
+ if length > max_length:
+ raise ValueError(
+ "Can not derive keys larger than {0} octets.".format(
+ max_length
+ ))
+
+ self._length = length
+
+ if not isinstance(info, bytes) and info is not None:
+ raise TypeError("info must be bytes.")
+
+ if info is None:
+ info = b""
+
+ self._info = info
+
+ self._used = False
+
+ def _expand(self, key_material):
+ output = [b""]
+ counter = 1
+
+ while (self._algorithm.digest_size // 8) * len(output) < self._length:
+ h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
+ h.update(output[-1])
+ h.update(self._info)
+ h.update(six.int2byte(counter))
+ output.append(h.finalize())
+ counter += 1
+
+ return b"".join(output)[:self._length]
+
+ def derive(self, key_material):
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
+
+ if self._used:
+ raise AlreadyFinalized
+
+ self._used = True
+ return self._expand(key_material)
+
+ def verify(self, key_material, expected_key):
+ if not constant_time.bytes_eq(self.derive(key_material), expected_key):
+ raise InvalidKey
diff --git a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py
new file mode 100644
index 00000000..97b6408c
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py
@@ -0,0 +1,66 @@
+# 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
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend
+from cryptography.hazmat.primitives import constant_time, interfaces
+
+
+@utils.register_interface(interfaces.KeyDerivationFunction)
+class PBKDF2HMAC(object):
+ def __init__(self, algorithm, length, salt, iterations, backend):
+ if not isinstance(backend, PBKDF2HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement PBKDF2HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not backend.pbkdf2_hmac_supported(algorithm):
+ raise UnsupportedAlgorithm(
+ "{0} is not supported for PBKDF2 by this backend.".format(
+ algorithm.name),
+ _Reasons.UNSUPPORTED_HASH
+ )
+ self._used = False
+ self._algorithm = algorithm
+ self._length = length
+ if not isinstance(salt, bytes):
+ raise TypeError("salt must be bytes.")
+ self._salt = salt
+ self._iterations = iterations
+ self._backend = backend
+
+ def derive(self, key_material):
+ if self._used:
+ raise AlreadyFinalized("PBKDF2 instances can only be used once.")
+ self._used = True
+
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
+ return self._backend.derive_pbkdf2_hmac(
+ self._algorithm,
+ self._length,
+ self._salt,
+ self._iterations,
+ key_material
+ )
+
+ def verify(self, key_material, expected_key):
+ derived_key = self.derive(key_material)
+ if not constant_time.bytes_eq(derived_key, expected_key):
+ raise InvalidKey("Keys do not match.")
diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py
new file mode 100644
index 00000000..7aeeff7c
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/padding.py
@@ -0,0 +1,164 @@
+# 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 six
+
+from cryptography import utils
+from cryptography.exceptions import AlreadyFinalized
+from cryptography.hazmat.bindings.utils import LazyLibrary, build_ffi
+from cryptography.hazmat.primitives import interfaces
+
+
+TYPES = """
+uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
+"""
+
+FUNCTIONS = """
+/* Returns the value of the input with the most-significant-bit copied to all
+ of the bits. */
+static uint8_t Cryptography_DUPLICATE_MSB_TO_ALL(uint8_t a) {
+ return (1 - (a >> (sizeof(uint8_t) * 8 - 1))) - 1;
+}
+
+/* This returns 0xFF if a < b else 0x00, but does so in a constant time
+ fashion */
+static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) {
+ a -= b;
+ return Cryptography_DUPLICATE_MSB_TO_ALL(a);
+}
+
+uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data,
+ uint8_t block_len) {
+ uint8_t i;
+ uint8_t pad_size = data[block_len - 1];
+ uint8_t mismatch = 0;
+ for (i = 0; i < block_len; i++) {
+ unsigned int mask = Cryptography_constant_time_lt(i, pad_size);
+ uint8_t b = data[block_len - 1 - i];
+ mismatch |= (mask & (pad_size ^ b));
+ }
+
+ /* Check to make sure the pad_size was within the valid range. */
+ mismatch |= ~Cryptography_constant_time_lt(0, pad_size);
+ mismatch |= Cryptography_constant_time_lt(block_len, pad_size);
+
+ /* Make sure any bits set are copied to the lowest bit */
+ mismatch |= mismatch >> 4;
+ mismatch |= mismatch >> 2;
+ mismatch |= mismatch >> 1;
+ /* Now check the low bit to see if it's set */
+ return (mismatch & 1) == 0;
+}
+"""
+
+
+_ffi = build_ffi(cdef_source=TYPES, verify_source=FUNCTIONS)
+_lib = LazyLibrary(_ffi)
+
+
+class PKCS7(object):
+ def __init__(self, block_size):
+ if not (0 <= block_size < 256):
+ raise ValueError("block_size must be in range(0, 256).")
+
+ if block_size % 8 != 0:
+ raise ValueError("block_size must be a multiple of 8.")
+
+ self.block_size = block_size
+
+ def padder(self):
+ return _PKCS7PaddingContext(self.block_size)
+
+ def unpadder(self):
+ return _PKCS7UnpaddingContext(self.block_size)
+
+
+@utils.register_interface(interfaces.PaddingContext)
+class _PKCS7PaddingContext(object):
+ def __init__(self, block_size):
+ self.block_size = block_size
+ # TODO: more copies than necessary, we should use zero-buffer (#193)
+ self._buffer = b""
+
+ def update(self, data):
+ if self._buffer is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+
+ self._buffer += data
+
+ finished_blocks = len(self._buffer) // (self.block_size // 8)
+
+ result = self._buffer[:finished_blocks * (self.block_size // 8)]
+ self._buffer = self._buffer[finished_blocks * (self.block_size // 8):]
+
+ return result
+
+ def finalize(self):
+ if self._buffer is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ pad_size = self.block_size // 8 - len(self._buffer)
+ result = self._buffer + six.int2byte(pad_size) * pad_size
+ self._buffer = None
+ return result
+
+
+@utils.register_interface(interfaces.PaddingContext)
+class _PKCS7UnpaddingContext(object):
+ def __init__(self, block_size):
+ self.block_size = block_size
+ # TODO: more copies than necessary, we should use zero-buffer (#193)
+ self._buffer = b""
+
+ def update(self, data):
+ if self._buffer is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
+
+ self._buffer += data
+
+ finished_blocks = max(
+ len(self._buffer) // (self.block_size // 8) - 1,
+ 0
+ )
+
+ result = self._buffer[:finished_blocks * (self.block_size // 8)]
+ self._buffer = self._buffer[finished_blocks * (self.block_size // 8):]
+
+ return result
+
+ def finalize(self):
+ if self._buffer is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ if len(self._buffer) != self.block_size // 8:
+ raise ValueError("Invalid padding bytes.")
+
+ valid = _lib.Cryptography_check_pkcs7_padding(
+ self._buffer, self.block_size // 8
+ )
+
+ if not valid:
+ raise ValueError("Invalid padding bytes.")
+
+ pad_size = six.indexbytes(self._buffer, -1)
+ res = self._buffer[:-pad_size]
+ self._buffer = None
+ return res
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
new file mode 100644
index 00000000..0fb560e0
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -0,0 +1,50 @@
+# 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 warnings
+
+from cryptography import utils
+
+
+def load_pem_traditional_openssl_private_key(data, password, backend):
+ warnings.warn(
+ "load_pem_traditional_openssl_private_key is deprecated and will be "
+ "removed in a future version, use load_pem_private_key instead.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+
+ return backend.load_traditional_openssl_pem_private_key(
+ data, password
+ )
+
+
+def load_pem_pkcs8_private_key(data, password, backend):
+ warnings.warn(
+ "load_pem_pkcs8_private_key is deprecated and will be removed in a "
+ "future version, use load_pem_private_key instead.",
+ utils.DeprecatedIn06,
+ stacklevel=2
+ )
+
+ return backend.load_pkcs8_pem_private_key(data, password)
+
+
+def load_pem_private_key(data, password, backend):
+ return backend.load_pem_private_key(data, password)
+
+
+def load_pem_public_key(data, backend):
+ return backend.load_pem_public_key(data)
diff --git a/src/cryptography/hazmat/primitives/src/constant_time.c b/src/cryptography/hazmat/primitives/src/constant_time.c
new file mode 100644
index 00000000..13ac4ab9
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/src/constant_time.c
@@ -0,0 +1,31 @@
+// 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.
+
+uint8_t Cryptography_constant_time_bytes_eq(uint8_t *a, size_t len_a,
+ uint8_t *b, size_t len_b) {
+ size_t i = 0;
+ uint8_t mismatch = 0;
+ if (len_a != len_b) {
+ return 0;
+ }
+ for (i = 0; i < len_a; i++) {
+ mismatch |= a[i] ^ b[i];
+ }
+
+ /* Make sure any bits set are copied to the lowest bit */
+ mismatch |= mismatch >> 4;
+ mismatch |= mismatch >> 2;
+ mismatch |= mismatch >> 1;
+ /* Now check the low bit to see if it's set */
+ return (mismatch & 1) == 0;
+}
diff --git a/src/cryptography/hazmat/primitives/src/constant_time.h b/src/cryptography/hazmat/primitives/src/constant_time.h
new file mode 100644
index 00000000..4f41034e
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/src/constant_time.h
@@ -0,0 +1,16 @@
+// 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.
+
+
+uint8_t Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *,
+ size_t);
diff --git a/src/cryptography/hazmat/primitives/twofactor/__init__.py b/src/cryptography/hazmat/primitives/twofactor/__init__.py
new file mode 100644
index 00000000..2f420574
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/twofactor/__init__.py
@@ -0,0 +1,14 @@
+# 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
diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py
new file mode 100644
index 00000000..d0b476a7
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py
@@ -0,0 +1,69 @@
+# 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 struct
+
+import six
+
+from cryptography.exceptions import (
+ InvalidToken, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HMACBackend
+from cryptography.hazmat.primitives import constant_time, hmac
+from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512
+
+
+class HOTP(object):
+ def __init__(self, key, length, algorithm, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if len(key) < 16:
+ raise ValueError("Key length has to be at least 128 bits.")
+
+ if not isinstance(length, six.integer_types):
+ raise TypeError("Length parameter must be an integer type.")
+
+ if length < 6 or length > 8:
+ raise ValueError("Length of HOTP has to be between 6 to 8.")
+
+ if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
+ raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
+
+ self._key = key
+ self._length = length
+ self._algorithm = algorithm
+ self._backend = backend
+
+ def generate(self, counter):
+ truncated_value = self._dynamic_truncate(counter)
+ hotp = truncated_value % (10 ** self._length)
+ return "{0:0{1}}".format(hotp, self._length).encode()
+
+ def verify(self, hotp, counter):
+ if not constant_time.bytes_eq(self.generate(counter), hotp):
+ raise InvalidToken("Supplied HOTP value does not match.")
+
+ def _dynamic_truncate(self, counter):
+ ctx = hmac.HMAC(self._key, self._algorithm, self._backend)
+ ctx.update(struct.pack(">Q", counter))
+ hmac_value = ctx.finalize()
+
+ offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
+ p = hmac_value[offset:offset + 4]
+ return struct.unpack(">I", p)[0] & 0x7fffffff
diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py
new file mode 100644
index 00000000..854c5163
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/twofactor/totp.py
@@ -0,0 +1,41 @@
+# 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
+
+from cryptography.exceptions import (
+ InvalidToken, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HMACBackend
+from cryptography.hazmat.primitives import constant_time
+from cryptography.hazmat.primitives.twofactor.hotp import HOTP
+
+
+class TOTP(object):
+ def __init__(self, key, length, algorithm, time_step, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ self._time_step = time_step
+ self._hotp = HOTP(key, length, algorithm, backend)
+
+ def generate(self, time):
+ counter = int(time / self._time_step)
+ return self._hotp.generate(counter)
+
+ def verify(self, totp, time):
+ if not constant_time.bytes_eq(self.generate(time), totp):
+ raise InvalidToken("Supplied TOTP value does not match.")
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
new file mode 100644
index 00000000..03c8c0e8
--- /dev/null
+++ b/src/cryptography/utils.py
@@ -0,0 +1,64 @@
+# 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 abc
+import inspect
+import sys
+
+
+DeprecatedIn06 = DeprecationWarning
+
+
+def register_interface(iface):
+ def register_decorator(klass):
+ verify_interface(iface, klass)
+ iface.register(klass)
+ return klass
+ return register_decorator
+
+
+def read_only_property(name):
+ return property(lambda self: getattr(self, name))
+
+
+class InterfaceNotImplemented(Exception):
+ pass
+
+
+def verify_interface(iface, klass):
+ for method in iface.__abstractmethods__:
+ if not hasattr(klass, method):
+ raise InterfaceNotImplemented(
+ "{0} is missing a {1!r} method".format(klass, method)
+ )
+ if isinstance(getattr(iface, method), abc.abstractproperty):
+ # Can't properly verify these yet.
+ continue
+ spec = inspect.getargspec(getattr(iface, method))
+ actual = inspect.getargspec(getattr(klass, method))
+ if spec != actual:
+ raise InterfaceNotImplemented(
+ "{0}.{1}'s signature differs from the expected. Expected: "
+ "{2!r}. Received: {3!r}".format(
+ klass, method, spec, actual
+ )
+ )
+
+
+def bit_length(x):
+ if sys.version_info >= (2, 7):
+ return x.bit_length()
+ else:
+ return len(bin(x)) - (2 + (x <= 0))