aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography/hazmat
diff options
context:
space:
mode:
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r--cryptography/hazmat/backends/interfaces.py46
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py59
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/binding.py7
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/cf.py114
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/secimport.py95
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/secitem.py40
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/seckey.py34
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/seckeychain.py36
-rw-r--r--cryptography/hazmat/bindings/commoncrypto/sectransform.py79
-rw-r--r--cryptography/hazmat/bindings/openssl/asn1.py3
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py2
-rw-r--r--cryptography/hazmat/primitives/asymmetric/ec.py69
-rw-r--r--cryptography/hazmat/primitives/interfaces.py60
-rw-r--r--cryptography/hazmat/primitives/serialization.py6
14 files changed, 640 insertions, 10 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index 97a7a4fd..ba02bbd2 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -196,6 +196,16 @@ class TraditionalOpenSSLSerializationBackend(object):
@six.add_metaclass(abc.ABCMeta)
+class PKCS8SerializationBackend(object):
+ @abc.abstractmethod
+ def load_pkcs8_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 CMACBackend(object):
@abc.abstractmethod
def cmac_algorithm_supported(self, algorithm):
@@ -208,3 +218,39 @@ class CMACBackend(object):
"""
Create a CMACContext for calculating a message authentication code.
"""
+
+
+@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 elliptic_curve_public_key_from_numbers(self, numbers):
+ """
+ Return an EllipticCurvePublicKey provider using the given numbers.
+ """
+
+ @abc.abstractmethod
+ def elliptic_curve_private_key_from_numbers(self, numbers):
+ """
+ Return an EllipticCurvePublicKey provider using the given numbers.
+ """
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index 9387c933..c6bcbaaa 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -26,7 +26,8 @@ from cryptography.exceptions import (
)
from cryptography.hazmat.backends.interfaces import (
CMACBackend, CipherBackend, DSABackend, HMACBackend, HashBackend,
- PBKDF2HMACBackend, RSABackend, TraditionalOpenSSLSerializationBackend
+ PBKDF2HMACBackend, PKCS8SerializationBackend, RSABackend,
+ TraditionalOpenSSLSerializationBackend
)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import hashes, interfaces
@@ -55,6 +56,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError",
@utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(RSABackend)
@utils.register_interface(TraditionalOpenSSLSerializationBackend)
+@utils.register_interface(PKCS8SerializationBackend)
class Backend(object):
"""
OpenSSL API binding interfaces.
@@ -770,6 +772,12 @@ class Backend(object):
return _CMACContext(self, algorithm)
def load_traditional_openssl_pem_private_key(self, data, password):
+ # OpenSSLs API for loading PKCS#8 certs can also load the traditional
+ # format so we just use that for both of them.
+
+ return self.load_pkcs8_pem_private_key(data, password)
+
+ def load_pkcs8_pem_private_key(self, data, password):
mem_bio = self._bytes_to_bio(data)
password_callback, password_func = self._pem_password_cb(password)
@@ -786,10 +794,18 @@ class Backend(object):
if not errors:
raise ValueError("Could not unserialize key data.")
- if errors[0][1:] == (
- self._lib.ERR_LIB_PEM,
- self._lib.PEM_F_PEM_DO_HEADER,
- self._lib.PEM_R_BAD_PASSWORD_READ
+ if (
+ errors[0][1:] == (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_DO_HEADER,
+ self._lib.PEM_R_BAD_PASSWORD_READ
+ )
+ ) or (
+ errors[0][1:] == (
+ self._lib.ERR_LIB_PEM,
+ self._lib.PEM_F_PEM_READ_BIO_PRIVATEKEY,
+ self._lib.PEM_R_BAD_PASSWORD_READ
+ )
):
assert not password
raise TypeError(
@@ -804,13 +820,36 @@ class Backend(object):
"Bad decrypt. Incorrect password?"
)
- elif errors[0][1:] == (
- self._lib.ERR_LIB_PEM,
- self._lib.PEM_F_PEM_GET_EVP_CIPHER_INFO,
- self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
+ 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(
- "PEM data is encrypted with an unsupported cipher")
+ "Unsupported public key algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
else:
assert errors[0][1] in (
diff --git a/cryptography/hazmat/bindings/commoncrypto/binding.py b/cryptography/hazmat/bindings/commoncrypto/binding.py
index 144bb099..ee7378ad 100644
--- a/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ b/cryptography/hazmat/bindings/commoncrypto/binding.py
@@ -25,10 +25,16 @@ class Binding(object):
"""
_module_prefix = "cryptography.hazmat.bindings.commoncrypto."
_modules = [
+ "cf",
"common_digest",
"common_hmac",
"common_key_derivation",
"common_cryptor",
+ "secimport",
+ "secitem",
+ "seckey",
+ "seckeychain",
+ "sectransform",
]
ffi = None
@@ -45,6 +51,7 @@ class Binding(object):
cls.ffi, cls.lib = build_ffi(
module_prefix=cls._module_prefix,
modules=cls._modules,
+ extra_link_args=["-framework", "Security"]
)
@classmethod
diff --git a/cryptography/hazmat/bindings/commoncrypto/cf.py b/cryptography/hazmat/bindings/commoncrypto/cf.py
new file mode 100644
index 00000000..671963a3
--- /dev/null
+++ b/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/cryptography/hazmat/bindings/commoncrypto/secimport.py b/cryptography/hazmat/bindings/commoncrypto/secimport.py
new file mode 100644
index 00000000..add62c79
--- /dev/null
+++ b/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/cryptography/hazmat/bindings/commoncrypto/secitem.py b/cryptography/hazmat/bindings/commoncrypto/secitem.py
new file mode 100644
index 00000000..4d7710bd
--- /dev/null
+++ b/cryptography/hazmat/bindings/commoncrypto/secitem.py
@@ -0,0 +1,40 @@
+# 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 kSecAttrKeyTypeEC;
+const CFTypeRef kSecAttrKeyTypeEC;
+const CFTypeRef kSecUseKeychain;
+"""
+
+FUNCTIONS = """
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/bindings/commoncrypto/seckey.py b/cryptography/hazmat/bindings/commoncrypto/seckey.py
new file mode 100644
index 00000000..38aaece8
--- /dev/null
+++ b/cryptography/hazmat/bindings/commoncrypto/seckey.py
@@ -0,0 +1,34 @@
+# 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 *);
+"""
+
+MACROS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
+
+CONDITIONAL_NAMES = {}
diff --git a/cryptography/hazmat/bindings/commoncrypto/seckeychain.py b/cryptography/hazmat/bindings/commoncrypto/seckeychain.py
new file mode 100644
index 00000000..c045c347
--- /dev/null
+++ b/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/cryptography/hazmat/bindings/commoncrypto/sectransform.py b/cryptography/hazmat/bindings/commoncrypto/sectransform.py
new file mode 100644
index 00000000..d6dbc5f6
--- /dev/null
+++ b/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/cryptography/hazmat/bindings/openssl/asn1.py b/cryptography/hazmat/bindings/openssl/asn1.py
index dfdf1bf5..2edfd2d8 100644
--- a/cryptography/hazmat/bindings/openssl/asn1.py
+++ b/cryptography/hazmat/bindings/openssl/asn1.py
@@ -141,6 +141,9 @@ 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 = """
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index f6456d66..f685e494 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -135,6 +135,7 @@ 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;
@@ -168,6 +169,7 @@ 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;
diff --git a/cryptography/hazmat/primitives/asymmetric/ec.py b/cryptography/hazmat/primitives/asymmetric/ec.py
new file mode 100644
index 00000000..1e49ad7b
--- /dev/null
+++ b/cryptography/hazmat/primitives/asymmetric/ec.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 six
+
+from cryptography.hazmat.primitives import interfaces
+
+
+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
+
+ @property
+ def curve(self):
+ return self._curve
+
+ @property
+ def x(self):
+ return self._x
+
+ @property
+ def y(self):
+ return self._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
+
+ @property
+ def private_value(self):
+ return self._private_value
+
+ @property
+ def public_numbers(self):
+ return self._public_numbers
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index 810a67a4..0dd1d01a 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -489,3 +489,63 @@ class CMACContext(object):
"""
Return a CMACContext that is a copy of the current context.
"""
+
+
+@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 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.
+ """
diff --git a/cryptography/hazmat/primitives/serialization.py b/cryptography/hazmat/primitives/serialization.py
index 38937508..ed73c4c4 100644
--- a/cryptography/hazmat/primitives/serialization.py
+++ b/cryptography/hazmat/primitives/serialization.py
@@ -18,3 +18,9 @@ def load_pem_traditional_openssl_private_key(data, password, backend):
return backend.load_traditional_openssl_pem_private_key(
data, password
)
+
+
+def load_pem_pkcs8_private_key(data, password, backend):
+ return backend.load_pkcs8_pem_private_key(
+ data, password
+ )