aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/_cffi_src/build_commoncrypto.py29
-rw-r--r--src/_cffi_src/build_constant_time.py28
-rw-r--r--src/_cffi_src/build_openssl.py109
-rw-r--r--src/_cffi_src/build_padding.py5
-rw-r--r--src/_cffi_src/commoncrypto/__init__.py5
-rw-r--r--src/_cffi_src/commoncrypto/cf.py105
-rw-r--r--src/_cffi_src/commoncrypto/common_cryptor.py101
-rw-r--r--src/_cffi_src/commoncrypto/common_digest.py60
-rw-r--r--src/_cffi_src/commoncrypto/common_hmac.py39
-rw-r--r--src/_cffi_src/commoncrypto/common_key_derivation.py41
-rw-r--r--src/_cffi_src/commoncrypto/common_symmetric_key_wrap.py37
-rw-r--r--src/_cffi_src/commoncrypto/secimport.py88
-rw-r--r--src/_cffi_src/commoncrypto/seckey.py26
-rw-r--r--src/_cffi_src/commoncrypto/seckeychain.py27
-rw-r--r--src/_cffi_src/commoncrypto/sectransform.py70
-rw-r--r--src/_cffi_src/hazmat_src/constant_time.c22
-rw-r--r--src/_cffi_src/hazmat_src/constant_time.h6
-rw-r--r--src/_cffi_src/hazmat_src/padding.c44
-rw-r--r--src/_cffi_src/hazmat_src/padding.h1
-rw-r--r--src/_cffi_src/openssl/aes.py37
-rw-r--r--src/_cffi_src/openssl/asn1.py117
-rw-r--r--src/_cffi_src/openssl/bignum.py68
-rw-r--r--src/_cffi_src/openssl/bio.py156
-rw-r--r--src/_cffi_src/openssl/callbacks.py168
-rw-r--r--src/_cffi_src/openssl/cmac.py31
-rw-r--r--src/_cffi_src/openssl/cms.py152
-rw-r--r--src/_cffi_src/openssl/conf.py7
-rw-r--r--src/_cffi_src/openssl/crypto.py125
-rw-r--r--src/_cffi_src/openssl/cryptography.py71
-rw-r--r--src/_cffi_src/openssl/ct.py111
-rw-r--r--src/_cffi_src/openssl/dh.py240
-rw-r--r--src/_cffi_src/openssl/dsa.py101
-rw-r--r--src/_cffi_src/openssl/ec.py388
-rw-r--r--src/_cffi_src/openssl/ecdh.py40
-rw-r--r--src/_cffi_src/openssl/ecdsa.py85
-rw-r--r--src/_cffi_src/openssl/engine.py163
-rw-r--r--src/_cffi_src/openssl/err.py294
-rw-r--r--src/_cffi_src/openssl/evp.py359
-rw-r--r--src/_cffi_src/openssl/fips.py (renamed from src/_cffi_src/commoncrypto/secitem.py)23
-rw-r--r--src/_cffi_src/openssl/hmac.py77
-rw-r--r--src/_cffi_src/openssl/nid.py260
-rw-r--r--src/_cffi_src/openssl/objects.py15
-rw-r--r--src/_cffi_src/openssl/ocsp.py170
-rw-r--r--src/_cffi_src/openssl/opensslv.py5
-rw-r--r--src/_cffi_src/openssl/osrandom_engine.py24
-rw-r--r--src/_cffi_src/openssl/pem.py27
-rw-r--r--src/_cffi_src/openssl/pkcs12.py5
-rw-r--r--src/_cffi_src/openssl/pkcs7.py33
-rw-r--r--src/_cffi_src/openssl/rand.py36
-rw-r--r--src/_cffi_src/openssl/rsa.py179
-rw-r--r--src/_cffi_src/openssl/src/osrandom_engine.c659
-rw-r--r--src/_cffi_src/openssl/src/osrandom_engine.h114
-rw-r--r--src/_cffi_src/openssl/ssl.py777
-rw-r--r--src/_cffi_src/openssl/x509.py308
-rw-r--r--src/_cffi_src/openssl/x509_vfy.py208
-rw-r--r--src/_cffi_src/openssl/x509name.py52
-rw-r--r--src/_cffi_src/openssl/x509v3.py113
-rw-r--r--src/_cffi_src/utils.py66
-rw-r--r--src/cryptography/__about__.py4
-rw-r--r--src/cryptography/__init__.py10
-rw-r--r--src/cryptography/exceptions.py21
-rw-r--r--src/cryptography/fernet.py66
-rw-r--r--src/cryptography/hazmat/__init__.py6
-rw-r--r--src/cryptography/hazmat/_der.py156
-rw-r--r--src/cryptography/hazmat/_oid.py72
-rw-r--r--src/cryptography/hazmat/backends/__init__.py28
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/backend.py244
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/ciphers.py193
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/hashes.py55
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/hmac.py59
-rw-r--r--src/cryptography/hazmat/backends/interfaces.py86
-rw-r--r--src/cryptography/hazmat/backends/multibackend.py353
-rw-r--r--src/cryptography/hazmat/backends/openssl/aead.py162
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py2281
-rw-r--r--src/cryptography/hazmat/backends/openssl/ciphers.py194
-rw-r--r--src/cryptography/hazmat/backends/openssl/cmac.py17
-rw-r--r--src/cryptography/hazmat/backends/openssl/decode_asn1.py910
-rw-r--r--src/cryptography/hazmat/backends/openssl/dh.py281
-rw-r--r--src/cryptography/hazmat/backends/openssl/dsa.py199
-rw-r--r--src/cryptography/hazmat/backends/openssl/ec.py268
-rw-r--r--src/cryptography/hazmat/backends/openssl/ed25519.py134
-rw-r--r--src/cryptography/hazmat/backends/openssl/ed448.py137
-rw-r--r--src/cryptography/hazmat/backends/openssl/encode_asn1.py660
-rw-r--r--src/cryptography/hazmat/backends/openssl/hashes.py56
-rw-r--r--src/cryptography/hazmat/backends/openssl/hmac.py49
-rw-r--r--src/cryptography/hazmat/backends/openssl/ocsp.py389
-rw-r--r--src/cryptography/hazmat/backends/openssl/poly1305.py60
-rw-r--r--src/cryptography/hazmat/backends/openssl/rsa.py678
-rw-r--r--src/cryptography/hazmat/backends/openssl/utils.py69
-rw-r--r--src/cryptography/hazmat/backends/openssl/x25519.py118
-rw-r--r--src/cryptography/hazmat/backends/openssl/x448.py106
-rw-r--r--src/cryptography/hazmat/backends/openssl/x509.py975
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/__init__.py5
-rw-r--r--src/cryptography/hazmat/bindings/commoncrypto/binding.py18
-rw-r--r--src/cryptography/hazmat/bindings/openssl/_conditional.py361
-rw-r--r--src/cryptography/hazmat/bindings/openssl/binding.py238
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dh.py60
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dsa.py37
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/ec.py204
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/ed25519.py84
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/ed448.py79
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/padding.py11
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/rsa.py50
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/utils.py56
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/x25519.py73
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/x448.py73
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/__init__.py5
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/aead.py182
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/algorithms.py33
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/base.py63
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/modes.py90
-rw-r--r--src/cryptography/hazmat/primitives/cmac.py10
-rw-r--r--src/cryptography/hazmat/primitives/constant_time.py20
-rw-r--r--src/cryptography/hazmat/primitives/hashes.py122
-rw-r--r--src/cryptography/hazmat/primitives/hmac.py9
-rw-r--r--src/cryptography/hazmat/primitives/interfaces/__init__.py37
-rw-r--r--src/cryptography/hazmat/primitives/kdf/concatkdf.py15
-rw-r--r--src/cryptography/hazmat/primitives/kdf/hkdf.py26
-rw-r--r--src/cryptography/hazmat/primitives/kdf/kbkdf.py145
-rw-r--r--src/cryptography/hazmat/primitives/kdf/pbkdf2.py8
-rw-r--r--src/cryptography/hazmat/primitives/kdf/scrypt.py63
-rw-r--r--src/cryptography/hazmat/primitives/kdf/x963kdf.py68
-rw-r--r--src/cryptography/hazmat/primitives/keywrap.py154
-rw-r--r--src/cryptography/hazmat/primitives/padding.py170
-rw-r--r--src/cryptography/hazmat/primitives/poly1305.py55
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py203
-rw-r--r--src/cryptography/hazmat/primitives/serialization/__init__.py24
-rw-r--r--src/cryptography/hazmat/primitives/serialization/base.py82
-rw-r--r--src/cryptography/hazmat/primitives/serialization/pkcs12.py (renamed from src/cryptography/hazmat/backends/commoncrypto/__init__.py)5
-rw-r--r--src/cryptography/hazmat/primitives/serialization/ssh.py153
-rw-r--r--src/cryptography/hazmat/primitives/twofactor/hotp.py5
-rw-r--r--src/cryptography/hazmat/primitives/twofactor/totp.py5
-rw-r--r--src/cryptography/utils.py112
-rw-r--r--src/cryptography/x509.py1489
-rw-r--r--src/cryptography/x509/__init__.py189
-rw-r--r--src/cryptography/x509/base.py758
-rw-r--r--src/cryptography/x509/certificate_transparency.py46
-rw-r--r--src/cryptography/x509/extensions.py1595
-rw-r--r--src/cryptography/x509/general_name.py360
-rw-r--r--src/cryptography/x509/name.py263
-rw-r--r--src/cryptography/x509/ocsp.py425
-rw-r--r--src/cryptography/x509/oid.py257
142 files changed, 15880 insertions, 8518 deletions
diff --git a/src/_cffi_src/build_commoncrypto.py b/src/_cffi_src/build_commoncrypto.py
deleted file mode 100644
index 1c2692a7..00000000
--- a/src/_cffi_src/build_commoncrypto.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from _cffi_src.utils import build_ffi_for_binding
-
-
-ffi = build_ffi_for_binding(
- module_name="_commoncrypto",
- module_prefix="_cffi_src.commoncrypto.",
- modules=[
- "cf",
- "common_digest",
- "common_hmac",
- "common_key_derivation",
- "common_cryptor",
- "common_symmetric_key_wrap",
- "secimport",
- "secitem",
- "seckey",
- "seckeychain",
- "sectransform",
- ],
- extra_link_args=[
- "-framework", "Security", "-framework", "CoreFoundation"
- ],
-)
diff --git a/src/_cffi_src/build_constant_time.py b/src/_cffi_src/build_constant_time.py
deleted file mode 100644
index 6d9a8f54..00000000
--- a/src/_cffi_src/build_constant_time.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-import os
-import sys
-
-from _cffi_src.utils import build_ffi, extra_link_args
-
-
-with open(os.path.join(
- os.path.dirname(__file__), "hazmat_src/constant_time.h"
-)) as f:
- types = f.read()
-
-with open(os.path.join(
- os.path.dirname(__file__), "hazmat_src/constant_time.c"
-)) as f:
- functions = f.read()
-
-ffi = build_ffi(
- module_name="_constant_time",
- cdef_source=types,
- verify_source=functions,
- extra_link_args=extra_link_args(sys.platform),
-)
diff --git a/src/_cffi_src/build_openssl.py b/src/_cffi_src/build_openssl.py
index dac3e4d8..a09d6d8e 100644
--- a/src/_cffi_src/build_openssl.py
+++ b/src/_cffi_src/build_openssl.py
@@ -6,66 +6,83 @@ from __future__ import absolute_import, division, print_function
import os
import sys
+from distutils import dist
+from distutils.ccompiler import get_default_compiler
+from distutils.command.config import config
-from _cffi_src.utils import build_ffi_for_binding, extra_link_args
+from _cffi_src.utils import (
+ build_ffi_for_binding, compiler_type, extra_link_args
+)
def _get_openssl_libraries(platform):
+ if os.environ.get("CRYPTOGRAPHY_SUPPRESS_LINK_FLAGS", None):
+ return []
# OpenSSL goes by a different library name on different operating systems.
- if platform != "win32":
+ if platform == "win32" and compiler_type() == "msvc":
+ windows_link_legacy_openssl = os.environ.get(
+ "CRYPTOGRAPHY_WINDOWS_LINK_LEGACY_OPENSSL", None
+ )
+ if windows_link_legacy_openssl is None:
+ # Link against the 1.1.0 names
+ # CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+ libs = ["libssl", "libcrypto"]
+ else:
+ # Link against the 1.0.2 and lower names
+ libs = ["libeay32", "ssleay32"]
+ return libs + ["advapi32", "crypt32", "gdi32", "user32", "ws2_32"]
+ else:
+ # darwin, linux, mingw all use this path
# 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_openssl_windows_libraries(link_type)
+ # (https://marc.info/?l=openssl-users&m=135361825921871)
+ # -lpthread required due to usage of pthread an potential
+ # existance of a static part containing e.g. pthread_atfork
+ # (https://github.com/pyca/cryptography/issues/5084)
+ return ["ssl", "crypto", "pthread"]
-def _get_openssl_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"]
+def _extra_compile_args(platform):
+ """
+ We set -Wconversion args here so that we only do Wconversion checks on the
+ code we're compiling and not on cffi itself (as passing -Wconversion in
+ CFLAGS would do). We set no error on sign conversion because some
+ function signatures in OpenSSL have changed from long -> unsigned long
+ in the past. Since that isn't a precision issue we don't care.
+ When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 we can
+ revisit this.
+ """
+ # make sure the compiler used supports the flags to be added
+ is_gcc = False
+ if get_default_compiler() == "unix":
+ d = dist.Distribution()
+ cmd = config(d)
+ cmd._check_compiler()
+ is_gcc = ("gcc" in cmd.compiler.compiler[0] or
+ "clang" in cmd.compiler.compiler[0])
+ if is_gcc or not (platform in ["win32", "hp-ux11", "sunos5"] or
+ platform.startswith("aix")):
+ return ["-Wconversion", "-Wno-error=sign-conversion"]
else:
- raise ValueError(
- "PYCA_WINDOWS_LINK_TYPE must be 'static' or 'dynamic'"
- )
-
-
-_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
-"""
+ return []
ffi = build_ffi_for_binding(
module_name="_openssl",
module_prefix="_cffi_src.openssl.",
modules=[
+ # This goes first so we can define some cryptography-wide symbols.
+ "cryptography",
+
"aes",
"asn1",
"bignum",
"bio",
"cmac",
- "cms",
"conf",
"crypto",
+ "ct",
"dh",
"dsa",
"ec",
@@ -74,12 +91,14 @@ ffi = build_ffi_for_binding(
"engine",
"err",
"evp",
+ "fips",
"hmac",
"nid",
"objects",
+ "ocsp",
"opensslv",
+ "osrandom_engine",
"pem",
- "pkcs7",
"pkcs12",
"rand",
"rsa",
@@ -87,10 +106,18 @@ ffi = build_ffi_for_binding(
"x509",
"x509name",
"x509v3",
- "x509_vfy"
+ "x509_vfy",
+ "pkcs7",
+ "callbacks",
],
- pre_include=_OSX_PRE_INCLUDE,
- post_include=_OSX_POST_INCLUDE,
libraries=_get_openssl_libraries(sys.platform),
- extra_link_args=extra_link_args(sys.platform),
+ # These args are passed here so that we only do Wconversion checks on the
+ # code we're compiling and not on cffi itself (as passing -Wconversion in
+ # CFLAGS would do). We set no error on sign convesrion because some
+ # function signatures in OpenSSL have changed from long -> unsigned long
+ # in the past. Since that isn't a precision issue we don't care.
+ # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 we can
+ # revisit this.
+ extra_compile_args=_extra_compile_args(sys.platform),
+ extra_link_args=extra_link_args(compiler_type()),
)
diff --git a/src/_cffi_src/build_padding.py b/src/_cffi_src/build_padding.py
index 5df93d80..4c5096a1 100644
--- a/src/_cffi_src/build_padding.py
+++ b/src/_cffi_src/build_padding.py
@@ -5,9 +5,8 @@
from __future__ import absolute_import, division, print_function
import os
-import sys
-from _cffi_src.utils import build_ffi, extra_link_args
+from _cffi_src.utils import build_ffi, compiler_type, extra_link_args
with open(os.path.join(
@@ -24,5 +23,5 @@ ffi = build_ffi(
module_name="_padding",
cdef_source=types,
verify_source=functions,
- extra_link_args=extra_link_args(sys.platform),
+ extra_link_args=extra_link_args(compiler_type()),
)
diff --git a/src/_cffi_src/commoncrypto/__init__.py b/src/_cffi_src/commoncrypto/__init__.py
deleted file mode 100644
index 4b540884..00000000
--- a/src/_cffi_src/commoncrypto/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
diff --git a/src/_cffi_src/commoncrypto/cf.py b/src/_cffi_src/commoncrypto/cf.py
deleted file mode 100644
index 77d2d7cc..00000000
--- a/src/_cffi_src/commoncrypto/cf.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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 ... *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/_cffi_src/commoncrypto/common_cryptor.py b/src/_cffi_src/commoncrypto/common_cryptor.py
deleted file mode 100644
index fc6eef91..00000000
--- a/src/_cffi_src/commoncrypto/common_cryptor.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/common_digest.py b/src/_cffi_src/commoncrypto/common_digest.py
deleted file mode 100644
index a76fc508..00000000
--- a/src/_cffi_src/commoncrypto/common_digest.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/common_hmac.py b/src/_cffi_src/commoncrypto/common_hmac.py
deleted file mode 100644
index fcd0c0f4..00000000
--- a/src/_cffi_src/commoncrypto/common_hmac.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/common_key_derivation.py b/src/_cffi_src/commoncrypto/common_key_derivation.py
deleted file mode 100644
index 19525852..00000000
--- a/src/_cffi_src/commoncrypto/common_key_derivation.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/common_symmetric_key_wrap.py b/src/_cffi_src/commoncrypto/common_symmetric_key_wrap.py
deleted file mode 100644
index ea9e459d..00000000
--- a/src/_cffi_src/commoncrypto/common_symmetric_key_wrap.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-INCLUDES = """
-#include <CommonCrypto/CommonSymmetricKeywrap.h>
-"""
-
-TYPES = """
-enum {
- kCCWRAPAES = 1,
-};
-
-typedef uint32_t CCWrappingAlgorithm;
-"""
-
-FUNCTIONS = """
-int CCSymmetricKeyWrap(CCWrappingAlgorithm, const uint8_t *, const size_t,
- const uint8_t *, size_t, const uint8_t *, size_t,
- uint8_t *, size_t *);
-int CCSymmetricKeyUnwrap(CCWrappingAlgorithm algorithm, const uint8_t *,
- const size_t, const uint8_t *, size_t,
- const uint8_t *, size_t, uint8_t *, size_t *);
-size_t CCSymmetricWrappedSize(CCWrappingAlgorithm, size_t);
-size_t CCSymmetricUnwrappedSize(CCWrappingAlgorithm, size_t);
-
-"""
-
-MACROS = """
-"""
-
-CUSTOMIZATIONS = """
-"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/commoncrypto/secimport.py b/src/_cffi_src/commoncrypto/secimport.py
deleted file mode 100644
index 41a799f9..00000000
--- a/src/_cffi_src/commoncrypto/secimport.py
+++ /dev/null
@@ -1,88 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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 *);
-OSStatus SecItemExport(CFTypeRef, SecExternalFormat, SecItemImportExportFlags,
- const SecItemImportExportKeyParameters *, CFDataRef *);
-"""
-
-MACROS = """
-"""
-
-CUSTOMIZATIONS = """
-"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/commoncrypto/seckey.py b/src/_cffi_src/commoncrypto/seckey.py
deleted file mode 100644
index 01d42e6a..00000000
--- a/src/_cffi_src/commoncrypto/seckey.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/seckeychain.py b/src/_cffi_src/commoncrypto/seckeychain.py
deleted file mode 100644
index 6a2cb4be..00000000
--- a/src/_cffi_src/commoncrypto/seckeychain.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/commoncrypto/sectransform.py b/src/_cffi_src/commoncrypto/sectransform.py
deleted file mode 100644
index bed94953..00000000
--- a/src/_cffi_src/commoncrypto/sectransform.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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/_cffi_src/hazmat_src/constant_time.c b/src/_cffi_src/hazmat_src/constant_time.c
deleted file mode 100644
index 0a48fe83..00000000
--- a/src/_cffi_src/hazmat_src/constant_time.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// This file is dual licensed under the terms of the Apache License, Version
-// 2.0, and the BSD License. See the LICENSE file in the root of this
-// repository for complete details.
-
-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/_cffi_src/hazmat_src/constant_time.h b/src/_cffi_src/hazmat_src/constant_time.h
deleted file mode 100644
index 593479f6..00000000
--- a/src/_cffi_src/hazmat_src/constant_time.h
+++ /dev/null
@@ -1,6 +0,0 @@
-// This file is dual licensed under the terms of the Apache License, Version
-// 2.0, and the BSD License. See the LICENSE file in the root of this
-// repository for complete details.
-
-uint8_t Cryptography_constant_time_bytes_eq(uint8_t *, size_t, uint8_t *,
- size_t);
diff --git a/src/_cffi_src/hazmat_src/padding.c b/src/_cffi_src/hazmat_src/padding.c
index 570bad9f..a6e05dee 100644
--- a/src/_cffi_src/hazmat_src/padding.c
+++ b/src/_cffi_src/hazmat_src/padding.c
@@ -4,25 +4,25 @@
/* 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;
+static uint16_t Cryptography_DUPLICATE_MSB_TO_ALL(uint16_t a) {
+ return (1 - (a >> (sizeof(uint16_t) * 8 - 1))) - 1;
}
-/* This returns 0xFF if a < b else 0x00, but does so in a constant time
+/* This returns 0xFFFF if a < b else 0x0000, but does so in a constant time
fashion */
-static uint8_t Cryptography_constant_time_lt(uint8_t a, uint8_t b) {
+static uint16_t Cryptography_constant_time_lt(uint16_t a, uint16_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;
+ uint16_t block_len) {
+ uint16_t i;
+ uint16_t pad_size = data[block_len - 1];
+ uint16_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];
+ uint16_t b = data[block_len - 1 - i];
mismatch |= (mask & (pad_size ^ b));
}
@@ -31,6 +31,32 @@ uint8_t Cryptography_check_pkcs7_padding(const uint8_t *data,
mismatch |= Cryptography_constant_time_lt(block_len, pad_size);
/* Make sure any bits set are copied to the lowest bit */
+ mismatch |= mismatch >> 8;
+ mismatch |= mismatch >> 4;
+ mismatch |= mismatch >> 2;
+ mismatch |= mismatch >> 1;
+ /* Now check the low bit to see if it's set */
+ return (mismatch & 1) == 0;
+}
+
+uint8_t Cryptography_check_ansix923_padding(const uint8_t *data,
+ uint16_t block_len) {
+ uint16_t i;
+ uint16_t pad_size = data[block_len - 1];
+ uint16_t mismatch = 0;
+ /* Skip the first one with the pad size */
+ for (i = 1; i < block_len; i++) {
+ unsigned int mask = Cryptography_constant_time_lt(i, pad_size);
+ uint16_t b = data[block_len - 1 - i];
+ mismatch |= (mask & 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 >> 8;
mismatch |= mismatch >> 4;
mismatch |= mismatch >> 2;
mismatch |= mismatch >> 1;
diff --git a/src/_cffi_src/hazmat_src/padding.h b/src/_cffi_src/hazmat_src/padding.h
index 4d218b1a..fb023c17 100644
--- a/src/_cffi_src/hazmat_src/padding.h
+++ b/src/_cffi_src/hazmat_src/padding.h
@@ -3,3 +3,4 @@
// repository for complete details.
uint8_t Cryptography_check_pkcs7_padding(const uint8_t *, uint8_t);
+uint8_t Cryptography_check_ansix923_padding(const uint8_t *, uint8_t);
diff --git a/src/_cffi_src/openssl/aes.py b/src/_cffi_src/openssl/aes.py
index 15da9b62..5c9dee6d 100644
--- a/src/_cffi_src/openssl/aes.py
+++ b/src/_cffi_src/openssl/aes.py
@@ -9,53 +9,18 @@ INCLUDES = """
"""
TYPES = """
-static const int Cryptography_HAS_AES_WRAP;
-
-struct aes_key_st {
- ...;
-};
-typedef struct aes_key_st AES_KEY;
+typedef ... 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/_cffi_src/openssl/asn1.py b/src/_cffi_src/openssl/asn1.py
index c18708c5..3e148ce0 100644
--- a/src/_cffi_src/openssl/asn1.py
+++ b/src/_cffi_src/openssl/asn1.py
@@ -9,26 +9,8 @@ INCLUDES = """
"""
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 int... time_t;
+
typedef ... ASN1_INTEGER;
struct asn1_string_st {
@@ -40,121 +22,88 @@ struct asn1_string_st {
typedef struct asn1_string_st ASN1_OCTET_STRING;
typedef struct asn1_string_st ASN1_IA5STRING;
-typedef ... ASN1_BIT_STRING;
+typedef struct asn1_string_st ASN1_BIT_STRING;
+typedef struct asn1_string_st ASN1_TIME;
typedef ... ASN1_OBJECT;
-typedef ... ASN1_STRING;
-typedef ... ASN1_TYPE;
-typedef ... ASN1_GENERALIZEDTIME;
-typedef ... ASN1_ENUMERATED;
-typedef ... ASN1_ITEM;
-typedef ... ASN1_VALUE;
-
+typedef struct asn1_string_st ASN1_STRING;
+typedef struct asn1_string_st ASN1_UTF8STRING;
typedef struct {
+ int type;
...;
-} ASN1_TIME;
-typedef ... ASN1_ITEM_EXP;
-
-typedef ... ASN1_UTCTIME;
+} ASN1_TYPE;
+typedef ... ASN1_GENERALIZEDTIME;
+typedef ... ASN1_ENUMERATED;
+typedef ... ASN1_NULL;
static const int V_ASN1_GENERALIZEDTIME;
-static const int MBSTRING_FLAG;
-static const int MBSTRING_ASC;
-static const int MBSTRING_BMP;
static const int MBSTRING_UTF8;
-static const int MBSTRING_UNIV;
"""
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 IA5STRING */
+ASN1_IA5STRING *ASN1_IA5STRING_new(void);
+
/* 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_TIME *ASN1_TIME_set(ASN1_TIME *, time_t);
-
-/* ASN1 UTCTIME */
-ASN1_UTCTIME *ASN1_UTCTIME_new(void);
-void ASN1_UTCTIME_free(ASN1_UTCTIME *);
-int ASN1_UTCTIME_cmp_time_t(const ASN1_UTCTIME *, time_t);
-ASN1_UTCTIME *ASN1_UTCTIME_set(ASN1_UTCTIME *, time_t);
+int ASN1_TIME_set_string(ASN1_TIME *, const char *);
/* ASN1 GENERALIZEDTIME */
-int ASN1_GENERALIZEDTIME_set_string(ASN1_GENERALIZEDTIME *, const char *);
+ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_set(ASN1_GENERALIZEDTIME *, time_t);
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);
-long ASN1_ENUMERATED_get(ASN1_ENUMERATED *);
-ASN1_VALUE *ASN1_item_d2i(ASN1_VALUE **, const unsigned char **, long,
- const ASN1_ITEM *);
int ASN1_BIT_STRING_set_bit(ASN1_BIT_STRING *, int, int);
-"""
+/* These became const ASN1_* in 1.1.0 */
+int ASN1_STRING_type(ASN1_STRING *);
+int ASN1_STRING_to_UTF8(unsigned char **, ASN1_STRING *);
+long ASN1_ENUMERATED_get(ASN1_ENUMERATED *);
+int i2a_ASN1_INTEGER(BIO *, ASN1_INTEGER *);
+
+/* This became const ASN1_TIME in 1.1.0f */
+ASN1_GENERALIZEDTIME *ASN1_TIME_to_generalizedtime(ASN1_TIME *,
+ ASN1_GENERALIZEDTIME **);
+
+ASN1_UTF8STRING *ASN1_UTF8STRING_new(void);
+void ASN1_UTF8STRING_free(ASN1_UTF8STRING *);
-MACROS = """
+ASN1_BIT_STRING *ASN1_BIT_STRING_new(void);
void ASN1_BIT_STRING_free(ASN1_BIT_STRING *);
/* This is not a macro, but is const on some versions of OpenSSL */
int ASN1_BIT_STRING_get_bit(ASN1_BIT_STRING *, int);
-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_TIME_print(BIO *, ASN1_TIME *);
int ASN1_STRING_length(ASN1_STRING *);
-ASN1_STRING *ASN1_STRING_dup(ASN1_STRING *);
-int ASN1_STRING_cmp(ASN1_STRING *, ASN1_STRING *);
-int ASN1_UTCTIME_print(BIO *, ASN1_UTCTIME *);
-
-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 *);
+int ASN1_STRING_set_default_mask_asc(char *);
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 *);
-int ASN1_UTCTIME_check(ASN1_UTCTIME *);
+int i2d_ASN1_TYPE(ASN1_TYPE *, unsigned char **);
+ASN1_TYPE *d2i_ASN1_TYPE(ASN1_TYPE **, const unsigned char **, long);
-/* Not a macro, const on openssl 1.0 */
-int ASN1_STRING_set_default_mask_asc(char *);
+ASN1_NULL *ASN1_NULL_new(void);
"""
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/bignum.py b/src/_cffi_src/openssl/bignum.py
index d974e04e..75101839 100644
--- a/src/_cffi_src/openssl/bignum.py
+++ b/src/_cffi_src/openssl/bignum.py
@@ -10,30 +10,21 @@ INCLUDES = """
TYPES = """
typedef ... BN_CTX;
+typedef ... BN_MONT_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;
+typedef int... BN_ULONG;
"""
FUNCTIONS = """
+#define BN_FLG_CONSTTIME ...
+
+void BN_set_flags(BIGNUM *, int);
+
BIGNUM *BN_new(void);
void BN_free(BIGNUM *);
+void BN_clear_free(BIGNUM *);
+
+int BN_rand_range(BIGNUM *, const BIGNUM *);
BN_CTX *BN_CTX_new(void);
void BN_CTX_free(BN_CTX *);
@@ -42,17 +33,18 @@ void BN_CTX_start(BN_CTX *);
BIGNUM *BN_CTX_get(BN_CTX *);
void BN_CTX_end(BN_CTX *);
-BIGNUM *BN_copy(BIGNUM *, const BIGNUM *);
+BN_MONT_CTX *BN_MONT_CTX_new(void);
+int BN_MONT_CTX_set(BN_MONT_CTX *, const BIGNUM *, BN_CTX *);
+void BN_MONT_CTX_free(BN_MONT_CTX *);
+
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 *);
@@ -60,11 +52,9 @@ BIGNUM *BN_bin2bn(const unsigned char *, int, BIGNUM *);
int BN_num_bits(const BIGNUM *);
int BN_cmp(const BIGNUM *, const BIGNUM *);
+int BN_is_negative(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 *);
@@ -72,34 +62,24 @@ 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 *);
+int BN_mod_exp_mont(BIGNUM *, const BIGNUM *, const BIGNUM *, const BIGNUM *,
+ BN_CTX *, BN_MONT_CTX *);
+int BN_mod_exp_mont_consttime(BIGNUM *, const BIGNUM *, const BIGNUM *,
+ const BIGNUM *, BN_CTX *, BN_MONT_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_num_bytes(const BIGNUM *);
-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 *);
+/* The following 3 prime methods are exposed for Tribler. */
+int BN_generate_prime_ex(BIGNUM *, int, int, const BIGNUM *,
+ const BIGNUM *, BN_GENCB *);
+int BN_is_prime_ex(const BIGNUM *, int, BN_CTX *, BN_GENCB *);
+const int BN_prime_checks_for_size(int);
"""
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/bio.py b/src/_cffi_src/openssl/bio.py
index 6cc1bcb2..8f5a3e6a 100644
--- a/src/_cffi_src/openssl/bio.py
+++ b/src/_cffi_src/openssl/bio.py
@@ -9,164 +9,42 @@ INCLUDES = """
"""
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;
+typedef ... BIO;
+typedef ... BIO_METHOD;
"""
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);
+BIO *BIO_new_dgram(int, 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);
-"""
+/* Added in 1.1.0 */
+int BIO_up_ref(BIO *);
-MACROS = """
-long BIO_set_fd(BIO *, long, int);
-long BIO_get_fd(BIO *, char *);
+BIO *BIO_new(BIO_METHOD *);
+BIO_METHOD *BIO_s_mem(void);
+BIO_METHOD *BIO_s_datagram(void);
+BIO *BIO_new_mem_buf(const void *, int);
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 *);
+void BIO_set_retry_read(BIO *);
+void BIO_clear_retry_flags(BIO *);
"""
CUSTOMIZATIONS = """
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+int BIO_up_ref(BIO *b) {
+ CRYPTO_add(&b->references, 1, CRYPTO_LOCK_BIO);
+ return 1;
+}
+#endif
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/callbacks.py b/src/_cffi_src/openssl/callbacks.py
new file mode 100644
index 00000000..8ee01e0e
--- /dev/null
+++ b/src/_cffi_src/openssl/callbacks.py
@@ -0,0 +1,168 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+#include <openssl/ssl.h>
+#include <openssl/x509.h>
+#include <openssl/x509_vfy.h>
+#include <openssl/crypto.h>
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <Windows.h>
+#include <Wincrypt.h>
+#include <Winsock2.h>
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#endif
+"""
+
+TYPES = """
+typedef struct {
+ char *password;
+ int length;
+ int called;
+ int error;
+ int maxsize;
+} CRYPTOGRAPHY_PASSWORD_DATA;
+"""
+
+FUNCTIONS = """
+int Cryptography_setup_ssl_threads(void);
+int Cryptography_pem_password_cb(char *, int, int, void *);
+"""
+
+CUSTOMIZATIONS = """
+/* This code is derived from the locking code found in the Python _ssl module's
+ locking callback for OpenSSL.
+
+ Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
+
+ It has been subsequently modified to use cross platform locking without
+ using CPython APIs by Armin Rigo of the PyPy project.
+*/
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+#ifdef _WIN32
+typedef CRITICAL_SECTION Cryptography_mutex;
+static __inline void cryptography_mutex_init(Cryptography_mutex *mutex) {
+ InitializeCriticalSection(mutex);
+}
+static __inline void cryptography_mutex_lock(Cryptography_mutex *mutex) {
+ EnterCriticalSection(mutex);
+}
+static __inline void cryptography_mutex_unlock(Cryptography_mutex *mutex) {
+ LeaveCriticalSection(mutex);
+}
+#else
+typedef pthread_mutex_t Cryptography_mutex;
+#define ASSERT_STATUS(call) \
+ if ((call) != 0) { \
+ perror("Fatal error in callback initialization: " #call); \
+ abort(); \
+ }
+static inline void cryptography_mutex_init(Cryptography_mutex *mutex) {
+#if !defined(pthread_mutexattr_default)
+# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
+#endif
+ ASSERT_STATUS(pthread_mutex_init(mutex, pthread_mutexattr_default));
+}
+static inline void cryptography_mutex_lock(Cryptography_mutex *mutex) {
+ ASSERT_STATUS(pthread_mutex_lock(mutex));
+}
+static inline void cryptography_mutex_unlock(Cryptography_mutex *mutex) {
+ ASSERT_STATUS(pthread_mutex_unlock(mutex));
+}
+#endif
+
+
+static int _ssl_locks_count = 0;
+static Cryptography_mutex *_ssl_locks = NULL;
+
+static void _ssl_thread_locking_function(int mode, int n, const char *file,
+ int line) {
+ /* this function is needed to perform locking on shared data
+ structures. (Note that OpenSSL uses a number of global data
+ structures that will be implicitly shared whenever multiple
+ threads use OpenSSL.) Multi-threaded applications will
+ crash at random if it is not set.
+
+ locking_function() must be able to handle up to
+ CRYPTO_num_locks() different mutex locks. It sets the n-th
+ lock if mode & CRYPTO_LOCK, and releases it otherwise.
+
+ file and line are the file number of the function setting the
+ lock. They can be useful for debugging.
+ */
+
+ if ((_ssl_locks == NULL) ||
+ (n < 0) || (n >= _ssl_locks_count)) {
+ return;
+ }
+
+ if (mode & CRYPTO_LOCK) {
+ cryptography_mutex_lock(_ssl_locks + n);
+ } else {
+ cryptography_mutex_unlock(_ssl_locks + n);
+ }
+}
+
+static void init_mutexes(void) {
+ int i;
+ for (i = 0; i < _ssl_locks_count; i++) {
+ cryptography_mutex_init(_ssl_locks + i);
+ }
+}
+
+
+int Cryptography_setup_ssl_threads(void) {
+ if (_ssl_locks == NULL) {
+ _ssl_locks_count = CRYPTO_num_locks();
+ _ssl_locks = calloc(_ssl_locks_count, sizeof(Cryptography_mutex));
+ if (_ssl_locks == NULL) {
+ return 0;
+ }
+ init_mutexes();
+ CRYPTO_set_locking_callback(_ssl_thread_locking_function);
+#ifndef _WIN32
+ pthread_atfork(NULL, NULL, &init_mutexes);
+#endif
+ }
+ return 1;
+}
+#else
+int (*Cryptography_setup_ssl_threads)(void) = NULL;
+#endif
+
+typedef struct {
+ char *password;
+ int length;
+ int called;
+ int error;
+ int maxsize;
+} CRYPTOGRAPHY_PASSWORD_DATA;
+
+int Cryptography_pem_password_cb(char *buf, int size,
+ int rwflag, void *userdata) {
+ /* The password cb is only invoked if OpenSSL decides the private
+ key is encrypted. So this path only occurs if it needs a password */
+ CRYPTOGRAPHY_PASSWORD_DATA *st = (CRYPTOGRAPHY_PASSWORD_DATA *)userdata;
+ st->called += 1;
+ st->maxsize = size;
+ if (st->length == 0) {
+ st->error = -1;
+ return 0;
+ } else if (st->length < size) {
+ memcpy(buf, st->password, st->length);
+ return st->length;
+ } else {
+ st->error = -2;
+ return 0;
+ }
+}
+"""
diff --git a/src/_cffi_src/openssl/cmac.py b/src/_cffi_src/openssl/cmac.py
index c01a449f..557abd1c 100644
--- a/src/_cffi_src/openssl/cmac.py
+++ b/src/_cffi_src/openssl/cmac.py
@@ -5,20 +5,16 @@
from __future__ import absolute_import, division, print_function
INCLUDES = """
-#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+#if !defined(OPENSSL_NO_CMAC)
#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);
@@ -28,29 +24,4 @@ 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/_cffi_src/openssl/cms.py b/src/_cffi_src/openssl/cms.py
deleted file mode 100644
index a43df5d9..00000000
--- a/src/_cffi_src/openssl/cms.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-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;
-
-static const int CMS_TEXT;
-static const int CMS_NOCERTS;
-static const int CMS_NO_CONTENT_VERIFY;
-static const int CMS_NO_ATTR_VERIFY;
-static const int CMS_NOSIGS;
-static const int CMS_NOINTERN;
-static const int CMS_NO_SIGNER_CERT_VERIFY;
-static const int CMS_NOVERIFY;
-static const int CMS_DETACHED;
-static const int CMS_BINARY;
-static const int CMS_NOATTR;
-static const int CMS_NOSMIMECAP;
-static const int CMS_NOOLDMIMETYPE;
-static const int CMS_CRLFEOL;
-static const int CMS_STREAM;
-static const int CMS_NOCRL;
-static const int CMS_PARTIAL;
-static const int CMS_REUSE_DIGEST;
-static const int CMS_USE_KEYID;
-static const int CMS_DEBUG_DECRYPT;
-"""
-
-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;
-const long CMS_TEXT = 0;
-const long CMS_NOCERTS = 0;
-const long CMS_NO_CONTENT_VERIFY = 0;
-const long CMS_NO_ATTR_VERIFY = 0;
-const long CMS_NOSIGS = 0;
-const long CMS_NOINTERN = 0;
-const long CMS_NO_SIGNER_CERT_VERIFY = 0;
-const long CMS_NOVERIFY = 0;
-const long CMS_DETACHED = 0;
-const long CMS_BINARY = 0;
-const long CMS_NOATTR = 0;
-const long CMS_NOSMIMECAP = 0;
-const long CMS_NOOLDMIMETYPE = 0;
-const long CMS_CRLFEOL = 0;
-const long CMS_STREAM = 0;
-const long CMS_NOCRL = 0;
-const long CMS_PARTIAL = 0;
-const long CMS_REUSE_DIGEST = 0;
-const long CMS_USE_KEYID = 0;
-const long CMS_DEBUG_DECRYPT = 0;
-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",
- "CMS_TEXT",
- "CMS_NOCERTS",
- "CMS_NO_CONTENT_VERIFY",
- "CMS_NO_ATTR_VERIFY",
- "CMS_NOSIGS",
- "CMS_NOINTERN",
- "CMS_NO_SIGNER_CERT_VERIFY",
- "CMS_NOVERIFY",
- "CMS_DETACHED",
- "CMS_BINARY",
- "CMS_NOATTR",
- "CMS_NOSMIMECAP",
- "CMS_NOOLDMIMETYPE",
- "CMS_CRLFEOL",
- "CMS_STREAM",
- "CMS_NOCRL",
- "CMS_PARTIAL",
- "CMS_REUSE_DIGEST",
- "CMS_USE_KEYID",
- "CMS_DEBUG_DECRYPT",
- ]
-}
diff --git a/src/_cffi_src/openssl/conf.py b/src/_cffi_src/openssl/conf.py
index cab246f0..9db0162a 100644
--- a/src/_cffi_src/openssl/conf.py
+++ b/src/_cffi_src/openssl/conf.py
@@ -9,18 +9,13 @@ INCLUDES = """
"""
TYPES = """
-typedef ... CONF;
"""
FUNCTIONS = """
void OPENSSL_config(const char *);
+/* This is a macro in 1.1.0 */
void OPENSSL_no_config(void);
"""
-MACROS = """
-"""
-
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/crypto.py b/src/_cffi_src/openssl/crypto.py
index 641e95a8..d8835442 100644
--- a/src/_cffi_src/openssl/crypto.py
+++ b/src/_cffi_src/openssl/crypto.py
@@ -9,50 +9,125 @@ INCLUDES = """
"""
TYPES = """
-typedef ... CRYPTO_THREADID;
+static const long Cryptography_HAS_LOCKING_CALLBACKS;
+static const long Cryptography_HAS_MEM_FUNCTIONS;
+static const long Cryptography_HAS_OPENSSL_CLEANUP;
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 OPENSSL_VERSION;
+static const int OPENSSL_CFLAGS;
+static const int OPENSSL_BUILT_ON;
+static const int OPENSSL_PLATFORM;
+static const int OPENSSL_DIR;
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 OPENSSL_cleanup(void);
+
+/* as of 1.1.0 OpenSSL does its own locking *angelic chorus*. This function
+ is now a noop macro. We can delete this once we drop 1.0.2 support. */
void (*CRYPTO_get_locking_callback(void))(int, int, const char *, int);
-void CRYPTO_lock(int, int, const char *, int);
+/* SSLeay was removed in 1.1.0 */
+unsigned long SSLeay(void);
+const char *SSLeay_version(int);
+/* these functions were added to replace the SSLeay functions in 1.1.0 */
+unsigned long OpenSSL_version_num(void);
+const char *OpenSSL_version(int);
+
+/* this is a macro in 1.1.0 */
+void *OPENSSL_malloc(size_t);
void OPENSSL_free(void *);
-"""
-MACROS = """
-void CRYPTO_add(int *, int, int);
-void CRYPTO_malloc_init(void);
-void CRYPTO_malloc_debug_init(void);
+
+/* Signature changed significantly in 1.1.0, only expose there for sanity */
+int Cryptography_CRYPTO_set_mem_functions(
+ void *(*)(size_t, const char *, int),
+ void *(*)(void *, size_t, const char *, int),
+ void (*)(void *, const char *, int));
+
+void *Cryptography_malloc_wrapper(size_t, const char *, int);
+void *Cryptography_realloc_wrapper(void *, size_t, const char *, int);
+void Cryptography_free_wrapper(void *, const char *, int);
"""
CUSTOMIZATIONS = """
-"""
+/* In 1.1.0 SSLeay has finally been retired. We bidirectionally define the
+ values so you can use either one. This is so we can use the new function
+ names no matter what OpenSSL we're running on, but users on older pyOpenSSL
+ releases won't see issues if they're running OpenSSL 1.1.0 */
+#if !defined(SSLEAY_VERSION)
+# define SSLeay OpenSSL_version_num
+# define SSLeay_version OpenSSL_version
+# define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+# define SSLEAY_VERSION OPENSSL_VERSION
+# define SSLEAY_CFLAGS OPENSSL_CFLAGS
+# define SSLEAY_BUILT_ON OPENSSL_BUILT_ON
+# define SSLEAY_PLATFORM OPENSSL_PLATFORM
+# define SSLEAY_DIR OPENSSL_DIR
+#endif
+#if !defined(OPENSSL_VERSION)
+# define OpenSSL_version_num SSLeay
+# define OpenSSL_version SSLeay_version
+# define OPENSSL_VERSION SSLEAY_VERSION
+# define OPENSSL_CFLAGS SSLEAY_CFLAGS
+# define OPENSSL_BUILT_ON SSLEAY_BUILT_ON
+# define OPENSSL_PLATFORM SSLEAY_PLATFORM
+# define OPENSSL_DIR SSLEAY_DIR
+#endif
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+static const long Cryptography_HAS_LOCKING_CALLBACKS = 1;
+#else
+static const long Cryptography_HAS_LOCKING_CALLBACKS = 0;
+#endif
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+static const long Cryptography_HAS_OPENSSL_CLEANUP = 0;
+
+void (*OPENSSL_cleanup)(void) = NULL;
+
+/* This function has a significantly different signature pre-1.1.0. since it is
+ * for testing only, we don't bother to expose it on older OpenSSLs.
+ */
+static const long Cryptography_HAS_MEM_FUNCTIONS = 0;
+int (*Cryptography_CRYPTO_set_mem_functions)(
+ void *(*)(size_t, const char *, int),
+ void *(*)(void *, size_t, const char *, int),
+ void (*)(void *, const char *, int)) = NULL;
-CONDITIONAL_NAMES = {}
+#else
+static const long Cryptography_HAS_OPENSSL_CLEANUP = 1;
+static const long Cryptography_HAS_MEM_FUNCTIONS = 1;
+
+int Cryptography_CRYPTO_set_mem_functions(
+ void *(*m)(size_t, const char *, int),
+ void *(*r)(void *, size_t, const char *, int),
+ void (*f)(void *, const char *, int)
+) {
+ return CRYPTO_set_mem_functions(m, r, f);
+}
+#endif
+
+void *Cryptography_malloc_wrapper(size_t size, const char *path, int line) {
+ return malloc(size);
+}
+
+void *Cryptography_realloc_wrapper(void *ptr, size_t size, const char *path,
+ int line) {
+ return realloc(ptr, size);
+}
+
+void Cryptography_free_wrapper(void *ptr, const char *path, int line) {
+ free(ptr);
+}
+"""
diff --git a/src/_cffi_src/openssl/cryptography.py b/src/_cffi_src/openssl/cryptography.py
new file mode 100644
index 00000000..cd583313
--- /dev/null
+++ b/src/_cffi_src/openssl/cryptography.py
@@ -0,0 +1,71 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+/* define our OpenSSL API compatibility level to 1.0.1. Any symbols older than
+ that will raise an error during compilation. We can raise this number again
+ after we drop 1.0.2 support in the distant future. */
+#define OPENSSL_API_COMPAT 0x10001000L
+
+#include <openssl/opensslv.h>
+
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define CRYPTOGRAPHY_IS_LIBRESSL 1
+#else
+#define CRYPTOGRAPHY_IS_LIBRESSL 0
+#endif
+
+/*
+ LibreSSL removed e_os2.h from the public headers so we'll only include it
+ if we're using vanilla OpenSSL.
+*/
+#if !CRYPTOGRAPHY_IS_LIBRESSL
+#include <openssl/e_os2.h>
+#endif
+#if defined(_WIN32)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <Wincrypt.h>
+#include <Winsock2.h>
+#endif
+
+#define CRYPTOGRAPHY_OPENSSL_102L_OR_GREATER \
+ (OPENSSL_VERSION_NUMBER >= 0x100020cf && !CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_110_OR_GREATER \
+ (OPENSSL_VERSION_NUMBER >= 0x10100000 && !CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER \
+ (OPENSSL_VERSION_NUMBER >= 0x1010006f && !CRYPTOGRAPHY_IS_LIBRESSL)
+
+#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I \
+ (OPENSSL_VERSION_NUMBER < 0x1000209f || CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 \
+ (OPENSSL_VERSION_NUMBER < 0x10100000 || CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J \
+ (OPENSSL_VERSION_NUMBER < 0x101000af || CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 \
+ (OPENSSL_VERSION_NUMBER < 0x10101000 || CRYPTOGRAPHY_IS_LIBRESSL)
+#define CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B \
+ (OPENSSL_VERSION_NUMBER < 0x10101020 || CRYPTOGRAPHY_IS_LIBRESSL)
+"""
+
+TYPES = """
+static const int CRYPTOGRAPHY_OPENSSL_102L_OR_GREATER;
+static const int CRYPTOGRAPHY_OPENSSL_110_OR_GREATER;
+static const int CRYPTOGRAPHY_OPENSSL_110F_OR_GREATER;
+
+static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I;
+static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111;
+static const int CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B;
+
+static const int CRYPTOGRAPHY_IS_LIBRESSL;
+"""
+
+FUNCTIONS = """
+"""
+
+CUSTOMIZATIONS = """
+"""
diff --git a/src/_cffi_src/openssl/ct.py b/src/_cffi_src/openssl/ct.py
new file mode 100644
index 00000000..71125dd1
--- /dev/null
+++ b/src/_cffi_src/openssl/ct.py
@@ -0,0 +1,111 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+#include <openssl/ct.h>
+
+typedef STACK_OF(SCT) Cryptography_STACK_OF_SCT;
+#endif
+"""
+
+TYPES = """
+static const long Cryptography_HAS_SCT;
+
+typedef enum {
+ SCT_VERSION_NOT_SET,
+ SCT_VERSION_V1
+} sct_version_t;
+
+typedef enum {
+ CT_LOG_ENTRY_TYPE_NOT_SET,
+ CT_LOG_ENTRY_TYPE_X509,
+ CT_LOG_ENTRY_TYPE_PRECERT
+} ct_log_entry_type_t;
+
+typedef enum {
+ SCT_SOURCE_UNKNOWN,
+ SCT_SOURCE_TLS_EXTENSION,
+ SCT_SOURCE_X509V3_EXTENSION,
+ SCT_SOURCE_OCSP_STAPLED_RESPONSE
+} sct_source_t;
+
+typedef ... SCT;
+typedef ... Cryptography_STACK_OF_SCT;
+"""
+
+FUNCTIONS = """
+sct_version_t SCT_get_version(const SCT *);
+
+ct_log_entry_type_t SCT_get_log_entry_type(const SCT *);
+
+size_t SCT_get0_log_id(const SCT *, unsigned char **);
+
+size_t SCT_get0_signature(const SCT *, unsigned char **);
+
+uint64_t SCT_get_timestamp(const SCT *);
+
+int SCT_set_source(SCT *, sct_source_t);
+
+int sk_SCT_num(const Cryptography_STACK_OF_SCT *);
+SCT *sk_SCT_value(const Cryptography_STACK_OF_SCT *, int);
+
+void SCT_LIST_free(Cryptography_STACK_OF_SCT *);
+
+int sk_SCT_push(Cryptography_STACK_OF_SCT *, SCT *);
+Cryptography_STACK_OF_SCT *sk_SCT_new_null(void);
+SCT *SCT_new(void);
+int SCT_set1_log_id(SCT *, unsigned char *, size_t);
+void SCT_set_timestamp(SCT *, uint64_t);
+int SCT_set_version(SCT *, sct_version_t);
+int SCT_set_log_entry_type(SCT *, ct_log_entry_type_t);
+"""
+
+CUSTOMIZATIONS = """
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+static const long Cryptography_HAS_SCT = 1;
+#else
+static const long Cryptography_HAS_SCT = 0;
+
+typedef enum {
+ SCT_VERSION_NOT_SET,
+ SCT_VERSION_V1
+} sct_version_t;
+typedef enum {
+ CT_LOG_ENTRY_TYPE_NOT_SET,
+ CT_LOG_ENTRY_TYPE_X509,
+ CT_LOG_ENTRY_TYPE_PRECERT
+} ct_log_entry_type_t;
+typedef enum {
+ SCT_SOURCE_UNKNOWN,
+ SCT_SOURCE_TLS_EXTENSION,
+ SCT_SOURCE_X509V3_EXTENSION,
+ SCT_SOURCE_OCSP_STAPLED_RESPONSE
+} sct_source_t;
+typedef void SCT;
+typedef void Cryptography_STACK_OF_SCT;
+
+sct_version_t (*SCT_get_version)(const SCT *) = NULL;
+ct_log_entry_type_t (*SCT_get_log_entry_type)(const SCT *) = NULL;
+size_t (*SCT_get0_log_id)(const SCT *, unsigned char **) = NULL;
+size_t (*SCT_get0_signature)(const SCT *, unsigned char **) = NULL;
+uint64_t (*SCT_get_timestamp)(const SCT *) = NULL;
+
+int (*SCT_set_source)(SCT *, sct_source_t) = NULL;
+
+int (*sk_SCT_num)(const Cryptography_STACK_OF_SCT *) = NULL;
+SCT *(*sk_SCT_value)(const Cryptography_STACK_OF_SCT *, int) = NULL;
+
+void (*SCT_LIST_free)(Cryptography_STACK_OF_SCT *) = NULL;
+int (*sk_SCT_push)(Cryptography_STACK_OF_SCT *, SCT *) = NULL;
+Cryptography_STACK_OF_SCT *(*sk_SCT_new_null)(void) = NULL;
+SCT *(*SCT_new)(void) = NULL;
+int (*SCT_set1_log_id)(SCT *, unsigned char *, size_t) = NULL;
+void (*SCT_set_timestamp)(SCT *, uint64_t) = NULL;
+int (*SCT_set_version)(SCT *, sct_version_t) = NULL;
+int (*SCT_set_log_entry_type)(SCT *, ct_log_entry_type_t) = NULL;
+#endif
+"""
diff --git a/src/_cffi_src/openssl/dh.py b/src/_cffi_src/openssl/dh.py
index b66e7196..0e1df23a 100644
--- a/src/_cffi_src/openssl/dh.py
+++ b/src/_cffi_src/openssl/dh.py
@@ -9,44 +9,230 @@ INCLUDES = """
"""
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;
- /* X9.42/RFC 2631 */
- BIGNUM *q;
- BIGNUM *j;
- ...;
-} DH;
+typedef ... DH;
+
+const long DH_NOT_SUITABLE_GENERATOR;
"""
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_check_pub_key(const DH *, const BIGNUM *, 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 *);
-"""
+DH *DHparams_dup(DH *);
+
+/* added in 1.1.0 when the DH struct was opaqued */
+void DH_get0_pqg(const DH *, const BIGNUM **, const BIGNUM **,
+ const BIGNUM **);
+int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
+void DH_get0_key(const DH *, const BIGNUM **, const BIGNUM **);
+int DH_set0_key(DH *, BIGNUM *, BIGNUM *);
-MACROS = """
+int Cryptography_DH_check(const DH *, int *);
int DH_generate_parameters_ex(DH *, int, int, BN_GENCB *);
+DH *d2i_DHparams_bio(BIO *, DH **);
+int i2d_DHparams_bio(BIO *, DH *);
+DH *Cryptography_d2i_DHxparams_bio(BIO *bp, DH **x);
+int Cryptography_i2d_DHxparams_bio(BIO *bp, DH *x);
"""
CUSTOMIZATIONS = """
-"""
+/* These functions were added in OpenSSL 1.1.0 */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+void DH_get0_pqg(const DH *dh,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = dh->p;
+ if (q != NULL)
+ *q = dh->q;
+ if (g != NULL)
+ *g = dh->g;
+}
+
+int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL. q may remain NULL.
+ */
+ if ((dh->p == NULL && p == NULL)
+ || (dh->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(dh->p);
+ dh->p = p;
+ }
+ if (q != NULL) {
+ BN_free(dh->q);
+ dh->q = q;
+ }
+ if (g != NULL) {
+ BN_free(dh->g);
+ dh->g = g;
+ }
+
+ if (q != NULL) {
+ dh->length = BN_num_bits(q);
+ }
+
+ return 1;
+}
+
+void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = dh->pub_key;
+ if (priv_key != NULL)
+ *priv_key = dh->priv_key;
+}
+
+int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in dh is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (dh->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL) {
+ BN_free(dh->pub_key);
+ dh->pub_key = pub_key;
+ }
+ if (priv_key != NULL) {
+ BN_free(dh->priv_key);
+ dh->priv_key = priv_key;
+ }
+
+ return 1;
+}
+#endif
-CONDITIONAL_NAMES = {}
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+#ifndef DH_CHECK_Q_NOT_PRIME
+#define DH_CHECK_Q_NOT_PRIME 0x10
+#endif
+
+#ifndef DH_CHECK_INVALID_Q_VALUE
+#define DH_CHECK_INVALID_Q_VALUE 0x20
+#endif
+
+#ifndef DH_CHECK_INVALID_J_VALUE
+#define DH_CHECK_INVALID_J_VALUE 0x40
+#endif
+
+/* DH_check implementation taken from OpenSSL 1.1.0pre6 */
+
+/*-
+ * Check that p is a safe prime and
+ * if g is 2, 3 or 5, check that it is a suitable generator
+ * where
+ * for 2, p mod 24 == 11
+ * for 3, p mod 12 == 5
+ * for 5, p mod 10 == 3 or 7
+ * should hold.
+ */
+
+int Cryptography_DH_check(const DH *dh, int *ret)
+{
+ int ok = 0, r;
+ BN_CTX *ctx = NULL;
+ BN_ULONG l;
+ BIGNUM *t1 = NULL, *t2 = NULL;
+
+ *ret = 0;
+ ctx = BN_CTX_new();
+ if (ctx == NULL)
+ goto err;
+ BN_CTX_start(ctx);
+ t1 = BN_CTX_get(ctx);
+ if (t1 == NULL)
+ goto err;
+ t2 = BN_CTX_get(ctx);
+ if (t2 == NULL)
+ goto err;
+
+ if (dh->q) {
+ if (BN_cmp(dh->g, BN_value_one()) <= 0)
+ *ret |= DH_NOT_SUITABLE_GENERATOR;
+ else if (BN_cmp(dh->g, dh->p) >= 0)
+ *ret |= DH_NOT_SUITABLE_GENERATOR;
+ else {
+ /* Check g^q == 1 mod p */
+ if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx))
+ goto err;
+ if (!BN_is_one(t1))
+ *ret |= DH_NOT_SUITABLE_GENERATOR;
+ }
+ r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL);
+ if (r < 0)
+ goto err;
+ if (!r)
+ *ret |= DH_CHECK_Q_NOT_PRIME;
+ /* Check p == 1 mod q i.e. q divides p - 1 */
+ if (!BN_div(t1, t2, dh->p, dh->q, ctx))
+ goto err;
+ if (!BN_is_one(t2))
+ *ret |= DH_CHECK_INVALID_Q_VALUE;
+ if (dh->j && BN_cmp(dh->j, t1))
+ *ret |= DH_CHECK_INVALID_J_VALUE;
+
+ } else if (BN_is_word(dh->g, DH_GENERATOR_2)) {
+ l = BN_mod_word(dh->p, 24);
+ if (l == (BN_ULONG)-1)
+ goto err;
+ if (l != 11)
+ *ret |= DH_NOT_SUITABLE_GENERATOR;
+ } else if (BN_is_word(dh->g, DH_GENERATOR_5)) {
+ l = BN_mod_word(dh->p, 10);
+ if (l == (BN_ULONG)-1)
+ goto err;
+ if ((l != 3) && (l != 7))
+ *ret |= DH_NOT_SUITABLE_GENERATOR;
+ } else
+ *ret |= DH_UNABLE_TO_CHECK_GENERATOR;
+
+ r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL);
+ if (r < 0)
+ goto err;
+ if (!r)
+ *ret |= DH_CHECK_P_NOT_PRIME;
+ else if (!dh->q) {
+ if (!BN_rshift1(t1, dh->p))
+ goto err;
+ r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL);
+ if (r < 0)
+ goto err;
+ if (!r)
+ *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
+ }
+ ok = 1;
+ err:
+ if (ctx != NULL) {
+ BN_CTX_end(ctx);
+ BN_CTX_free(ctx);
+ }
+ return (ok);
+}
+#else
+int Cryptography_DH_check(const DH *dh, int *ret) {
+ return DH_check(dh, ret);
+}
+#endif
+
+/* These functions were added in OpenSSL 1.1.0f commit d0c50e80a8 */
+/* Define our own to simplify support across all versions. */
+#if defined(EVP_PKEY_DHX) && EVP_PKEY_DHX != -1
+DH *Cryptography_d2i_DHxparams_bio(BIO *bp, DH **x) {
+ return ASN1_d2i_bio_of(DH, DH_new, d2i_DHxparams, bp, x);
+}
+int Cryptography_i2d_DHxparams_bio(BIO *bp, DH *x) {
+ return ASN1_i2d_bio_of_const(DH, i2d_DHxparams, bp, x);
+}
+#else
+DH *(*Cryptography_d2i_DHxparams_bio)(BIO *bp, DH **x) = NULL;
+int (*Cryptography_i2d_DHxparams_bio)(BIO *bp, DH *x) = NULL;
+#endif
+"""
diff --git a/src/_cffi_src/openssl/dsa.py b/src/_cffi_src/openssl/dsa.py
index 99a685df..938c18fc 100644
--- a/src/_cffi_src/openssl/dsa.py
+++ b/src/_cffi_src/openssl/dsa.py
@@ -9,48 +9,95 @@ INCLUDES = """
"""
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;
+typedef ... DSA;
"""
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);
+DSA *DSAparams_dup(DSA *);
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 = """
+/* added in 1.1.0 to access the opaque struct */
+void DSA_get0_pqg(const DSA *, const BIGNUM **, const BIGNUM **,
+ const BIGNUM **);
+int DSA_set0_pqg(DSA *, BIGNUM *, BIGNUM *, BIGNUM *);
+void DSA_get0_key(const DSA *, const BIGNUM **, const BIGNUM **);
+int DSA_set0_key(DSA *, BIGNUM *, BIGNUM *);
int DSA_generate_parameters_ex(DSA *, int, unsigned char *, int,
int *, unsigned long *, BN_GENCB *);
"""
CUSTOMIZATIONS = """
-"""
+/* These functions were added in OpenSSL 1.1.0 */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+void DSA_get0_pqg(const DSA *d,
+ const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
+{
+ if (p != NULL)
+ *p = d->p;
+ if (q != NULL)
+ *q = d->q;
+ if (g != NULL)
+ *g = d->g;
+}
+int DSA_set0_pqg(DSA *d, BIGNUM *p, BIGNUM *q, BIGNUM *g)
+{
+ /* If the fields p, q and g in d are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((d->p == NULL && p == NULL)
+ || (d->q == NULL && q == NULL)
+ || (d->g == NULL && g == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(d->p);
+ d->p = p;
+ }
+ if (q != NULL) {
+ BN_free(d->q);
+ d->q = q;
+ }
+ if (g != NULL) {
+ BN_free(d->g);
+ d->g = g;
+ }
-CONDITIONAL_NAMES = {}
+ return 1;
+}
+void DSA_get0_key(const DSA *d,
+ const BIGNUM **pub_key, const BIGNUM **priv_key)
+{
+ if (pub_key != NULL)
+ *pub_key = d->pub_key;
+ if (priv_key != NULL)
+ *priv_key = d->priv_key;
+}
+int DSA_set0_key(DSA *d, BIGNUM *pub_key, BIGNUM *priv_key)
+{
+ /* If the field pub_key in d is NULL, the corresponding input
+ * parameters MUST be non-NULL. The priv_key field may
+ * be left NULL.
+ */
+ if (d->pub_key == NULL && pub_key == NULL)
+ return 0;
+
+ if (pub_key != NULL) {
+ BN_free(d->pub_key);
+ d->pub_key = pub_key;
+ }
+ if (priv_key != NULL) {
+ BN_free(d->priv_key);
+ d->priv_key = priv_key;
+ }
+
+ return 1;
+}
+#endif
+"""
diff --git a/src/_cffi_src/openssl/ec.py b/src/_cffi_src/openssl/ec.py
index c5052d36..6432fc22 100644
--- a/src/_cffi_src/openssl/ec.py
+++ b/src/_cffi_src/openssl/ec.py
@@ -5,19 +5,12 @@
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 Cryptography_HAS_EC_1_0_2;
static const int OPENSSL_EC_NAMED_CURVE;
@@ -29,32 +22,18 @@ typedef struct {
int nid;
const char *comment;
} EC_builtin_curve;
-typedef enum { ... } point_conversion_form_t;
+typedef enum {
+ POINT_CONVERSION_COMPRESSED,
+ POINT_CONVERSION_UNCOMPRESSED,
+ ...
+} 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 *);
@@ -63,15 +42,10 @@ int EC_GROUP_get_curve_name(const EC_GROUP *);
size_t EC_get_builtin_curves(EC_builtin_curve *, size_t);
+EC_KEY *EC_KEY_new(void);
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 *);
@@ -79,43 +53,14 @@ 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 *);
@@ -142,18 +87,6 @@ size_t EC_POINT_point2oct(const EC_GROUP *, const EC_POINT *,
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 *);
@@ -165,209 +98,20 @@ 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 *);
const char *EC_curve_nid2nist(int);
+
+int EC_GROUP_get_asn1_flag(const EC_GROUP *);
"""
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)
+#if 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;
@@ -376,121 +120,7 @@ int (*EC_POINT_get_affine_coordinates_GF2m)(const EC_GROUP *,
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
-
-#if defined(OPENSSL_NO_EC) || OPENSSL_VERSION_NUMBER < 0x1000200f || \
- defined(LIBRESSL_VERSION_NUMBER)
-static const long Cryptography_HAS_EC_1_0_2 = 0;
-const char *(*EC_curve_nid2nist)(int) = NULL;
-#else
-static const long Cryptography_HAS_EC_1_0_2 = 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",
- ],
-
- "Cryptography_HAS_EC_1_0_2": [
- "EC_curve_nid2nist",
- ],
-}
diff --git a/src/_cffi_src/openssl/ecdh.py b/src/_cffi_src/openssl/ecdh.py
index 6c7e010c..c73cc9f3 100644
--- a/src/_cffi_src/openssl/ecdh.py
+++ b/src/_cffi_src/openssl/ecdh.py
@@ -5,55 +5,17 @@
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);
+long SSL_CTX_set_ecdh_auto(SSL_CTX *, 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/_cffi_src/openssl/ecdsa.py b/src/_cffi_src/openssl/ecdsa.py
index db21025c..44a778a6 100644
--- a/src/_cffi_src/openssl/ecdsa.py
+++ b/src/_cffi_src/openssl/ecdsa.py
@@ -5,18 +5,13 @@
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 ... ECDSA_SIG;
typedef ... CRYPTO_EX_new;
typedef ... CRYPTO_EX_dup;
@@ -24,98 +19,20 @@ 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/_cffi_src/openssl/engine.py b/src/_cffi_src/openssl/engine.py
index bc5c1906..fa503a26 100644
--- a/src/_cffi_src/openssl/engine.py
+++ b/src/_cffi_src/openssl/engine.py
@@ -9,169 +9,42 @@ INCLUDES = """
"""
TYPES = """
-static const long Cryptography_HAS_ENGINE_CRYPTODEV;
-
-struct rand_meth_st {
- void (*seed)(const void *buf, int num);
- int (*bytes)(unsigned char *buf, int num);
- void (*cleanup)(void);
- void (*add)(const void *buf, int num, double entropy);
- int (*pseudorand)(unsigned char *buf, int num);
- int (*status)(void);
-};
-
typedef ... ENGINE;
-typedef ... RSA_METHOD;
-typedef ... DSA_METHOD;
-typedef ... ECDH_METHOD;
-typedef ... ECDSA_METHOD;
-typedef ... DH_METHOD;
-typedef struct rand_meth_st RAND_METHOD;
-typedef ... STORE_METHOD;
-typedef int(*ENGINE_GEN_INT_FUNC_PTR)(ENGINE*);
-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;
+static const long Cryptography_HAS_ENGINE;
"""
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_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 = """
-void ENGINE_load_cryptodev(void);
"""
CUSTOMIZATIONS = """
-#if defined(LIBRESSL_VERSION_NUMBER)
-static const long Cryptography_HAS_ENGINE_CRYPTODEV = 0;
-void (*ENGINE_load_cryptodev)(void) = NULL;
+#ifdef OPENSSL_NO_ENGINE
+static const long Cryptography_HAS_ENGINE = 0;
+
+ENGINE *(*ENGINE_by_id)(const char *) = NULL;
+int (*ENGINE_init)(ENGINE *) = NULL;
+int (*ENGINE_finish)(ENGINE *) = NULL;
+ENGINE *(*ENGINE_get_default_RAND)(void) = NULL;
+int (*ENGINE_set_default_RAND)(ENGINE *) = NULL;
+void (*ENGINE_unregister_RAND)(ENGINE *) = NULL;
+int (*ENGINE_ctrl_cmd)(ENGINE *, const char *, long, void *,
+ void (*)(void), int) = NULL;
+
+int (*ENGINE_free)(ENGINE *) = NULL;
+const char *(*ENGINE_get_id)(const ENGINE *) = NULL;
+const char *(*ENGINE_get_name)(const ENGINE *) = NULL;
+
#else
-static const long Cryptography_HAS_ENGINE_CRYPTODEV = 1;
+static const long Cryptography_HAS_ENGINE = 1;
#endif
"""
-
-CONDITIONAL_NAMES = {
- "Cryptography_HAS_ENGINE_CRYPTODEV": [
- "ENGINE_load_cryptodev"
- ]
-}
diff --git a/src/_cffi_src/openssl/err.py b/src/_cffi_src/openssl/err.py
index 0ee19c9e..ecdc6e3d 100644
--- a/src/_cffi_src/openssl/err.py
+++ b/src/_cffi_src/openssl/err.py
@@ -9,17 +9,9 @@ INCLUDES = """
"""
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 Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED;
static const int ERR_LIB_DH;
static const int ERR_LIB_EVP;
@@ -28,55 +20,17 @@ 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 ERR_LIB_SSL;
+static const int ERR_LIB_X509;
-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 ERR_R_MALLOC_FAILURE;
+static const int EVP_R_MEMORY_LIMIT_EXCEEDED;
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;
@@ -88,122 +42,46 @@ 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 DH_F_COMPUTE_KEY;
+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;
+static const int ASN1_R_HEADER_TOO_LONG;
static const int DH_R_INVALID_PUBKEY;
-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 EVP_R_CAMELLIA_KEY_SETUP_FAILED;
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;
@@ -215,116 +93,79 @@ 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_BAD_PAD_BYTE_COUNT;
static const int RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE;
+static const int RSA_R_DATA_TOO_LARGE_FOR_MODULUS;
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;
+static const int RSA_R_OAEP_DECODING_ERROR;
+
+static const int SSL_TLSEXT_ERR_OK;
+static const int SSL_TLSEXT_ERR_ALERT_WARNING;
+static const int SSL_TLSEXT_ERR_ALERT_FATAL;
+static const int SSL_TLSEXT_ERR_NOACK;
+
+static const int SSL_AD_CLOSE_NOTIFY;
+static const int SSL_AD_UNEXPECTED_MESSAGE;
+static const int SSL_AD_BAD_RECORD_MAC;
+static const int SSL_AD_RECORD_OVERFLOW;
+static const int SSL_AD_DECOMPRESSION_FAILURE;
+static const int SSL_AD_HANDSHAKE_FAILURE;
+static const int SSL_AD_BAD_CERTIFICATE;
+static const int SSL_AD_UNSUPPORTED_CERTIFICATE;
+static const int SSL_AD_CERTIFICATE_REVOKED;
+static const int SSL_AD_CERTIFICATE_EXPIRED;
+static const int SSL_AD_CERTIFICATE_UNKNOWN;
+static const int SSL_AD_ILLEGAL_PARAMETER;
+static const int SSL_AD_UNKNOWN_CA;
+static const int SSL_AD_ACCESS_DENIED;
+static const int SSL_AD_DECODE_ERROR;
+static const int SSL_AD_DECRYPT_ERROR;
+static const int SSL_AD_PROTOCOL_VERSION;
+static const int SSL_AD_INSUFFICIENT_SECURITY;
+static const int SSL_AD_INTERNAL_ERROR;
+static const int SSL_AD_USER_CANCELLED;
+static const int SSL_AD_NO_RENEGOTIATION;
+
+static const int SSL_AD_UNSUPPORTED_EXTENSION;
+static const int SSL_AD_CERTIFICATE_UNOBTAINABLE;
+static const int SSL_AD_UNRECOGNIZED_NAME;
+static const int SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE;
+static const int SSL_AD_BAD_CERTIFICATE_HASH_VALUE;
+static const int SSL_AD_UNKNOWN_PSK_IDENTITY;
+
+static const int X509_R_CERT_ALREADY_IN_HASH_TABLE;
+static const int X509_R_KEY_VALUES_MISMATCH;
"""
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_clear_error(void);
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;
@@ -332,30 +173,11 @@ static const long Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR = 1;
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"
- ]
-}
+#ifdef EVP_R_MEMORY_LIMIT_EXCEEDED
+static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 1;
+#else
+static const long EVP_R_MEMORY_LIMIT_EXCEEDED = 0;
+static const long Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED = 0;
+#endif
+"""
diff --git a/src/_cffi_src/openssl/evp.py b/src/_cffi_src/openssl/evp.py
index 93aa83de..a0767021 100644
--- a/src/_cffi_src/openssl/evp.py
+++ b/src/_cffi_src/openssl/evp.py
@@ -10,78 +10,69 @@ INCLUDES = """
TYPES = """
typedef ... EVP_CIPHER;
-typedef struct {
- const EVP_CIPHER *cipher;
- ENGINE *engine;
- int encrypt;
- ...;
-} EVP_CIPHER_CTX;
+typedef ... 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_MD_CTX;
+
+typedef ... EVP_PKEY;
typedef ... EVP_PKEY_CTX;
static const int EVP_PKEY_RSA;
static const int EVP_PKEY_DSA;
static const int EVP_PKEY_DH;
+static const int EVP_PKEY_DHX;
static const int EVP_PKEY_EC;
+static const int EVP_PKEY_X25519;
+static const int EVP_PKEY_ED25519;
+static const int EVP_PKEY_X448;
+static const int EVP_PKEY_ED448;
+static const int EVP_PKEY_POLY1305;
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 EVP_CTRL_AEAD_SET_IVLEN;
+static const int EVP_CTRL_AEAD_GET_TAG;
+static const int EVP_CTRL_AEAD_SET_TAG;
-static const int Cryptography_HAS_GCM;
-static const int Cryptography_HAS_PBKDF2_HMAC;
-static const int Cryptography_HAS_PKEY_CTX;
+static const int Cryptography_HAS_SCRYPT;
+static const int Cryptography_HAS_EVP_PKEY_DHX;
+static const int Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint;
+static const int Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY;
+static const long Cryptography_HAS_RAW_KEY;
+static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF;
"""
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);
+const EVP_CIPHER *EVP_CIPHER_CTX_cipher(const EVP_CIPHER_CTX *);
-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 *);
+int EVP_DigestFinalXOF(EVP_MD_CTX *, unsigned char *, size_t);
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_PKEY_encrypt(EVP_PKEY_CTX *, unsigned char *, size_t *,
+ const unsigned char *, size_t);
+int EVP_PKEY_decrypt(EVP_PKEY_CTX *, unsigned char *, size_t *,
+ const unsigned char *, size_t);
+
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 *);
@@ -91,49 +82,70 @@ 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);
-const EVP_MD *EVP_sha1(void);
-const EVP_MD *EVP_ripemd160(void);
-const EVP_MD *EVP_sha224(void);
-const EVP_MD *EVP_sha256(void);
-const EVP_MD *EVP_sha384(void);
-const EVP_MD *EVP_sha512(void);
+int EVP_DigestSignInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *,
+ ENGINE *, EVP_PKEY *);
+int EVP_DigestSignUpdate(EVP_MD_CTX *, const void *, size_t);
+int EVP_DigestSignFinal(EVP_MD_CTX *, unsigned char *, size_t *);
+int EVP_DigestVerifyInit(EVP_MD_CTX *, EVP_PKEY_CTX **, const EVP_MD *,
+ ENGINE *, EVP_PKEY *);
+
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 *);
+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 *);
-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_set1_RSA(EVP_PKEY *, RSA *);
+int EVP_PKEY_set1_DSA(EVP_PKEY *, DSA *);
+int EVP_PKEY_set1_DH(EVP_PKEY *, DH *);
int EVP_PKEY_cmp(const EVP_PKEY *, const EVP_PKEY *);
-EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *);
-"""
+int EVP_PKEY_keygen_init(EVP_PKEY_CTX *);
+int EVP_PKEY_keygen(EVP_PKEY_CTX *, EVP_PKEY **);
+int EVP_PKEY_derive_init(EVP_PKEY_CTX *);
+int EVP_PKEY_derive_set_peer(EVP_PKEY_CTX *, EVP_PKEY *);
+int EVP_PKEY_derive(EVP_PKEY_CTX *, unsigned char *, size_t *);
+int EVP_PKEY_set_type(EVP_PKEY *, int);
+
+int EVP_PKEY_id(const EVP_PKEY *);
+int Cryptography_EVP_PKEY_id(const EVP_PKEY *);
+
+/* in 1.1.0 _create and _destroy were renamed to _new and _free. The following
+ two functions wrap both the old and new functions so we can call them
+ without worrying about what OpenSSL we're running against. */
+EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void);
+void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *);
+/* Added in 1.1.1 */
+int EVP_DigestSign(EVP_MD_CTX *, unsigned char *, size_t *,
+ const unsigned char *, size_t);
+int EVP_DigestVerify(EVP_MD_CTX *, const unsigned char *, size_t,
+ const unsigned char *, size_t);
+/* Added in 1.1.0 */
+size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *, unsigned char **);
+int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *, const unsigned char *,
+ size_t);
+
+/* EVP_PKEY * became const in 1.1.0 */
+int EVP_PKEY_bits(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,
@@ -141,125 +153,126 @@ int PKCS5_PBKDF2_HMAC(const char *, int, const unsigned char *, int, int,
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 *);
-int EVP_PKEY_id(const EVP_PKEY *);
+int EVP_PBE_scrypt(const char *, size_t, const unsigned char *, size_t,
+ uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *,
+ size_t);
-/* 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);
+EVP_PKEY *EVP_PKEY_new_raw_private_key(int, ENGINE *, const unsigned char *,
+ size_t);
+EVP_PKEY *EVP_PKEY_new_raw_public_key(int, ENGINE *, const unsigned char *,
+ size_t);
+int EVP_PKEY_get_raw_private_key(const EVP_PKEY *, unsigned char *, size_t *);
+int EVP_PKEY_get_raw_public_key(const EVP_PKEY *, unsigned char *, size_t *);
"""
CUSTOMIZATIONS = """
-#ifdef EVP_CTRL_GCM_SET_TAG
-const long Cryptography_HAS_GCM = 1;
+#ifdef EVP_PKEY_DHX
+const long Cryptography_HAS_EVP_PKEY_DHX = 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;
+const long Cryptography_HAS_EVP_PKEY_DHX = 0;
+const long EVP_PKEY_DHX = -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_id(const EVP_PKEY *key) {
+ return EVP_PKEY_id(key);
}
-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);
+
+EVP_MD_CTX *Cryptography_EVP_MD_CTX_new(void) {
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+ return EVP_MD_CTX_create();
+#else
+ return EVP_MD_CTX_new();
+#endif
}
+void Cryptography_EVP_MD_CTX_free(EVP_MD_CTX *ctx) {
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+ EVP_MD_CTX_destroy(ctx);
#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;
-int (*EVP_PKEY_id)(const EVP_PKEY *) = NULL;
+ EVP_MD_CTX_free(ctx);
#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;
+}
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || defined(OPENSSL_NO_SCRYPT)
+static const long Cryptography_HAS_SCRYPT = 0;
+int (*EVP_PBE_scrypt)(const char *, size_t, const unsigned char *, size_t,
+ uint64_t, uint64_t, uint64_t, uint64_t, unsigned char *,
+ size_t) = NULL;
+#else
+static const long Cryptography_HAS_SCRYPT = 1;
#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",
- "EVP_PKEY_id",
- ],
- "Cryptography_HAS_EC": [
- "EVP_PKEY_assign_EC_KEY",
- "EVP_PKEY_get1_EC_KEY",
- "EVP_PKEY_set1_EC_KEY",
- ]
-}
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+static const long Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint = 1;
+#else
+static const long Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint = 0;
+size_t (*EVP_PKEY_get1_tls_encodedpoint)(EVP_PKEY *, unsigned char **) = NULL;
+int (*EVP_PKEY_set1_tls_encodedpoint)(EVP_PKEY *, const unsigned char *,
+ size_t) = NULL;
+#endif
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
+static const long Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY = 0;
+static const long Cryptography_HAS_RAW_KEY = 0;
+static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF = 0;
+int (*EVP_DigestFinalXOF)(EVP_MD_CTX *, unsigned char *, size_t) = NULL;
+int (*EVP_DigestSign)(EVP_MD_CTX *, unsigned char *, size_t *,
+ const unsigned char *tbs, size_t) = NULL;
+int (*EVP_DigestVerify)(EVP_MD_CTX *, const unsigned char *, size_t,
+ const unsigned char *, size_t) = NULL;
+EVP_PKEY *(*EVP_PKEY_new_raw_private_key)(int, ENGINE *, const unsigned char *,
+ size_t) = NULL;
+EVP_PKEY *(*EVP_PKEY_new_raw_public_key)(int, ENGINE *, const unsigned char *,
+ size_t) = NULL;
+int (*EVP_PKEY_get_raw_private_key)(const EVP_PKEY *, unsigned char *,
+ size_t *) = NULL;
+int (*EVP_PKEY_get_raw_public_key)(const EVP_PKEY *, unsigned char *,
+ size_t *) = NULL;
+#else
+static const long Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY = 1;
+static const long Cryptography_HAS_RAW_KEY = 1;
+static const long Cryptography_HAS_EVP_DIGESTFINAL_XOF = 1;
+#endif
+
+/* OpenSSL 1.1.0+ does this define for us, but if not present we'll do it */
+#if !defined(EVP_CTRL_AEAD_SET_IVLEN)
+# define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
+#endif
+#if !defined(EVP_CTRL_AEAD_GET_TAG)
+# define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
+#endif
+#if !defined(EVP_CTRL_AEAD_SET_TAG)
+# define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
+#endif
+
+/* This is tied to X25519 support so we reuse the Cryptography_HAS_X25519
+ conditional to remove it. OpenSSL 1.1.0 didn't have this define, but
+ 1.1.1 will when it is released. We can remove this in the distant
+ future when we drop 1.1.0 support. */
+#ifndef EVP_PKEY_X25519
+#define EVP_PKEY_X25519 NID_X25519
+#endif
+
+/* This is tied to X448 support so we reuse the Cryptography_HAS_X448
+ conditional to remove it. OpenSSL 1.1.1 adds this define. We can remove
+ this in the distant future when we drop 1.1.0 support. */
+#ifndef EVP_PKEY_X448
+#define EVP_PKEY_X448 NID_X448
+#endif
+
+/* This is tied to ED25519 support so we reuse the Cryptography_HAS_ED25519
+ conditional to remove it. */
+#ifndef EVP_PKEY_ED25519
+#define EVP_PKEY_ED25519 NID_ED25519
+#endif
+
+/* This is tied to ED448 support so we reuse the Cryptography_HAS_ED448
+ conditional to remove it. */
+#ifndef EVP_PKEY_ED448
+#define EVP_PKEY_ED448 NID_ED448
+#endif
+
+/* This is tied to poly1305 support so we reuse the Cryptography_HAS_POLY1305
+ conditional to remove it. */
+#ifndef EVP_PKEY_POLY1305
+#define EVP_PKEY_POLY1305 NID_poly1305
+#endif
+"""
diff --git a/src/_cffi_src/commoncrypto/secitem.py b/src/_cffi_src/openssl/fips.py
index dd255430..c92bca49 100644
--- a/src/_cffi_src/commoncrypto/secitem.py
+++ b/src/_cffi_src/openssl/fips.py
@@ -5,25 +5,24 @@
from __future__ import absolute_import, division, print_function
INCLUDES = """
-#include <Security/SecItem.h>
+#include <openssl/crypto.h>
"""
TYPES = """
-const CFTypeRef kSecAttrKeyType;
-const CFTypeRef kSecAttrKeySizeInBits;
-const CFTypeRef kSecAttrIsPermanent;
-const CFTypeRef kSecAttrKeyTypeRSA;
-const CFTypeRef kSecAttrKeyTypeDSA;
-const CFTypeRef kSecUseKeychain;
+static const long Cryptography_HAS_FIPS;
"""
FUNCTIONS = """
-"""
-
-MACROS = """
+int FIPS_mode_set(int);
+int FIPS_mode(void);
"""
CUSTOMIZATIONS = """
+#if CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_FIPS = 0;
+int (*FIPS_mode_set)(int) = NULL;
+int (*FIPS_mode)(void) = NULL;
+#else
+static const long Cryptography_HAS_FIPS = 1;
+#endif
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/hmac.py b/src/_cffi_src/openssl/hmac.py
index 86bbdfc2..b006e642 100644
--- a/src/_cffi_src/openssl/hmac.py
+++ b/src/_cffi_src/openssl/hmac.py
@@ -9,77 +9,40 @@ INCLUDES = """
"""
TYPES = """
-typedef struct { ...; } HMAC_CTX;
+typedef ... HMAC_CTX;
"""
FUNCTIONS = """
-void HMAC_CTX_init(HMAC_CTX *);
-void HMAC_CTX_cleanup(HMAC_CTX *);
+int HMAC_Init_ex(HMAC_CTX *, const void *, int, const EVP_MD *, ENGINE *);
+int HMAC_Update(HMAC_CTX *, const unsigned char *, size_t);
+int HMAC_Final(HMAC_CTX *, unsigned char *, unsigned int *);
+int HMAC_CTX_copy(HMAC_CTX *, 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 = """
+HMAC_CTX *Cryptography_HMAC_CTX_new(void);
+void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx);
"""
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);
+HMAC_CTX *Cryptography_HMAC_CTX_new(void) {
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+ return HMAC_CTX_new();
#else
- HMAC_Init_ex(ctx, key, key_len, md, impl);
- return 1;
+ /* This uses OPENSSL_zalloc in 1.1.0, which is malloc + memset */
+ HMAC_CTX *ctx = (HMAC_CTX *)OPENSSL_malloc(sizeof(HMAC_CTX));
+ memset(ctx, 0, sizeof(HMAC_CTX));
+ return ctx;
#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);
+void Cryptography_HMAC_CTX_free(HMAC_CTX *ctx) {
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+ return HMAC_CTX_free(ctx);
#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 (ctx != NULL) {
+ HMAC_CTX_cleanup(ctx);
+ OPENSSL_free(ctx);
}
- 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/_cffi_src/openssl/nid.py b/src/_cffi_src/openssl/nid.py
index c2c0552b..cdd4c0db 100644
--- a/src/_cffi_src/openssl/nid.py
+++ b/src/_cffi_src/openssl/nid.py
@@ -9,240 +9,56 @@ INCLUDES = """
"""
TYPES = """
-static const int Cryptography_HAS_ECDSA_SHA2_NIDS;
+static const int Cryptography_HAS_X25519;
+static const int Cryptography_HAS_X448;
+static const int Cryptography_HAS_ED448;
+static const int Cryptography_HAS_ED25519;
+static const int Cryptography_HAS_POLY1305;
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_X25519;
+static const int NID_X448;
+static const int NID_ED25519;
+static const int NID_ED448;
+static const int NID_poly1305;
-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;
-
-static const int NID_commonName;
-static const int NID_countryName;
-static const int NID_localityName;
-static const int NID_stateOrProvinceName;
-static const int NID_organizationName;
-static const int NID_organizationalUnitName;
-static const int NID_serialNumber;
-static const int NID_surname;
-static const int NID_givenName;
-static const int NID_title;
-static const int NID_generationQualifier;
-static const int NID_dnQualifier;
-static const int NID_pseudonym;
-static const int NID_domainComponent;
-static const int NID_pkcs9_emailAddress;
"""
FUNCTIONS = """
"""
-MACROS = """
-"""
-
CUSTOMIZATIONS = """
-/* OpenSSL 0.9.8g+ */
-#if OPENSSL_VERSION_NUMBER >= 0x0090807fL
-static const long Cryptography_HAS_ECDSA_SHA2_NIDS = 1;
+#ifndef NID_X25519
+static const long Cryptography_HAS_X25519 = 0;
+static const int NID_X25519 = 0;
#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;
+static const long Cryptography_HAS_X25519 = 1;
+#endif
+#ifndef NID_ED25519
+static const long Cryptography_HAS_ED25519 = 0;
+static const int NID_ED25519 = 0;
+#else
+static const long Cryptography_HAS_ED25519 = 1;
+#endif
+#ifndef NID_X448
+static const long Cryptography_HAS_X448 = 0;
+static const int NID_X448 = 0;
+#else
+static const long Cryptography_HAS_X448 = 1;
+#endif
+#ifndef NID_ED448
+static const long Cryptography_HAS_ED448 = 0;
+static const int NID_ED448 = 0;
+#else
+static const long Cryptography_HAS_ED448 = 1;
+#endif
+#ifndef NID_poly1305
+static const long Cryptography_HAS_POLY1305 = 0;
+static const int NID_poly1305 = 0;
+#else
+static const long Cryptography_HAS_POLY1305 = 1;
#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/_cffi_src/openssl/objects.py b/src/_cffi_src/openssl/objects.py
index 9c480b37..265ac75c 100644
--- a/src/_cffi_src/openssl/objects.py
+++ b/src/_cffi_src/openssl/objects.py
@@ -9,6 +9,14 @@ INCLUDES = """
"""
TYPES = """
+typedef struct {
+ int type;
+ int alias;
+ const char *name;
+ const char *data;
+} OBJ_NAME;
+
+static const long OBJ_NAME_TYPE_MD_METH;
"""
FUNCTIONS = """
@@ -24,13 +32,10 @@ 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_NAME_do_all(int, void (*) (const OBJ_NAME *, void *), void *);
+/* OBJ_cleanup became a macro in 1.1.0 */
void OBJ_cleanup(void);
"""
-MACROS = """
-"""
-
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/ocsp.py b/src/_cffi_src/openssl/ocsp.py
new file mode 100644
index 00000000..829314a3
--- /dev/null
+++ b/src/_cffi_src/openssl/ocsp.py
@@ -0,0 +1,170 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+INCLUDES = """
+#include <openssl/ocsp.h>
+"""
+
+TYPES = """
+typedef ... OCSP_REQUEST;
+typedef ... OCSP_ONEREQ;
+typedef ... OCSP_RESPONSE;
+typedef ... OCSP_BASICRESP;
+typedef ... OCSP_SINGLERESP;
+typedef ... OCSP_CERTID;
+typedef ... OCSP_RESPDATA;
+static const long OCSP_NOCERTS;
+static const long OCSP_RESPID_KEY;
+"""
+
+FUNCTIONS = """
+int OCSP_response_status(OCSP_RESPONSE *);
+OCSP_BASICRESP *OCSP_response_get1_basic(OCSP_RESPONSE *);
+int OCSP_BASICRESP_get_ext_count(OCSP_BASICRESP *);
+const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *);
+Cryptography_STACK_OF_X509 *OCSP_resp_get0_certs(const OCSP_BASICRESP *);
+const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at(
+ const OCSP_BASICRESP *);
+const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *);
+int OCSP_resp_get0_id(const OCSP_BASICRESP *, const ASN1_OCTET_STRING **,
+ const X509_NAME **);
+const X509_ALGOR *OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *);
+const OCSP_RESPDATA *OCSP_resp_get0_respdata(const OCSP_BASICRESP *);
+X509_EXTENSION *OCSP_BASICRESP_get_ext(OCSP_BASICRESP *, int);
+int OCSP_resp_count(OCSP_BASICRESP *);
+OCSP_SINGLERESP *OCSP_resp_get0(OCSP_BASICRESP *, int);
+int OCSP_SINGLERESP_get_ext_count(OCSP_SINGLERESP *);
+X509_EXTENSION *OCSP_SINGLERESP_get_ext(OCSP_SINGLERESP *, int);
+
+int OCSP_single_get0_status(OCSP_SINGLERESP *, int *, ASN1_GENERALIZEDTIME **,
+ ASN1_GENERALIZEDTIME **, ASN1_GENERALIZEDTIME **);
+
+int OCSP_REQUEST_get_ext_count(OCSP_REQUEST *);
+X509_EXTENSION *OCSP_REQUEST_get_ext(OCSP_REQUEST *, int);
+int OCSP_request_onereq_count(OCSP_REQUEST *);
+OCSP_ONEREQ *OCSP_request_onereq_get0(OCSP_REQUEST *, int);
+int OCSP_ONEREQ_get_ext_count(OCSP_ONEREQ *);
+X509_EXTENSION *OCSP_ONEREQ_get_ext(OCSP_ONEREQ *, int);
+OCSP_CERTID *OCSP_onereq_get0_id(OCSP_ONEREQ *);
+OCSP_ONEREQ *OCSP_request_add0_id(OCSP_REQUEST *, OCSP_CERTID *);
+OCSP_CERTID *OCSP_cert_to_id(const EVP_MD *, const X509 *, const X509 *);
+void OCSP_CERTID_free(OCSP_CERTID *);
+
+
+OCSP_BASICRESP *OCSP_BASICRESP_new(void);
+void OCSP_BASICRESP_free(OCSP_BASICRESP *);
+OCSP_SINGLERESP *OCSP_basic_add1_status(OCSP_BASICRESP *, OCSP_CERTID *, int,
+ int, ASN1_TIME *, ASN1_TIME *,
+ ASN1_TIME *);
+int OCSP_basic_add1_nonce(OCSP_BASICRESP *, unsigned char *, int);
+int OCSP_basic_add1_cert(OCSP_BASICRESP *, X509 *);
+int OCSP_BASICRESP_add_ext(OCSP_BASICRESP *, X509_EXTENSION *, int);
+int OCSP_basic_sign(OCSP_BASICRESP *, X509 *, EVP_PKEY *, const EVP_MD *,
+ Cryptography_STACK_OF_X509 *, unsigned long);
+OCSP_RESPONSE *OCSP_response_create(int, OCSP_BASICRESP *);
+void OCSP_RESPONSE_free(OCSP_RESPONSE *);
+
+OCSP_REQUEST *OCSP_REQUEST_new(void);
+void OCSP_REQUEST_free(OCSP_REQUEST *);
+int OCSP_request_add1_nonce(OCSP_REQUEST *, unsigned char *, int);
+int OCSP_REQUEST_add_ext(OCSP_REQUEST *, X509_EXTENSION *, int);
+int OCSP_id_get0_info(ASN1_OCTET_STRING **, ASN1_OBJECT **,
+ ASN1_OCTET_STRING **, ASN1_INTEGER **, OCSP_CERTID *);
+OCSP_REQUEST *d2i_OCSP_REQUEST_bio(BIO *, OCSP_REQUEST **);
+OCSP_RESPONSE *d2i_OCSP_RESPONSE_bio(BIO *, OCSP_RESPONSE **);
+int i2d_OCSP_REQUEST_bio(BIO *, OCSP_REQUEST *);
+int i2d_OCSP_RESPONSE_bio(BIO *, OCSP_RESPONSE *);
+int i2d_OCSP_RESPDATA(OCSP_RESPDATA *, unsigned char **);
+"""
+
+CUSTOMIZATIONS = """
+#if ( \
+ CRYPTOGRAPHY_OPENSSL_110_OR_GREATER && \
+ CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J \
+ )
+/* These structs come from ocsp_lcl.h and are needed to de-opaque the struct
+ for the getters in OpenSSL 1.1.0 through 1.1.0i */
+struct ocsp_responder_id_st {
+ int type;
+ union {
+ X509_NAME *byName;
+ ASN1_OCTET_STRING *byKey;
+ } value;
+};
+struct ocsp_response_data_st {
+ ASN1_INTEGER *version;
+ OCSP_RESPID responderId;
+ ASN1_GENERALIZEDTIME *producedAt;
+ STACK_OF(OCSP_SINGLERESP) *responses;
+ STACK_OF(X509_EXTENSION) *responseExtensions;
+};
+struct ocsp_basic_response_st {
+ OCSP_RESPDATA tbsResponseData;
+ X509_ALGOR signatureAlgorithm;
+ ASN1_BIT_STRING *signature;
+ STACK_OF(X509) *certs;
+};
+#endif
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+/* These functions are all taken from ocsp_cl.c in OpenSSL 1.1.0 */
+const OCSP_CERTID *OCSP_SINGLERESP_get0_id(const OCSP_SINGLERESP *single)
+{
+ return single->certId;
+}
+const Cryptography_STACK_OF_X509 *OCSP_resp_get0_certs(
+ const OCSP_BASICRESP *bs)
+{
+ return bs->certs;
+}
+int OCSP_resp_get0_id(const OCSP_BASICRESP *bs,
+ const ASN1_OCTET_STRING **pid,
+ const X509_NAME **pname)
+{
+ const OCSP_RESPID *rid = bs->tbsResponseData->responderId;
+
+ if (rid->type == V_OCSP_RESPID_NAME) {
+ *pname = rid->value.byName;
+ *pid = NULL;
+ } else if (rid->type == V_OCSP_RESPID_KEY) {
+ *pid = rid->value.byKey;
+ *pname = NULL;
+ } else {
+ return 0;
+ }
+ return 1;
+}
+const ASN1_GENERALIZEDTIME *OCSP_resp_get0_produced_at(
+ const OCSP_BASICRESP* bs)
+{
+ return bs->tbsResponseData->producedAt;
+}
+const ASN1_OCTET_STRING *OCSP_resp_get0_signature(const OCSP_BASICRESP *bs)
+{
+ return bs->signature;
+}
+#endif
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110J
+const X509_ALGOR *OCSP_resp_get0_tbs_sigalg(const OCSP_BASICRESP *bs)
+{
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+ return bs->signatureAlgorithm;
+#else
+ return &bs->signatureAlgorithm;
+#endif
+}
+
+const OCSP_RESPDATA *OCSP_resp_get0_respdata(const OCSP_BASICRESP *bs)
+{
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+ return bs->tbsResponseData;
+#else
+ return &bs->tbsResponseData;
+#endif
+}
+#endif
+"""
diff --git a/src/_cffi_src/openssl/opensslv.py b/src/_cffi_src/openssl/opensslv.py
index e6c5f269..9b0c6893 100644
--- a/src/_cffi_src/openssl/opensslv.py
+++ b/src/_cffi_src/openssl/opensslv.py
@@ -18,10 +18,5 @@ static const char *const OPENSSL_VERSION_TEXT;
FUNCTIONS = """
"""
-MACROS = """
-"""
-
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/osrandom_engine.py b/src/_cffi_src/openssl/osrandom_engine.py
new file mode 100644
index 00000000..ed1068ef
--- /dev/null
+++ b/src/_cffi_src/openssl/osrandom_engine.py
@@ -0,0 +1,24 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import os
+
+HERE = os.path.dirname(os.path.abspath(__file__))
+
+with open(os.path.join(HERE, "src/osrandom_engine.h")) as f:
+ INCLUDES = f.read()
+
+TYPES = """
+static const char *const Cryptography_osrandom_engine_name;
+static const char *const Cryptography_osrandom_engine_id;
+"""
+
+FUNCTIONS = """
+int Cryptography_add_osrandom_engine(void);
+"""
+
+with open(os.path.join(HERE, "src/osrandom_engine.c")) as f:
+ CUSTOMIZATIONS = f.read()
diff --git a/src/_cffi_src/openssl/pem.py b/src/_cffi_src/openssl/pem.py
index 8ec3fefd..09b523d6 100644
--- a/src/_cffi_src/openssl/pem.py
+++ b/src/_cffi_src/openssl/pem.py
@@ -51,10 +51,6 @@ int PEM_write_bio_PKCS7(BIO *, PKCS7 *);
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 *);
@@ -63,36 +59,21 @@ 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 = """
int PEM_write_bio_ECPrivateKey(BIO *, EC_KEY *, const EVP_CIPHER *,
unsigned char *, int, pem_password_cb *,
void *);
+int PEM_write_bio_DHparams(BIO *, DH *);
+int PEM_write_bio_DHxparams(BIO *, DH *);
"""
CUSTOMIZATIONS = """
-// Cryptography_HAS_EC is provided by ec.py so we don't need to define it here
-#ifdef OPENSSL_NO_EC
-int (*PEM_write_bio_ECPrivateKey)(BIO *, EC_KEY *, const EVP_CIPHER *,
- unsigned char *, int, pem_password_cb *,
- void *) = NULL;
+#if !defined(EVP_PKEY_DHX) || EVP_PKEY_DHX == -1
+int (*PEM_write_bio_DHxparams)(BIO *, DH *) = NULL;
#endif
-
"""
-
-CONDITIONAL_NAMES = {
- "Cryptography_HAS_EC": [
- "PEM_write_bio_ECPrivateKey"
- ]
-}
diff --git a/src/_cffi_src/openssl/pkcs12.py b/src/_cffi_src/openssl/pkcs12.py
index fa7564ac..21a8481f 100644
--- a/src/_cffi_src/openssl/pkcs12.py
+++ b/src/_cffi_src/openssl/pkcs12.py
@@ -17,9 +17,6 @@ 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 *,
@@ -28,5 +25,3 @@ PKCS12 *PKCS12_create(char *, char *, EVP_PKEY *, X509 *,
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/pkcs7.py b/src/_cffi_src/openssl/pkcs7.py
index df82afef..1bece5b7 100644
--- a/src/_cffi_src/openssl/pkcs7.py
+++ b/src/_cffi_src/openssl/pkcs7.py
@@ -10,7 +10,33 @@ INCLUDES = """
TYPES = """
typedef struct {
+ Cryptography_STACK_OF_X509 *cert;
+ Cryptography_STACK_OF_X509_CRL *crl;
+ ...;
+} PKCS7_SIGNED;
+
+typedef struct {
+ Cryptography_STACK_OF_X509 *cert;
+ Cryptography_STACK_OF_X509_CRL *crl;
+ ...;
+} PKCS7_SIGN_ENVELOPE;
+
+typedef ... PKCS7_DIGEST;
+typedef ... PKCS7_ENCRYPT;
+typedef ... PKCS7_ENVELOPE;
+
+typedef struct {
ASN1_OBJECT *type;
+ union {
+ char *ptr;
+ ASN1_OCTET_STRING *data;
+ PKCS7_SIGNED *sign;
+ PKCS7_ENVELOPE *enveloped;
+ PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
+ PKCS7_DIGEST *digest;
+ PKCS7_ENCRYPT *encrypted;
+ ASN1_TYPE *other;
+ } d;
...;
} PKCS7;
@@ -44,15 +70,14 @@ Cryptography_STACK_OF_X509 *PKCS7_get0_signers(PKCS7 *,
PKCS7 *PKCS7_encrypt(Cryptography_STACK_OF_X509 *, BIO *,
const EVP_CIPHER *, int);
int PKCS7_decrypt(PKCS7 *, EVP_PKEY *, X509 *, BIO *, int);
-"""
-MACROS = """
+BIO *PKCS7_dataInit(PKCS7 *, BIO *);
+int PKCS7_type_is_encrypted(PKCS7 *);
int PKCS7_type_is_signed(PKCS7 *);
int PKCS7_type_is_enveloped(PKCS7 *);
int PKCS7_type_is_signedAndEnveloped(PKCS7 *);
int PKCS7_type_is_data(PKCS7 *);
+int PKCS7_type_is_digest(PKCS7 *);
"""
CUSTOMIZATIONS = ""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/rand.py b/src/_cffi_src/openssl/rand.py
index 6330482c..c0cd6836 100644
--- a/src/_cffi_src/openssl/rand.py
+++ b/src/_cffi_src/openssl/rand.py
@@ -9,43 +9,23 @@ INCLUDES = """
"""
TYPES = """
+typedef ... RAND_METHOD;
+
static const long Cryptography_HAS_EGD;
"""
FUNCTIONS = """
-void ERR_load_RAND_strings(void);
-void RAND_seed(const void *, int);
+int RAND_set_rand_method(const RAND_METHOD *);
void RAND_add(const void *, int, double);
int RAND_status(void);
-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 = """
-int RAND_egd(const char *);
-int RAND_egd_bytes(const char *, int);
-int RAND_query_egd_bytes(const char *, unsigned char *, int);
+/* ERR_load_RAND_strings started returning an int in 1.1.0. Unfortunately we
+ can't declare a conditional signature like that. Since it always returns
+ 1 we'll just lie about the signature to preserve compatibility for
+ pyOpenSSL (which calls this in its rand.py as of mid-2016) */
+void ERR_load_RAND_strings(void);
"""
CUSTOMIZATIONS = """
-#if defined(LIBRESSL_VERSION_NUMBER)
static const long Cryptography_HAS_EGD = 0;
-int (*RAND_egd)(const char *) = NULL;
-int (*RAND_egd_bytes)(const char *, int) = NULL;
-int (*RAND_query_egd_bytes)(const char *, unsigned char *, int) = NULL;
-#else
-static const long Cryptography_HAS_EGD = 1;
-#endif
"""
-
-CONDITIONAL_NAMES = {
- "Cryptography_HAS_EGD": [
- "RAND_egd",
- "RAND_egd_bytes",
- "RAND_query_egd_bytes",
- ]
-}
diff --git a/src/_cffi_src/openssl/rsa.py b/src/_cffi_src/openssl/rsa.py
index 8bac7895..4b915463 100644
--- a/src/_cffi_src/openssl/rsa.py
+++ b/src/_cffi_src/openssl/rsa.py
@@ -9,28 +9,17 @@ INCLUDES = """
"""
TYPES = """
-typedef struct rsa_st {
- BIGNUM *n;
- BIGNUM *e;
- BIGNUM *d;
- BIGNUM *p;
- BIGNUM *q;
- BIGNUM *dmp1;
- BIGNUM *dmq1;
- BIGNUM *iqmp;
- ...;
-} RSA;
+typedef ... 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;
+static const int Cryptography_HAS_RSA_OAEP_MD;
+static const int Cryptography_HAS_RSA_OAEP_LABEL;
"""
FUNCTIONS = """
@@ -41,7 +30,6 @@ 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 *,
@@ -51,49 +39,146 @@ int RSA_public_decrypt(int, const unsigned char *, unsigned char *,
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 = """
+/* added in 1.1.0 when the RSA struct was opaqued */
+int RSA_set0_key(RSA *, BIGNUM *, BIGNUM *, BIGNUM *);
+int RSA_set0_factors(RSA *, BIGNUM *, BIGNUM *);
+int RSA_set0_crt_params(RSA *, BIGNUM *, BIGNUM *, BIGNUM *);
+void RSA_get0_key(const RSA *, const BIGNUM **, const BIGNUM **,
+ const BIGNUM **);
+void RSA_get0_factors(const RSA *, const BIGNUM **, const BIGNUM **);
+void RSA_get0_crt_params(const RSA *, const BIGNUM **, const BIGNUM **,
+ const BIGNUM **);
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 *);
+int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *, unsigned char *, int);
+
+int EVP_PKEY_CTX_set_rsa_oaep_md(EVP_PKEY_CTX *, EVP_MD *);
"""
CUSTOMIZATIONS = """
-#if OPENSSL_VERSION_NUMBER >= 0x10000000
static const long Cryptography_HAS_PSS_PADDING = 1;
+
+#if defined(EVP_PKEY_CTX_set_rsa_oaep_md)
+static const long Cryptography_HAS_RSA_OAEP_MD = 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;
+static const long Cryptography_HAS_RSA_OAEP_MD = 0;
+int (*EVP_PKEY_CTX_set_rsa_oaep_md)(EVP_PKEY_CTX *, EVP_MD *) = NULL;
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x1000100f
-static const long Cryptography_HAS_MGF1_MD = 1;
+
+#if defined(EVP_PKEY_CTX_set0_rsa_oaep_label)
+static const long Cryptography_HAS_RSA_OAEP_LABEL = 1;
#else
-static const long Cryptography_HAS_MGF1_MD = 0;
-int (*EVP_PKEY_CTX_set_rsa_mgf1_md)(EVP_PKEY_CTX *, EVP_MD *) = NULL;
+static const long Cryptography_HAS_RSA_OAEP_LABEL = 0;
+int (*EVP_PKEY_CTX_set0_rsa_oaep_label)(EVP_PKEY_CTX *, unsigned char *,
+ int) = 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",
- ],
+/* These functions were added in OpenSSL 1.1.0 */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
+{
+ /* If the fields n and e in r are NULL, the corresponding input
+ * parameters MUST be non-NULL for n and e. d may be
+ * left NULL (in case only the public key is used).
+ */
+ if ((r->n == NULL && n == NULL)
+ || (r->e == NULL && e == NULL))
+ return 0;
+
+ if (n != NULL) {
+ BN_free(r->n);
+ r->n = n;
+ }
+ if (e != NULL) {
+ BN_free(r->e);
+ r->e = e;
+ }
+ if (d != NULL) {
+ BN_free(r->d);
+ r->d = d;
+ }
+
+ return 1;
+}
+
+int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
+{
+ /* If the fields p and q in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->p == NULL && p == NULL)
+ || (r->q == NULL && q == NULL))
+ return 0;
+
+ if (p != NULL) {
+ BN_free(r->p);
+ r->p = p;
+ }
+ if (q != NULL) {
+ BN_free(r->q);
+ r->q = q;
+ }
+
+ return 1;
}
+
+int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
+{
+ /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input
+ * parameters MUST be non-NULL.
+ */
+ if ((r->dmp1 == NULL && dmp1 == NULL)
+ || (r->dmq1 == NULL && dmq1 == NULL)
+ || (r->iqmp == NULL && iqmp == NULL))
+ return 0;
+
+ if (dmp1 != NULL) {
+ BN_free(r->dmp1);
+ r->dmp1 = dmp1;
+ }
+ if (dmq1 != NULL) {
+ BN_free(r->dmq1);
+ r->dmq1 = dmq1;
+ }
+ if (iqmp != NULL) {
+ BN_free(r->iqmp);
+ r->iqmp = iqmp;
+ }
+
+ return 1;
+}
+
+void RSA_get0_key(const RSA *r,
+ const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
+{
+ if (n != NULL)
+ *n = r->n;
+ if (e != NULL)
+ *e = r->e;
+ if (d != NULL)
+ *d = r->d;
+}
+
+void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
+{
+ if (p != NULL)
+ *p = r->p;
+ if (q != NULL)
+ *q = r->q;
+}
+
+void RSA_get0_crt_params(const RSA *r,
+ const BIGNUM **dmp1, const BIGNUM **dmq1,
+ const BIGNUM **iqmp)
+{
+ if (dmp1 != NULL)
+ *dmp1 = r->dmp1;
+ if (dmq1 != NULL)
+ *dmq1 = r->dmq1;
+ if (iqmp != NULL)
+ *iqmp = r->iqmp;
+}
+#endif
+"""
diff --git a/src/_cffi_src/openssl/src/osrandom_engine.c b/src/_cffi_src/openssl/src/osrandom_engine.c
new file mode 100644
index 00000000..dc7b1d5e
--- /dev/null
+++ b/src/_cffi_src/openssl/src/osrandom_engine.c
@@ -0,0 +1,659 @@
+/* osurandom engine
+ *
+ * Windows CryptGenRandom()
+ * macOS >= 10.12 getentropy()
+ * OpenBSD 5.6+ getentropy()
+ * other BSD getentropy() if SYS_getentropy is defined
+ * Linux 3.17+ getrandom() with fallback to /dev/urandom
+ * other /dev/urandom with cached fd
+ *
+ * The /dev/urandom, getrandom and getentropy code is derived from Python's
+ * Python/random.c, written by Antoine Pitrou and Victor Stinner.
+ *
+ * Copyright 2001-2016 Python Software Foundation; All Rights Reserved.
+ */
+
+#ifdef __linux__
+#include <poll.h>
+#endif
+
+#ifndef OPENSSL_NO_ENGINE
+/* OpenSSL has ENGINE support so build the engine. */
+static const char *Cryptography_osrandom_engine_id = "osrandom";
+
+/****************************************************************************
+ * Windows
+ */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine CryptGenRandom()";
+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 {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_INIT,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ if (hCryptProv == 0) {
+ return 0;
+ }
+
+ if (!CryptGenRandom(hCryptProv, (DWORD)size, buffer)) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_finish(ENGINE *e) {
+ if (CryptReleaseContext(hCryptProv, 0)) {
+ hCryptProv = 0;
+ return 1;
+ } else {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_FINISH,
+ CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+}
+
+static int osrandom_rand_status(void) {
+ return hCryptProv != 0;
+}
+
+static const char *osurandom_get_implementation(void) {
+ return "CryptGenRandom";
+}
+
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM */
+
+/****************************************************************************
+ * /dev/urandom helpers for all non-BSD Unix platforms
+ */
+#ifdef CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM
+
+static struct {
+ int fd;
+ dev_t st_dev;
+ ino_t st_ino;
+} urandom_cache = { -1 };
+
+static int open_cloexec(const char *path) {
+ int open_flags = O_RDONLY;
+#ifdef O_CLOEXEC
+ open_flags |= O_CLOEXEC;
+#endif
+
+ int fd = open(path, open_flags);
+ if (fd == -1) {
+ return -1;
+ }
+
+#ifndef O_CLOEXEC
+ int flags = fcntl(fd, F_GETFD);
+ if (flags == -1) {
+ return -1;
+ }
+ if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
+ return -1;
+ }
+#endif
+ return fd;
+}
+
+#ifdef __linux__
+/* On Linux, we open("/dev/random") and use poll() to wait until it's readable
+ * before we read from /dev/urandom, this ensures that we don't read from
+ * /dev/urandom before the kernel CSPRNG is initialized. This isn't necessary on
+ * other platforms because they don't have the same _bug_ as Linux does with
+ * /dev/urandom and early boot. */
+static int wait_on_devrandom(void) {
+ struct pollfd pfd = {};
+ int ret = 0;
+ int random_fd = open_cloexec("/dev/random");
+ if (random_fd < 0) {
+ return -1;
+ }
+ pfd.fd = random_fd;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ do {
+ ret = poll(&pfd, 1, -1);
+ } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
+ close(random_fd);
+ return ret;
+}
+#endif
+
+/* return -1 on error */
+static int dev_urandom_fd(void) {
+ int fd = -1;
+ struct stat st;
+
+ /* Check that fd still points to the correct device */
+ if (urandom_cache.fd >= 0) {
+ if (fstat(urandom_cache.fd, &st)
+ || st.st_dev != urandom_cache.st_dev
+ || st.st_ino != urandom_cache.st_ino) {
+ /* Somebody replaced our FD. Invalidate our cache but don't
+ * close the fd. */
+ urandom_cache.fd = -1;
+ }
+ }
+ if (urandom_cache.fd < 0) {
+#ifdef __linux__
+ if (wait_on_devrandom() < 0) {
+ goto error;
+ }
+#endif
+
+ fd = open_cloexec("/dev/urandom");
+ if (fd < 0) {
+ goto error;
+ }
+ if (fstat(fd, &st)) {
+ goto error;
+ }
+ /* Another thread initialized the fd */
+ if (urandom_cache.fd >= 0) {
+ close(fd);
+ return urandom_cache.fd;
+ }
+ urandom_cache.st_dev = st.st_dev;
+ urandom_cache.st_ino = st.st_ino;
+ urandom_cache.fd = fd;
+ }
+ return urandom_cache.fd;
+
+ error:
+ if (fd != -1) {
+ close(fd);
+ }
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD,
+ CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED,
+ __FILE__, __LINE__
+ );
+ return -1;
+}
+
+static int dev_urandom_read(unsigned char *buffer, int size) {
+ int fd;
+ int n;
+
+ fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+
+ while (size > 0) {
+ do {
+ n = (int)read(fd, buffer, (size_t)size);
+ } while (n < 0 && errno == EINTR);
+
+ if (n <= 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ,
+ CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += n;
+ size -= n;
+ }
+ return 1;
+}
+
+static void dev_urandom_close(void) {
+ if (urandom_cache.fd >= 0) {
+ int fd;
+ struct stat st;
+
+ if (fstat(urandom_cache.fd, &st)
+ && st.st_dev == urandom_cache.st_dev
+ && st.st_ino == urandom_cache.st_ino) {
+ fd = urandom_cache.fd;
+ urandom_cache.fd = -1;
+ close(fd);
+ }
+ }
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM */
+
+/****************************************************************************
+ * BSD getentropy
+ */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine getentropy()";
+
+static int getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT;
+
+static int osrandom_init(ENGINE *e) {
+#if !defined(__APPLE__)
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
+#else
+ if (__builtin_available(macOS 10.12, *)) {
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS;
+ } else {
+ getentropy_works = CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK;
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ }
+#endif
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ int len;
+ int res;
+
+ switch(getentropy_works) {
+#if defined(__APPLE__)
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
+ return dev_urandom_read(buffer, size);
+#endif
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
+ while (size > 0) {
+ /* OpenBSD and macOS restrict maximum buffer size to 256. */
+ len = size > 256 ? 256 : size;
+/* on mac, availability is already checked using `__builtin_available` above */
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunguarded-availability"
+ res = getentropy(buffer, (size_t)len);
+#pragma clang diagnostic pop
+ if (res < 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += len;
+ size -= len;
+ }
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static int osrandom_finish(ENGINE *e) {
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ return 1;
+}
+
+static const char *osurandom_get_implementation(void) {
+ switch(getentropy_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK:
+ return "/dev/urandom";
+ case CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS:
+ return "getentropy";
+ }
+ __builtin_unreachable();
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY */
+
+/****************************************************************************
+ * Linux getrandom engine with fallback to dev_urandom
+ */
+
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine getrandom()";
+
+static int getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT;
+
+static int osrandom_init(ENGINE *e) {
+ /* We try to detect working getrandom until we succeed. */
+ if (getrandom_works != CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS) {
+ long n;
+ char dest[1];
+ /* if the kernel CSPRNG is not initialized this will block */
+ n = syscall(SYS_getrandom, dest, sizeof(dest), 0);
+ if (n == sizeof(dest)) {
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS;
+ } else {
+ int e = errno;
+ switch(e) {
+ case ENOSYS:
+ /* Fallback: Kernel does not support the syscall. */
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
+ break;
+ case EPERM:
+ /* Fallback: seccomp prevents syscall */
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK;
+ break;
+ default:
+ /* EINTR cannot occur for buflen < 256. */
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_INIT,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED,
+ "errno", e
+ );
+ getrandom_works = CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED;
+ break;
+ }
+ }
+ }
+
+ /* fallback to dev urandom */
+ if (getrandom_works == CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK) {
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ long n;
+
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT,
+ __FILE__, __LINE__
+ );
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return dev_urandom_read(buffer, size);
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ while (size > 0) {
+ do {
+ n = syscall(SYS_getrandom, buffer, size, 0);
+ } while (n < 0 && errno == EINTR);
+
+ if (n <= 0) {
+ ERR_Cryptography_OSRandom_error(
+ CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES,
+ CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED,
+ __FILE__, __LINE__
+ );
+ return 0;
+ }
+ buffer += n;
+ size -= (int)n;
+ }
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static int osrandom_finish(ENGINE *e) {
+ dev_urandom_close();
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ return 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return urandom_cache.fd >= 0;
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ return 1;
+ }
+ __builtin_unreachable();
+}
+
+static const char *osurandom_get_implementation(void) {
+ switch(getrandom_works) {
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED:
+ return "<failed>";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT:
+ return "<not initialized>";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK:
+ return "/dev/urandom";
+ case CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS:
+ return "getrandom";
+ }
+ __builtin_unreachable();
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM */
+
+/****************************************************************************
+ * dev_urandom engine for all remaining platforms
+ */
+
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine /dev/urandom";
+
+static int osrandom_init(ENGINE *e) {
+ int fd = dev_urandom_fd();
+ if (fd < 0) {
+ return 0;
+ }
+ return 1;
+}
+
+static int osrandom_rand_bytes(unsigned char *buffer, int size) {
+ return dev_urandom_read(buffer, size);
+}
+
+static int osrandom_finish(ENGINE *e) {
+ dev_urandom_close();
+ return 1;
+}
+
+static int osrandom_rand_status(void) {
+ return urandom_cache.fd >= 0;
+}
+
+static const char *osurandom_get_implementation(void) {
+ return "/dev/urandom";
+}
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM */
+
+/****************************************************************************
+ * ENGINE boiler plate
+ */
+
+/* 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,
+};
+
+static const ENGINE_CMD_DEFN osrandom_cmd_defns[] = {
+ {CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION,
+ "get_implementation",
+ "Get CPRNG implementation.",
+ ENGINE_CMD_FLAG_NO_INPUT},
+ {0, NULL, NULL, 0}
+};
+
+static int osrandom_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void)) {
+ const char *name;
+ size_t len;
+
+ switch (cmd) {
+ case CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION:
+ /* i: buffer size, p: char* buffer */
+ name = osurandom_get_implementation();
+ len = strlen(name);
+ if ((p == NULL) && (i == 0)) {
+ /* return required buffer len */
+ return (int)len;
+ }
+ if ((p == NULL) || i < 0 || ((size_t)i <= len)) {
+ /* no buffer or buffer too small */
+ ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_INVALID_ARGUMENT);
+ return 0;
+ }
+ strncpy((char *)p, name, len);
+ return (int)len;
+ default:
+ ENGINEerr(ENGINE_F_ENGINE_CTRL, ENGINE_R_CTRL_COMMAND_NOT_IMPLEMENTED);
+ return 0;
+ }
+}
+
+/* error reporting */
+#define ERR_FUNC(func) ERR_PACK(0, func, 0)
+#define ERR_REASON(reason) ERR_PACK(0, 0, reason)
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_lib_name[] = {
+ {0, "osrandom_engine"},
+ {0, NULL}
+};
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_funcs[] = {
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_INIT),
+ "osrandom_init"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES),
+ "osrandom_rand_bytes"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_FINISH),
+ "osrandom_finish"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD),
+ "dev_urandom_fd"},
+ {ERR_FUNC(CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ),
+ "dev_urandom_read"},
+ {0, NULL}
+};
+
+static ERR_STRING_DATA CRYPTOGRAPHY_OSRANDOM_str_reasons[] = {
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT),
+ "CryptAcquireContext() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM),
+ "CryptGenRandom() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT),
+ "CryptReleaseContext() failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED),
+ "getentropy() failed"},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED),
+ "open('/dev/urandom') failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED),
+ "Reading from /dev/urandom fd failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED),
+ "getrandom() initialization failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED),
+ "getrandom() initialization failed with unexpected errno."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED),
+ "getrandom() syscall failed."},
+ {ERR_REASON(CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT),
+ "getrandom() engine was not properly initialized."},
+ {0, NULL}
+};
+
+static int Cryptography_OSRandom_lib_error_code = 0;
+
+static void ERR_load_Cryptography_OSRandom_strings(void)
+{
+ if (Cryptography_OSRandom_lib_error_code == 0) {
+ Cryptography_OSRandom_lib_error_code = ERR_get_next_error_library();
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_lib_name);
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_str_funcs);
+ ERR_load_strings(Cryptography_OSRandom_lib_error_code,
+ CRYPTOGRAPHY_OSRANDOM_str_reasons);
+ }
+}
+
+static void ERR_Cryptography_OSRandom_error(int function, int reason,
+ char *file, int line)
+{
+ ERR_PUT_error(Cryptography_OSRandom_lib_error_code, function, reason,
+ file, line);
+}
+
+/* Returns 1 if successfully added, 2 if engine has previously been added,
+ and 0 for error. */
+int Cryptography_add_osrandom_engine(void) {
+ ENGINE *e;
+
+ ERR_load_Cryptography_OSRandom_strings();
+
+ 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_set_cmd_defns(e, osrandom_cmd_defns) ||
+ !ENGINE_set_ctrl_function(e, osrandom_ctrl)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_add(e)) {
+ ENGINE_free(e);
+ return 0;
+ }
+ if (!ENGINE_free(e)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+#else
+/* If OpenSSL has no ENGINE support then we don't want
+ * to compile the osrandom engine, but we do need some
+ * placeholders */
+static const char *Cryptography_osrandom_engine_id = "no-engine-support";
+static const char *Cryptography_osrandom_engine_name = "osrandom_engine disabled due to no engine support";
+
+int Cryptography_add_osrandom_engine(void) {
+ return 0;
+}
+
+#endif
diff --git a/src/_cffi_src/openssl/src/osrandom_engine.h b/src/_cffi_src/openssl/src/osrandom_engine.h
new file mode 100644
index 00000000..cf394f22
--- /dev/null
+++ b/src/_cffi_src/openssl/src/osrandom_engine.h
@@ -0,0 +1,114 @@
+#ifndef OPENSSL_NO_ENGINE
+/* OpenSSL has ENGINE support so include all of this. */
+#ifdef _WIN32
+ #include <Wincrypt.h>
+#else
+ #include <fcntl.h>
+ #include <unistd.h>
+ /* for defined(BSD) */
+ #include <sys/param.h>
+
+ #ifdef BSD
+ /* for SYS_getentropy */
+ #include <sys/syscall.h>
+ #endif
+
+ #ifdef __APPLE__
+ #include <sys/random.h>
+ /* To support weak linking we need to declare this as a weak import even if
+ * it's not present in sys/random (e.g. macOS < 10.12). */
+ extern int getentropy(void *buffer, size_t size) __attribute((weak_import));
+ #endif
+
+ #ifdef __linux__
+ /* for SYS_getrandom */
+ #include <sys/syscall.h>
+ #ifndef GRND_NONBLOCK
+ #define GRND_NONBLOCK 0x0001
+ #endif /* GRND_NONBLOCK */
+
+ #ifndef SYS_getrandom
+ /* We only bother to define the constants for platforms where we ship
+ * wheels, since that's the predominant way you get a situation where
+ * you don't have SYS_getrandom at compile time but do have the syscall
+ * at runtime */
+ #if defined __x86_64__
+ #define SYS_getrandom 318
+ #elif defined(__i386__)
+ #define SYS_getrandom 355
+ #endif
+ #endif
+ #endif /* __linux__ */
+#endif /* _WIN32 */
+
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM 1
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY 2
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM 3
+#define CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM 4
+
+#ifndef CRYPTOGRAPHY_OSRANDOM_ENGINE
+ #if defined(_WIN32)
+ /* Windows */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_CRYPTGENRANDOM
+ #elif defined(BSD) && defined(SYS_getentropy)
+ /* OpenBSD 5.6+ & macOS with SYS_getentropy defined, although < 10.12 will fallback
+ * to urandom */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY
+ #elif defined(__linux__) && defined(SYS_getrandom)
+ /* Linux 3.17+ */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM
+ #else
+ /* Keep this as last entry, fall back to /dev/urandom */
+ #define CRYPTOGRAPHY_OSRANDOM_ENGINE CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM
+ #endif
+#endif /* CRYPTOGRAPHY_OSRANDOM_ENGINE */
+
+/* Fallbacks need /dev/urandom helper functions. */
+#if CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETRANDOM || \
+ CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_DEV_URANDOM || \
+ (CRYPTOGRAPHY_OSRANDOM_ENGINE == CRYPTOGRAPHY_OSRANDOM_ENGINE_GETENTROPY && \
+ defined(__APPLE__))
+ #define CRYPTOGRAPHY_OSRANDOM_NEEDS_DEV_URANDOM 1
+#endif
+
+enum {
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_INIT_FAILED = -2,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_NOT_INIT,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_FALLBACK,
+ CRYPTOGRAPHY_OSRANDOM_GETRANDOM_WORKS
+};
+
+enum {
+ CRYPTOGRAPHY_OSRANDOM_GETENTROPY_NOT_INIT,
+ CRYPTOGRAPHY_OSRANDOM_GETENTROPY_FALLBACK,
+ CRYPTOGRAPHY_OSRANDOM_GETENTROPY_WORKS
+};
+
+/* engine ctrl */
+#define CRYPTOGRAPHY_OSRANDOM_GET_IMPLEMENTATION ENGINE_CMD_BASE
+
+/* error reporting */
+static void ERR_load_Cryptography_OSRandom_strings(void);
+static void ERR_Cryptography_OSRandom_error(int function, int reason,
+ char *file, int line);
+
+#define CRYPTOGRAPHY_OSRANDOM_F_INIT 100
+#define CRYPTOGRAPHY_OSRANDOM_F_RAND_BYTES 101
+#define CRYPTOGRAPHY_OSRANDOM_F_FINISH 102
+#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_FD 300
+#define CRYPTOGRAPHY_OSRANDOM_F_DEV_URANDOM_READ 301
+
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTACQUIRECONTEXT 100
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTGENRANDOM 101
+#define CRYPTOGRAPHY_OSRANDOM_R_CRYPTRELEASECONTEXT 102
+
+#define CRYPTOGRAPHY_OSRANDOM_R_GETENTROPY_FAILED 200
+
+#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_OPEN_FAILED 300
+#define CRYPTOGRAPHY_OSRANDOM_R_DEV_URANDOM_READ_FAILED 301
+
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED 400
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_INIT_FAILED_UNEXPECTED 402
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_FAILED 403
+#define CRYPTOGRAPHY_OSRANDOM_R_GETRANDOM_NOT_INIT 404
+#endif
diff --git a/src/_cffi_src/openssl/ssl.py b/src/_cffi_src/openssl/ssl.py
index fa0aefc8..4ba86693 100644
--- a/src/_cffi_src/openssl/ssl.py
+++ b/src/_cffi_src/openssl/ssl.py
@@ -11,20 +11,26 @@ 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_SSL_ST;
+static const long Cryptography_HAS_TLS_ST;
static const long Cryptography_HAS_SSL2;
static const long Cryptography_HAS_SSL3_METHOD;
static const long Cryptography_HAS_TLSv1_1;
static const long Cryptography_HAS_TLSv1_2;
+static const long Cryptography_HAS_TLSv1_3;
static const long Cryptography_HAS_SECURE_RENEGOTIATION;
static const long Cryptography_HAS_COMPRESSION;
static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB;
static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP;
static const long Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE;
-static const long Cryptography_HAS_GET_SERVER_TMP_KEY;
static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE;
+static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS;
+static const long Cryptography_HAS_DTLS;
+static const long Cryptography_HAS_SIGALGS;
+static const long Cryptography_HAS_PSK;
+static const long Cryptography_HAS_CIPHER_DETAILS;
+static const long Cryptography_HAS_VERIFIED_CHAIN;
+static const long Cryptography_HAS_KEYLOG;
/* Internally invented symbol to tell us if SNI is supported */
static const long Cryptography_HAS_TLSEXT_HOSTNAME;
@@ -38,13 +44,13 @@ static const long Cryptography_HAS_RELEASE_BUFFERS;
* 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 Cryptography_HAS_NEXTPROTONEG;
+static const long Cryptography_HAS_SET_CERT_CB;
+static const long Cryptography_HAS_CUSTOM_EXT;
static const long SSL_FILETYPE_PEM;
static const long SSL_FILETYPE_ASN1;
@@ -53,6 +59,7 @@ 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_WANT_CONNECT;
static const long SSL_ERROR_SYSCALL;
static const long SSL_ERROR_SSL;
static const long SSL_SENT_SHUTDOWN;
@@ -62,6 +69,9 @@ 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_TLSv1_3;
+static const long SSL_OP_NO_DTLSv1;
+static const long SSL_OP_NO_DTLSv1_2;
static const long SSL_OP_NO_COMPRESSION;
static const long SSL_OP_SINGLE_DH_USE;
static const long SSL_OP_EPHEMERAL_RSA;
@@ -92,6 +102,7 @@ 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_VERIFY_POST_HANDSHAKE;
static const long SSL_SESS_CACHE_OFF;
static const long SSL_SESS_CACHE_CLIENT;
static const long SSL_SESS_CACHE_SERVER;
@@ -125,41 +136,32 @@ 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;
+static const long TLS_ST_BEFORE;
+static const long TLS_ST_OK;
+
+static const long OPENSSL_NPN_NEGOTIATED;
typedef ... SSL_METHOD;
typedef ... 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 ... SSL_SESSION;
-typedef struct {
- int version;
- int type;
- SSL3_STATE *s3;
- SSL_SESSION *session;
- ...;
-} SSL;
+typedef ... SSL;
static const long TLSEXT_NAMETYPE_host_name;
+static const long TLSEXT_STATUSTYPE_ocsp;
typedef ... SSL_CIPHER;
typedef ... Cryptography_STACK_OF_SSL_CIPHER;
typedef ... COMP_METHOD;
+
+typedef struct {
+ const char *name;
+ unsigned long id;
+} SRTP_PROTECTION_PROFILE;
"""
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 *);
@@ -174,6 +176,10 @@ 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);
+SSL_CTX *SSL_get_SSL_CTX(const SSL *);
+SSL_CTX *SSL_set_SSL_CTX(SSL *, SSL_CTX *);
+BIO *SSL_get_rbio(const SSL *);
+BIO *SSL_get_wbio(const SSL *);
void SSL_set_bio(SSL *, BIO *, BIO *);
void SSL_set_connect_state(SSL *);
void SSL_set_accept_state(SSL *);
@@ -182,9 +188,15 @@ int SSL_get_shutdown(const SSL *);
int SSL_pending(const SSL *);
int SSL_write(SSL *, const void *, int);
int SSL_read(SSL *, void *, int);
+int SSL_peek(SSL *, void *, int);
+X509 *SSL_get_certificate(const SSL *);
X509 *SSL_get_peer_certificate(const SSL *);
int SSL_get_ex_data_X509_STORE_CTX_idx(void);
+/* Added in 1.0.2 */
+X509_VERIFY_PARAM *SSL_get0_param(SSL *);
+X509_VERIFY_PARAM *SSL_CTX_get0_param(SSL_CTX *);
+
int SSL_use_certificate(SSL *, X509 *);
int SSL_use_certificate_ASN1(SSL *, const unsigned char *, int);
int SSL_use_certificate_file(SSL *, const char *, int);
@@ -193,12 +205,19 @@ int SSL_use_PrivateKey_ASN1(int, SSL *, const unsigned char *, long);
int SSL_use_PrivateKey_file(SSL *, const char *, int);
int SSL_check_private_key(const SSL *);
+int SSL_get_sigalgs(SSL *, int, int *, int *, int *, unsigned char *,
+ unsigned char *);
+
Cryptography_STACK_OF_X509 *SSL_get_peer_cert_chain(const SSL *);
+Cryptography_STACK_OF_X509 *SSL_get0_verified_chain(const SSL *);
Cryptography_STACK_OF_X509_NAME *SSL_get_client_CA_list(const SSL *);
int SSL_get_error(const SSL *, int);
+long SSL_get_verify_result(const SSL *ssl);
int SSL_do_handshake(SSL *);
int SSL_shutdown(SSL *);
+int SSL_renegotiate(SSL *);
+int SSL_renegotiate_pending(SSL *);
const char *SSL_get_cipher_list(const SSL *, int);
Cryptography_STACK_OF_SSL_CIPHER *SSL_get_ciphers(const SSL *);
@@ -224,40 +243,116 @@ int SSL_CTX_use_PrivateKey_ASN1(int, SSL_CTX *, const unsigned char *, long);
int SSL_CTX_use_PrivateKey_file(SSL_CTX *, const char *, int);
int SSL_CTX_check_private_key(const SSL_CTX *);
void SSL_CTX_set_cert_verify_callback(SSL_CTX *,
- int (*)(X509_STORE_CTX *,void *),
+ int (*)(X509_STORE_CTX *, void *),
void *);
+void SSL_CTX_set_cookie_generate_cb(SSL_CTX *,
+ int (*)(
+ SSL *,
+ unsigned char *,
+ unsigned int *
+ ));
+long SSL_CTX_get_read_ahead(SSL_CTX *);
+long SSL_CTX_set_read_ahead(SSL_CTX *, long);
+
+int SSL_CTX_use_psk_identity_hint(SSL_CTX *, const char *);
+void SSL_CTX_set_psk_server_callback(SSL_CTX *,
+ unsigned int (*)(
+ SSL *,
+ const char *,
+ unsigned char *,
+ unsigned int
+ ));
+void SSL_CTX_set_psk_client_callback(SSL_CTX *,
+ unsigned int (*)(
+ SSL *,
+ const char *,
+ char *,
+ unsigned int,
+ unsigned char *,
+ unsigned int
+ ));
+
+int SSL_CTX_set_session_id_context(SSL_CTX *, const unsigned char *,
+ unsigned 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 *);
+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);
+
+void SSL_CTX_set_keylog_callback(SSL_CTX *,
+ void (*)(const SSL *, const char *));
+void (*SSL_CTX_get_keylog_callback(SSL_CTX *))(const SSL *, const char *);
+
+long SSL_CTX_set1_sigalgs_list(SSL_CTX *, const char *);
+
/* 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 *);
+/* the modern signature of this is uint32_t, but older openssl declared it
+ as unsigned long. To make our compiler flags happy we'll declare it as a
+ 64-bit wide value, which should always be safe */
+uint64_t SSL_CIPHER_get_id(const SSL_CIPHER *);
+int SSL_CIPHER_is_aead(const SSL_CIPHER *);
+int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *);
+int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *);
+int SSL_CIPHER_get_kx_nid(const SSL_CIPHER *);
+int SSL_CIPHER_get_auth_nid(const SSL_CIPHER *);
size_t SSL_get_finished(const SSL *, void *, size_t);
size_t SSL_get_peer_finished(const SSL *, void *, size_t);
-"""
+Cryptography_STACK_OF_X509_NAME *SSL_load_client_CA_file(const char *);
+
+const char *SSL_get_servername(const SSL *, const int);
+/* Function signature changed to const char * in 1.1.0 */
+const char *SSL_CIPHER_get_version(const SSL_CIPHER *);
+/* These became macros in 1.1.0 */
+int SSL_library_init(void);
+void SSL_load_error_strings(void);
+
+/* these CRYPTO_EX_DATA functions became macros in 1.1.0 */
+int SSL_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *,
+ CRYPTO_EX_free *);
+int SSL_set_ex_data(SSL *, int, void *);
+int SSL_CTX_get_ex_new_index(long, void *, CRYPTO_EX_new *, CRYPTO_EX_dup *,
+ CRYPTO_EX_free *);
+int SSL_CTX_set_ex_data(SSL_CTX *, int, void *);
+
+SSL_SESSION *SSL_get_session(const SSL *);
+const unsigned char *SSL_SESSION_get_id(const SSL_SESSION *, unsigned int *);
+long SSL_SESSION_get_time(const SSL_SESSION *);
+long SSL_SESSION_get_timeout(const SSL_SESSION *);
+int SSL_SESSION_has_ticket(const SSL_SESSION *);
+long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *);
+
+/* not a macro, but older OpenSSLs don't pass the args as const */
+char *SSL_CIPHER_description(const SSL_CIPHER *, char *, int);
+int SSL_SESSION_print(BIO *, const SSL_SESSION *);
-MACROS = """
/* not macros, but will be conditionally bound so can't live in functions */
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 *);
-int SSL_CTX_set_client_cert_engine(SSL_CTX *, ENGINE *);
unsigned long SSL_set_mode(SSL *, unsigned long);
+unsigned long SSL_clear_mode(SSL *, unsigned long);
unsigned long SSL_get_mode(SSL *);
unsigned long SSL_set_options(SSL *, unsigned long);
unsigned long SSL_get_options(SSL *);
+void SSL_set_app_data(SSL *, char *);
+char * SSL_get_app_data(SSL *);
+void SSL_set_read_ahead(SSL *, int);
+
int SSL_want_read(const SSL *);
int SSL_want_write(const SSL *);
@@ -267,8 +362,10 @@ 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_clear_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_clear_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 *);
@@ -280,15 +377,6 @@ unsigned long SSL_CTX_add_extra_chain_cert(SSL_CTX *, X509 *);
/* 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.
@@ -313,6 +401,11 @@ const SSL_METHOD *DTLSv1_method(void);
const SSL_METHOD *DTLSv1_server_method(void);
const SSL_METHOD *DTLSv1_client_method(void);
+/* Added in 1.0.2 */
+const SSL_METHOD *DTLS_method(void);
+const SSL_METHOD *DTLS_server_method(void);
+const SSL_METHOD *DTLS_client_method(void);
+
const SSL_METHOD *SSLv23_method(void);
const SSL_METHOD *SSLv23_server_method(void);
const SSL_METHOD *SSLv23_client_method(void);
@@ -325,39 +418,28 @@ const SSL_CIPHER *SSL_get_current_cipher(const SSL *);
const char *SSL_get_version(const SSL *);
int SSL_version(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_CTX_get_ex_data(const SSL_CTX *, int);
+void *SSL_get_ex_data(const SSL *, int);
+
void SSL_set_tlsext_host_name(SSL *, char *);
void SSL_CTX_set_tlsext_servername_callback(
SSL_CTX *,
- int (*)(const SSL *, int *, void *));
+ int (*)(SSL *, int *, void *));
+void SSL_CTX_set_tlsext_servername_arg(
+ SSL_CTX *, void *);
-/* These were added in OpenSSL 0.9.8h, but since version testing in OpenSSL
- is fraught with peril thanks to OS distributions we check some constants
- to determine if they are supported or not */
long SSL_set_tlsext_status_ocsp_resp(SSL *, unsigned char *, int);
long SSL_get_tlsext_status_ocsp_resp(SSL *, const unsigned char **);
long SSL_set_tlsext_status_type(SSL *, long);
long SSL_CTX_set_tlsext_status_cb(SSL_CTX *, int(*)(SSL *, void *));
long SSL_CTX_set_tlsext_status_arg(SSL_CTX *, 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 *);
+int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *, const char *);
+int SSL_set_tlsext_use_srtp(SSL *, const char *);
+SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *);
-const SSL_METHOD *Cryptography_SSL_CTX_get_method(const SSL_CTX *);
+long SSL_session_reused(SSL *);
-/* 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 **,
@@ -379,7 +461,7 @@ 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);
+const 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.
@@ -397,29 +479,172 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *,
void SSL_get0_alpn_selected(const SSL *, const unsigned char **, unsigned *);
long SSL_get_server_tmp_key(SSL *, EVP_PKEY **);
+
+/* SSL_CTX_set_cert_cb is introduced in OpenSSL 1.0.2. To continue to support
+ * earlier versions some special handling of these is necessary.
+ */
+void SSL_CTX_set_cert_cb(SSL_CTX *, int (*)(SSL *, void *), void *);
+void SSL_set_cert_cb(SSL *, int (*)(SSL *, void *), void *);
+
+/* Added in 1.0.2 */
+const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *);
+
+int SSL_SESSION_set1_id_context(SSL_SESSION *, const unsigned char *,
+ unsigned int);
+/* Added in 1.1.0 for the great opaquing of structs */
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *, unsigned char *,
+ size_t);
+size_t SSL_get_client_random(const SSL *, unsigned char *, size_t);
+size_t SSL_get_server_random(const SSL *, unsigned char *, size_t);
+int SSL_export_keying_material(SSL *, unsigned char *, size_t, const char *,
+ size_t, const unsigned char *, size_t, int);
+
+long SSL_CTX_sess_number(SSL_CTX *);
+long SSL_CTX_sess_connect(SSL_CTX *);
+long SSL_CTX_sess_connect_good(SSL_CTX *);
+long SSL_CTX_sess_connect_renegotiate(SSL_CTX *);
+long SSL_CTX_sess_accept(SSL_CTX *);
+long SSL_CTX_sess_accept_good(SSL_CTX *);
+long SSL_CTX_sess_accept_renegotiate(SSL_CTX *);
+long SSL_CTX_sess_hits(SSL_CTX *);
+long SSL_CTX_sess_cb_hits(SSL_CTX *);
+long SSL_CTX_sess_misses(SSL_CTX *);
+long SSL_CTX_sess_timeouts(SSL_CTX *);
+long SSL_CTX_sess_cache_full(SSL_CTX *);
+
+/* DTLS support */
+long Cryptography_DTLSv1_get_timeout(SSL *, time_t *, long *);
+long DTLSv1_handle_timeout(SSL *);
+long DTLS_set_link_mtu(SSL *, long);
+long DTLS_get_link_min_mtu(SSL *);
+
+/* Custom extensions. */
+typedef int (*custom_ext_add_cb)(SSL *, unsigned int,
+ const unsigned char **,
+ size_t *, int *,
+ void *);
+
+typedef void (*custom_ext_free_cb)(SSL *, unsigned int,
+ const unsigned char *,
+ void *);
+
+typedef int (*custom_ext_parse_cb)(SSL *, unsigned int,
+ const unsigned char *,
+ size_t, int *,
+ void *);
+
+int SSL_CTX_add_client_custom_ext(SSL_CTX *, unsigned int,
+ custom_ext_add_cb,
+ custom_ext_free_cb, void *,
+ custom_ext_parse_cb,
+ void *);
+
+int SSL_CTX_add_server_custom_ext(SSL_CTX *, unsigned int,
+ custom_ext_add_cb,
+ custom_ext_free_cb, void *,
+ custom_ext_parse_cb,
+ void *);
+
+int SSL_extension_supported(unsigned int);
+
+int SSL_CTX_set_ciphersuites(SSL_CTX *, const char *);
+int SSL_verify_client_post_handshake(SSL *);
+void SSL_CTX_set_post_handshake_auth(SSL_CTX *, int);
+void SSL_set_post_handshake_auth(SSL *, int);
+
+uint32_t SSL_SESSION_get_max_early_data(const SSL_SESSION *);
+int SSL_write_early_data(SSL *, const void *, size_t, size_t *);
+int SSL_read_early_data(SSL *, void *, size_t, size_t *);
+int SSL_CTX_set_max_early_data(SSL_CTX *, uint32_t);
"""
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;
+#if CRYPTOGRAPHY_IS_LIBRESSL
+const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) {
+ return ctx->method;
+}
+#endif
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+static const long Cryptography_HAS_VERIFIED_CHAIN = 0;
+Cryptography_STACK_OF_X509 *(*SSL_get0_verified_chain)(const SSL *) = NULL;
#else
-static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1;
+static const long Cryptography_HAS_VERIFIED_CHAIN = 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;
+
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
+static const long Cryptography_HAS_KEYLOG = 0;
+void (*SSL_CTX_set_keylog_callback)(SSL_CTX *,
+ void (*) (const SSL *, const char *)
+ ) = NULL;
+void (*(*SSL_CTX_get_keylog_callback)(SSL_CTX *))(
+ const SSL *,
+ const char *
+ ) = NULL;
#else
-static const long Cryptography_HAS_SSL2 = 1;
+static const long Cryptography_HAS_KEYLOG = 1;
+#endif
+
+/* Added in 1.1.0 in the great opaquing, but we need to define it for older
+ OpenSSLs. Such is our burden. */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+/* from ssl/ssl_lib.c */
+size_t SSL_get_client_random(const SSL *ssl, unsigned char *out, size_t outlen)
+{
+ if (outlen == 0)
+ return sizeof(ssl->s3->client_random);
+ if (outlen > sizeof(ssl->s3->client_random))
+ outlen = sizeof(ssl->s3->client_random);
+ memcpy(out, ssl->s3->client_random, outlen);
+ return outlen;
+}
+/* Added in 1.1.0 as well */
+/* from ssl/ssl_lib.c */
+size_t SSL_get_server_random(const SSL *ssl, unsigned char *out, size_t outlen)
+{
+ if (outlen == 0)
+ return sizeof(ssl->s3->server_random);
+ if (outlen > sizeof(ssl->s3->server_random))
+ outlen = sizeof(ssl->s3->server_random);
+ memcpy(out, ssl->s3->server_random, outlen);
+ return outlen;
+}
+/* Added in 1.1.0 as well */
+/* from ssl/ssl_lib.c */
+size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
+ unsigned char *out, size_t outlen)
+{
+ if (session->master_key_length < 0) {
+ /* Should never happen */
+ return 0;
+ }
+ if (outlen == 0)
+ return session->master_key_length;
+ if (outlen > (size_t)session->master_key_length)
+ outlen = session->master_key_length;
+ memcpy(out, session->master_key, outlen);
+ return outlen;
+}
+/* from ssl/ssl_sess.c */
+int SSL_SESSION_has_ticket(const SSL_SESSION *s)
+{
+ return (s->tlsext_ticklen > 0) ? 1 : 0;
+}
+/* from ssl/ssl_sess.c */
+unsigned long SSL_SESSION_get_ticket_lifetime_hint(const SSL_SESSION *s)
+{
+ return s->tlsext_tick_lifetime_hint;
+}
#endif
+static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1;
+
+/* Cryptography now compiles out all SSLv2 bindings. This exists to allow
+ * clients that use it to check for SSLv2 support to keep functioning as
+ * expected.
+ */
+static const long Cryptography_HAS_SSL2 = 0;
+
#ifdef OPENSSL_NO_SSL3_METHOD
static const long Cryptography_HAS_SSL3_METHOD = 0;
SSL_METHOD* (*SSLv3_method)(void) = NULL;
@@ -429,308 +654,172 @@ SSL_METHOD* (*SSLv3_server_method)(void) = NULL;
static const long Cryptography_HAS_SSL3_METHOD = 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_CTRL_SET_TLSEXT_STATUS_REQ_CB
static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 1;
-#else
-static const long Cryptography_HAS_TLSEXT_STATUS_REQ_CB = 0;
-long (*SSL_CTX_set_tlsext_status_cb)(SSL_CTX *, int(*)(SSL *, void *)) = NULL;
-long (*SSL_CTX_set_tlsext_status_arg)(SSL_CTX *, void *) = NULL;
-#endif
-
-#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_OCSP_RESP
static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 1;
-#else
-static const long Cryptography_HAS_STATUS_REQ_OCSP_RESP = 0;
-long (*SSL_set_tlsext_status_ocsp_resp)(SSL *, unsigned char *, int) = NULL;
-long (*SSL_get_tlsext_status_ocsp_resp)(SSL *, const unsigned char **) = NULL;
-#endif
-
-#ifdef SSL_CTRL_SET_TLSEXT_STATUS_REQ_TYPE
static const long Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE = 1;
-#else
-static const long Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE = 0;
-long (*SSL_set_tlsext_status_type)(SSL *, long) = 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;
+static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 1;
+static const long Cryptography_HAS_SSL_OP_NO_TICKET = 1;
+static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1;
+static const long Cryptography_HAS_NEXTPROTONEG = 1;
+static const long Cryptography_HAS_ALPN = 1;
+
+#if CRYPTOGRAPHY_IS_LIBRESSL
+void (*SSL_CTX_set_cert_cb)(SSL_CTX *, int (*)(SSL *, void *), void *) = NULL;
+void (*SSL_set_cert_cb)(SSL *, int (*)(SSL *, void *), void *) = NULL;
+static const long Cryptography_HAS_SET_CERT_CB = 0;
#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;
+static const long Cryptography_HAS_SET_CERT_CB = 1;
#endif
-#ifdef SSL_OP_MSIE_SSLV2_RSA_PADDING
-static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 1;
+/* In OpenSSL 1.0.2i+ the handling of COMP_METHOD when OPENSSL_NO_COMP was
+ changed and we no longer need to typedef void */
+#if (defined(OPENSSL_NO_COMP) && CRYPTOGRAPHY_OPENSSL_LESS_THAN_102I) || \
+ CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_COMPRESSION = 0;
+typedef void COMP_METHOD;
#else
-static const long Cryptography_HAS_SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
-const long SSL_OP_MSIE_SSLV2_RSA_PADDING = 0;
+static const long Cryptography_HAS_COMPRESSION = 1;
#endif
-#ifdef OPENSSL_NO_EC
-long (*SSL_CTX_set_tmp_ecdh)(SSL_CTX *, EC_KEY *) = NULL;
-#endif
+static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 1;
-#ifdef SSL_OP_NO_TICKET
-static const long Cryptography_HAS_SSL_OP_NO_TICKET = 1;
+static const long Cryptography_HAS_SSL_CTX_CLEAR_OPTIONS = 1;
+
+/* in OpenSSL 1.1.0 the SSL_ST values were renamed to TLS_ST and several were
+ removed */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+static const long Cryptography_HAS_SSL_ST = 1;
#else
-static const long Cryptography_HAS_SSL_OP_NO_TICKET = 0;
-const long SSL_OP_NO_TICKET = 0;
+static const long Cryptography_HAS_SSL_ST = 0;
+static const long SSL_ST_BEFORE = 0;
+static const long SSL_ST_OK = 0;
+static const long SSL_ST_INIT = 0;
+static const long SSL_ST_RENEGOTIATE = 0;
#endif
-
-/* OpenSSL 0.9.8f+ */
-#if OPENSSL_VERSION_NUMBER >= 0x00908070L
-static const long Cryptography_HAS_SSL_SET_SSL_CTX = 1;
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+static const long Cryptography_HAS_TLS_ST = 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;
+static const long Cryptography_HAS_TLS_ST = 0;
+static const long TLS_ST_BEFORE = 0;
+static const long TLS_ST_OK = 0;
#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;
+#if CRYPTOGRAPHY_IS_LIBRESSL
+static const long SSL_OP_NO_DTLSv1 = 0;
+static const long SSL_OP_NO_DTLSv1_2 = 0;
+long (*DTLS_set_link_mtu)(SSL *, long) = NULL;
+long (*DTLS_get_link_min_mtu)(SSL *) = NULL;
#endif
-/* Workaround for #794 caused by cffi const** bug. */
-const SSL_METHOD *Cryptography_SSL_CTX_get_method(const SSL_CTX *ctx) {
- return ctx->method;
+static const long Cryptography_HAS_DTLS = 1;
+/* Wrap DTLSv1_get_timeout to avoid cffi to handle a 'struct timeval'. */
+long Cryptography_DTLSv1_get_timeout(SSL *ssl, time_t *ptv_sec,
+ long *ptv_usec) {
+ struct timeval tv = { 0 };
+ long r = DTLSv1_get_timeout(ssl, &tv);
+
+ if (r == 1) {
+ if (ptv_sec) {
+ *ptv_sec = tv.tv_sec;
+ }
+
+ if (ptv_usec) {
+ *ptv_usec = tv.tv_usec;
+ }
+ }
+
+ return r;
}
-/* 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;
+#if CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_SIGALGS = 0;
+const int (*SSL_get_sigalgs)(SSL *, int, int *, int *, int *, unsigned char *,
+ unsigned char *) = NULL;
+const long (*SSL_CTX_set1_sigalgs_list)(SSL_CTX *, const char *) = NULL;
#else
-static const long Cryptography_HAS_NEXTPROTONEG = 1;
+static const long Cryptography_HAS_SIGALGS = 1;
#endif
-/* ALPN was added in OpenSSL 1.0.2. */
-#if OPENSSL_VERSION_NUMBER < 0x10002001L && !defined(LIBRESSL_VERSION_NUMBER)
-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 **,
+#if CRYPTOGRAPHY_IS_LIBRESSL || defined(OPENSSL_NO_PSK)
+static const long Cryptography_HAS_PSK = 0;
+int (*SSL_CTX_use_psk_identity_hint)(SSL_CTX *, const char *) = NULL;
+void (*SSL_CTX_set_psk_server_callback)(SSL_CTX *,
+ unsigned int (*)(
+ SSL *,
+ const char *,
unsigned char *,
- const unsigned char *,
+ unsigned int
+ )) = NULL;
+void (*SSL_CTX_set_psk_client_callback)(SSL_CTX *,
+ unsigned int (*)(
+ SSL *,
+ const char *,
+ 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;
+ unsigned char *,
+ unsigned int
+ )) = NULL;
#else
-static const long Cryptography_HAS_ALPN = 1;
+static const long Cryptography_HAS_PSK = 1;
#endif
-#if defined(OPENSSL_NO_COMP) || defined(LIBRESSL_VERSION_NUMBER)
-static const long Cryptography_HAS_COMPRESSION = 0;
-typedef void COMP_METHOD;
+#if !CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_CUSTOM_EXT = 1;
#else
-static const long Cryptography_HAS_COMPRESSION = 1;
+static const long Cryptography_HAS_CUSTOM_EXT = 0;
+typedef int (*custom_ext_add_cb)(SSL *, unsigned int,
+ const unsigned char **,
+ size_t *, int *,
+ void *);
+typedef void (*custom_ext_free_cb)(SSL *, unsigned int,
+ const unsigned char *,
+ void *);
+typedef int (*custom_ext_parse_cb)(SSL *, unsigned int,
+ const unsigned char *,
+ size_t, int *,
+ void *);
+int (*SSL_CTX_add_client_custom_ext)(SSL_CTX *, unsigned int,
+ custom_ext_add_cb,
+ custom_ext_free_cb, void *,
+ custom_ext_parse_cb,
+ void *) = NULL;
+int (*SSL_CTX_add_server_custom_ext)(SSL_CTX *, unsigned int,
+ custom_ext_add_cb,
+ custom_ext_free_cb, void *,
+ custom_ext_parse_cb,
+ void *) = NULL;
+int (*SSL_extension_supported)(unsigned int) = NULL;
#endif
-#if defined(SSL_CTRL_GET_SERVER_TMP_KEY)
-static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 1;
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+int (*SSL_CIPHER_is_aead)(const SSL_CIPHER *) = NULL;
+int (*SSL_CIPHER_get_cipher_nid)(const SSL_CIPHER *) = NULL;
+int (*SSL_CIPHER_get_digest_nid)(const SSL_CIPHER *) = NULL;
+int (*SSL_CIPHER_get_kx_nid)(const SSL_CIPHER *) = NULL;
+int (*SSL_CIPHER_get_auth_nid)(const SSL_CIPHER *) = NULL;
+static const long Cryptography_HAS_CIPHER_DETAILS = 0;
#else
-static const long Cryptography_HAS_GET_SERVER_TMP_KEY = 0;
-long (*SSL_get_server_tmp_key)(SSL *, EVP_PKEY **) = NULL;
+static const long Cryptography_HAS_CIPHER_DETAILS = 1;
#endif
-/* Added in 0.9.8i */
-#if OPENSSL_VERSION_NUMBER < 0x0090809fL
-int (*SSL_CTX_set_client_cert_engine)(SSL_CTX *, ENGINE *) = NULL;
-static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 0;
-# else
-static const long Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE = 1;
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
+static const long Cryptography_HAS_TLSv1_3 = 0;
+static const long SSL_OP_NO_TLSv1_3 = 0;
+static const long SSL_VERIFY_POST_HANDSHAKE = 0;
+int (*SSL_CTX_set_ciphersuites)(SSL_CTX *, const char *) = NULL;
+int (*SSL_verify_client_post_handshake)(SSL *) = NULL;
+void (*SSL_CTX_set_post_handshake_auth)(SSL_CTX *, int) = NULL;
+void (*SSL_set_post_handshake_auth)(SSL *, int) = NULL;
+uint32_t (*SSL_SESSION_get_max_early_data)(const SSL_SESSION *) = NULL;
+int (*SSL_write_early_data)(SSL *, const void *, size_t, size_t *) = NULL;
+int (*SSL_read_early_data)(SSL *, void *, size_t, size_t *) = NULL;
+int (*SSL_CTX_set_max_early_data)(SSL_CTX *, uint32_t) = NULL;
+#else
+static const long Cryptography_HAS_TLSv1_3 = 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_SSL3_METHOD": [
- "SSLv3_method",
- "SSLv3_client_method",
- "SSLv3_server_method",
- ],
-
- "Cryptography_HAS_TLSEXT_HOSTNAME": [
- "SSL_set_tlsext_host_name",
- "SSL_get_servername",
- "SSL_CTX_set_tlsext_servername_callback",
- ],
-
- "Cryptography_HAS_TLSEXT_STATUS_REQ_CB": [
- "SSL_CTX_set_tlsext_status_cb",
- "SSL_CTX_set_tlsext_status_arg"
- ],
-
- "Cryptography_HAS_STATUS_REQ_OCSP_RESP": [
- "SSL_set_tlsext_status_ocsp_resp",
- "SSL_get_tlsext_status_ocsp_resp",
- ],
-
- "Cryptography_HAS_TLSEXT_STATUS_REQ_TYPE": [
- "SSL_set_tlsext_status_type",
- ],
-
- "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",
- ],
-
- "Cryptography_HAS_COMPRESSION": [
- "SSL_get_current_compression",
- "SSL_get_current_expansion",
- "SSL_COMP_get_name",
- ],
-
- "Cryptography_HAS_GET_SERVER_TMP_KEY": [
- "SSL_get_server_tmp_key",
- ],
-
- "Cryptography_HAS_SSL_CTX_SET_CLIENT_CERT_ENGINE": [
- "SSL_CTX_set_client_cert_engine",
- ],
-}
diff --git a/src/_cffi_src/openssl/x509.py b/src/_cffi_src/openssl/x509.py
index 6bd117b0..0135a89a 100644
--- a/src/_cffi_src/openssl/x509.py
+++ b/src/_cffi_src/openssl/x509.py
@@ -30,86 +30,18 @@ typedef struct {
} 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_EXTENSION;
typedef ... X509_EXTENSIONS;
-
-typedef struct {
- X509_ALGOR *sig_alg;
- ...;
-} 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_ALGOR *sig_alg;
- ...;
-} X509_CRL;
-
-typedef struct {
- X509_ALGOR *sig_alg;
- X509_CINF *cert_info;
- ...;
-} X509;
+typedef ... X509_REQ;
+typedef ... X509_REVOKED;
+typedef ... X509_CRL;
+typedef ... X509;
typedef ... NETSCAPE_SPKI;
typedef ... PKCS8_PRIV_KEY_INFO;
-static const int X509_FLAG_COMPAT;
-static const int X509_FLAG_NO_HEADER;
-static const int X509_FLAG_NO_VERSION;
-static const int X509_FLAG_NO_SERIAL;
-static const int X509_FLAG_NO_SIGNAME;
-static const int X509_FLAG_NO_ISSUER;
-static const int X509_FLAG_NO_VALIDITY;
-static const int X509_FLAG_NO_SUBJECT;
-static const int X509_FLAG_NO_PUBKEY;
-static const int X509_FLAG_NO_EXTENSIONS;
-static const int X509_FLAG_NO_SIGDUMP;
-static const int X509_FLAG_NO_AUX;
-static const int X509_FLAG_NO_ATTRIBUTES;
-
-static const int XN_FLAG_SEP_MASK;
-static const int XN_FLAG_COMPAT;
-static const int XN_FLAG_SEP_COMMA_PLUS;
-static const int XN_FLAG_SEP_CPLUS_SPC;
-static const int XN_FLAG_SEP_SPLUS_SPC;
-static const int XN_FLAG_SEP_MULTILINE;
-static const int XN_FLAG_DN_REV;
-static const int XN_FLAG_FN_MASK;
-static const int XN_FLAG_FN_SN;
-static const int XN_FLAG_FN_LN;
-static const int XN_FLAG_FN_OID;
-static const int XN_FLAG_FN_NONE;
-static const int XN_FLAG_SPC_EQ;
-static const int XN_FLAG_DUMP_UNKNOWN_FIELDS;
-static const int XN_FLAG_FN_ALIGN;
-static const int XN_FLAG_RFC2253;
-static const int XN_FLAG_ONELINE;
-static const int XN_FLAG_MULTILINE;
+typedef void (*sk_X509_EXTENSION_freefunc)(X509_EXTENSION *);
"""
FUNCTIONS = """
@@ -117,6 +49,7 @@ X509 *X509_new(void);
void X509_free(X509 *);
X509 *X509_dup(X509 *);
int X509_cmp(const X509 *, const X509 *);
+int X509_up_ref(X509 *);
int X509_print_ex(BIO *, X509 *, unsigned long, unsigned long);
@@ -134,27 +67,15 @@ 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_delete_ext(X509 *, int);
X509_EXTENSION *X509_EXTENSION_dup(X509_EXTENSION *);
-X509_EXTENSION *X509_get_ext(X509 *, int);
-int X509_get_ext_by_NID(X509 *, int, int);
-int X509_EXTENSION_get_critical(X509_EXTENSION *);
ASN1_OBJECT *X509_EXTENSION_get_object(X509_EXTENSION *);
void X509_EXTENSION_free(X509_EXTENSION *);
-X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **,
- ASN1_OBJECT *, int,
- ASN1_OCTET_STRING *);
-
-int i2d_X509(X509 *, unsigned char **);
int X509_REQ_set_version(X509_REQ *, long);
X509_REQ *X509_REQ_new(void);
@@ -163,11 +84,16 @@ int X509_REQ_set_pubkey(X509_REQ *, EVP_PKEY *);
int X509_REQ_set_subject_name(X509_REQ *, X509_NAME *);
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(BIO *, X509_REQ *);
int X509_REQ_print_ex(BIO *, X509_REQ *, unsigned long, unsigned long);
+int X509_REQ_add_extensions(X509_REQ *, X509_EXTENSIONS *);
+X509_EXTENSIONS *X509_REQ_get_extensions(X509_REQ *);
+X509_ATTRIBUTE *X509_REQ_get_attr(const X509_REQ *, int);
+int X509_REQ_get_attr_by_OBJ(const X509_REQ *, const ASN1_OBJECT *, int);
+void *X509_ATTRIBUTE_get0_data(X509_ATTRIBUTE *, int, int, void *);
+ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *, int);
+int X509_REQ_add1_attr_by_txt(X509_REQ *, const char *, int,
+ const unsigned char *, int);
int X509V3_EXT_print(BIO *, X509_EXTENSION *, unsigned long, int);
ASN1_OCTET_STRING *X509_EXTENSION_get_data(X509_EXTENSION *);
@@ -177,18 +103,18 @@ void X509_REVOKED_free(X509_REVOKED *);
int X509_REVOKED_set_serialNumber(X509_REVOKED *, ASN1_INTEGER *);
-int X509_REVOKED_get_ext_count(X509_REVOKED *);
-X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *, int);
int X509_REVOKED_add_ext(X509_REVOKED *, X509_EXTENSION*, int);
int X509_REVOKED_add1_ext_i2d(X509_REVOKED *, int, void *, int, unsigned long);
+X509_EXTENSION *X509_REVOKED_delete_ext(X509_REVOKED *, int);
+
+int X509_REVOKED_set_revocationDate(X509_REVOKED *, ASN1_TIME *);
X509_CRL *X509_CRL_new(void);
+X509_CRL *X509_CRL_dup(X509_CRL *);
X509_CRL *d2i_X509_CRL_bio(BIO *, X509_CRL **);
-X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int);
int X509_CRL_add0_revoked(X509_CRL *, X509_REVOKED *);
int X509_CRL_add_ext(X509_CRL *, X509_EXTENSION *, int);
int X509_CRL_cmp(const X509_CRL *, const X509_CRL *);
-int X509_CRL_get_ext_count(X509_CRL *);
int X509_CRL_print(BIO *, X509_CRL *);
int X509_CRL_set_issuer_name(X509_CRL *, X509_NAME *);
int X509_CRL_set_version(X509_CRL *, long);
@@ -224,43 +150,59 @@ 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 *);
-PKCS8_PRIV_KEY_INFO *d2i_PKCS8_PRIV_KEY_INFO_bio(BIO *,
- PKCS8_PRIV_KEY_INFO **);
-void PKCS8_PRIV_KEY_INFO_free(PKCS8_PRIV_KEY_INFO *);
-"""
+/* These became const X509 in 1.1.0 */
+int X509_get_ext_count(X509 *);
+X509_EXTENSION *X509_get_ext(X509 *, int);
+X509_NAME *X509_get_subject_name(X509 *);
+X509_NAME *X509_get_issuer_name(X509 *);
+
+/* This became const ASN1_OBJECT * in 1.1.0 */
+X509_EXTENSION *X509_EXTENSION_create_by_OBJ(X509_EXTENSION **,
+ ASN1_OBJECT *, int,
+ ASN1_OCTET_STRING *);
+
+
+/* This became const X509_EXTENSION * in 1.1.0 */
+int X509_EXTENSION_get_critical(X509_EXTENSION *);
+
+/* This became const X509_REVOKED * in 1.1.0 */
+int X509_REVOKED_get_ext_count(X509_REVOKED *);
+X509_EXTENSION *X509_REVOKED_get_ext(X509_REVOKED *, int);
+
+/* This became const X509_CRL * in 1.1.0 */
+X509_EXTENSION *X509_CRL_get_ext(X509_CRL *, int);
+int X509_CRL_get_ext_count(X509_CRL *);
+
+int X509_CRL_get0_by_serial(X509_CRL *, X509_REVOKED **, ASN1_INTEGER *);
+
+X509_REVOKED *X509_REVOKED_dup(X509_REVOKED *);
+X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *);
+
+/* new in 1.0.2 */
+int i2d_re_X509_tbs(X509 *, unsigned char **);
+int X509_get_signature_nid(const X509 *);
+
+const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *);
+
+void X509_get0_signature(const ASN1_BIT_STRING **,
+ const X509_ALGOR **, const X509 *);
-MACROS = """
long X509_get_version(X509 *);
ASN1_TIME *X509_get_notBefore(X509 *);
ASN1_TIME *X509_get_notAfter(X509 *);
+ASN1_TIME *X509_getm_notBefore(X509 *);
+ASN1_TIME *X509_getm_notAfter(X509 *);
long X509_REQ_get_version(X509_REQ *);
X509_NAME *X509_REQ_get_subject_name(X509_REQ *);
@@ -275,8 +217,10 @@ 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 *);
+int sk_X509_EXTENSION_insert(X509_EXTENSIONS *, X509_EXTENSION *, int);
X509_EXTENSION *sk_X509_EXTENSION_delete(X509_EXTENSIONS *, int);
void sk_X509_EXTENSION_free(X509_EXTENSIONS *);
+void sk_X509_EXTENSION_pop_free(X509_EXTENSIONS *, sk_X509_EXTENSION_freefunc);
int sk_X509_REVOKED_num(Cryptography_STACK_OF_X509_REVOKED *);
X509_REVOKED *sk_X509_REVOKED_value(Cryptography_STACK_OF_X509_REVOKED *, int);
@@ -287,12 +231,7 @@ int sk_X509_CRL_num(Cryptography_STACK_OF_X509_CRL *);
int sk_X509_CRL_push(Cryptography_STACK_OF_X509_CRL *, X509_CRL *);
X509_CRL *sk_X509_CRL_value(Cryptography_STACK_OF_X509_CRL *, 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 **);
-
-int X509_CRL_get_version(X509_CRL *);
+long X509_CRL_get_version(X509_CRL *);
ASN1_TIME *X509_CRL_get_lastUpdate(X509_CRL *);
ASN1_TIME *X509_CRL_get_nextUpdate(X509_CRL *);
X509_NAME *X509_CRL_get_issuer(X509_CRL *);
@@ -303,61 +242,102 @@ int X509_CRL_set_lastUpdate(X509_CRL *, ASN1_TIME *);
int X509_CRL_set_nextUpdate(X509_CRL *, ASN1_TIME *);
int X509_set_notBefore(X509 *, ASN1_TIME *);
int X509_set_notAfter(X509 *, ASN1_TIME *);
+int X509_set1_notBefore(X509 *, ASN1_TIME *);
+int X509_set1_notAfter(X509 *, 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(EC_KEY **, const unsigned char **, long);
EC_KEY *d2i_ECPrivateKey_bio(BIO *, EC_KEY **);
-int i2d_ECPrivateKey(EC_KEY *, unsigned char **);
int i2d_ECPrivateKey_bio(BIO *, EC_KEY *);
-EC_KEY *o2i_ECPublicKey(EC_KEY **, const unsigned char **, long);
-int i2o_ECPublicKey(EC_KEY *, unsigned char **);
-
// declared in safestack
int sk_ASN1_OBJECT_num(Cryptography_STACK_OF_ASN1_OBJECT *);
ASN1_OBJECT *sk_ASN1_OBJECT_value(Cryptography_STACK_OF_ASN1_OBJECT *, int);
void sk_ASN1_OBJECT_free(Cryptography_STACK_OF_ASN1_OBJECT *);
+Cryptography_STACK_OF_ASN1_OBJECT *sk_ASN1_OBJECT_new_null(void);
+int sk_ASN1_OBJECT_push(Cryptography_STACK_OF_ASN1_OBJECT *, ASN1_OBJECT *);
+
+/* these functions were added in 1.1.0 */
+const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *);
+const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *);
+void X509_CRL_get0_signature(const X509_CRL *, const ASN1_BIT_STRING **,
+ const X509_ALGOR **);
+int i2d_re_X509_REQ_tbs(X509_REQ *, unsigned char **);
+int i2d_re_X509_CRL_tbs(X509_CRL *, unsigned char **);
+void X509_REQ_get0_signature(const X509_REQ *, const ASN1_BIT_STRING **,
+ const X509_ALGOR **);
"""
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)(EC_KEY **, const unsigned char **, long) = NULL;
-EC_KEY *(*d2i_ECPrivateKey_bio)(BIO *, EC_KEY **) = NULL;
-int (*i2d_ECPrivateKey)(EC_KEY *, unsigned char **) = NULL;
-int (*i2d_ECPrivateKey_bio)(BIO *, EC_KEY *) = NULL;
-
-EC_KEY *(*o2i_ECPublicKey)(EC_KEY **, const unsigned char **, long) = NULL;
-int (*i2o_ECPublicKey)(EC_KEY *, unsigned char **) = NULL;
+#if CRYPTOGRAPHY_IS_LIBRESSL
+int i2d_re_X509_tbs(X509 *x, unsigned char **pp)
+{
+ /* in 1.0.2+ this function also sets x->cert_info->enc.modified = 1
+ but older OpenSSLs don't have the enc ASN1_ENCODING member in the
+ X509 struct. Setting modified to 1 marks the encoding
+ (x->cert_info->enc.enc) as invalid, but since the entire struct isn't
+ present we don't care. */
+ return i2d_X509_CINF(x->cert_info, pp);
+}
#endif
-"""
-CONDITIONAL_NAMES = {
- "Cryptography_HAS_EC": [
- "i2d_EC_PUBKEY",
- "d2i_EC_PUBKEY",
- "d2i_EC_PUBKEY_bio",
- "i2d_EC_PUBKEY_bio",
- "d2i_ECPrivateKey",
- "d2i_ECPrivateKey_bio",
- "i2d_ECPrivateKey",
- "i2d_ECPrivateKey_bio",
- "i2o_ECPublicKey",
- "o2i_ECPublicKey",
- ]
+/* Being kept around for pyOpenSSL */
+X509_REVOKED *Cryptography_X509_REVOKED_dup(X509_REVOKED *rev) {
+ return X509_REVOKED_dup(rev);
}
+/* Added in 1.1.0 but we need it in all versions now due to the great
+ opaquing. */
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+int i2d_re_X509_REQ_tbs(X509_REQ *req, unsigned char **pp)
+{
+ req->req_info->enc.modified = 1;
+ return i2d_X509_REQ_INFO(req->req_info, pp);
+}
+int i2d_re_X509_CRL_tbs(X509_CRL *crl, unsigned char **pp) {
+ crl->crl->enc.modified = 1;
+ return i2d_X509_CRL_INFO(crl->crl, pp);
+}
+
+#if !CRYPTOGRAPHY_IS_LIBRESSL
+int X509_up_ref(X509 *x) {
+ return CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+}
+
+const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x)
+{
+ return x->cert_info->signature;
+}
+
+/* from x509/x509_req.c */
+void X509_REQ_get0_signature(const X509_REQ *req, const ASN1_BIT_STRING **psig,
+ const X509_ALGOR **palg)
+{
+ if (psig != NULL)
+ *psig = req->signature;
+ if (palg != NULL)
+ *palg = req->sig_alg;
+}
+void X509_CRL_get0_signature(const X509_CRL *crl, const ASN1_BIT_STRING **psig,
+ const X509_ALGOR **palg)
+{
+ if (psig != NULL)
+ *psig = crl->signature;
+ if (palg != NULL)
+ *palg = crl->sig_alg;
+}
+const ASN1_TIME *X509_REVOKED_get0_revocationDate(const X509_REVOKED *x)
+{
+ return x->revocationDate;
+}
+const ASN1_INTEGER *X509_REVOKED_get0_serialNumber(const X509_REVOKED *x)
+{
+ return x->serialNumber;
+}
+
+#define X509_set1_notBefore X509_set_notBefore
+#define X509_set1_notAfter X509_set_notAfter
+#define X509_getm_notAfter X509_get_notAfter
+#define X509_getm_notBefore X509_get_notBefore
+#endif
+#endif
+"""
diff --git a/src/_cffi_src/openssl/x509_vfy.py b/src/_cffi_src/openssl/x509_vfy.py
index 23ac8483..d2bc5f4e 100644
--- a/src/_cffi_src/openssl/x509_vfy.py
+++ b/src/_cffi_src/openssl/x509_vfy.py
@@ -15,36 +15,23 @@ INCLUDES = """
* Note that the result is an opaque type.
*/
typedef STACK_OF(ASN1_OBJECT) Cryptography_STACK_OF_ASN1_OBJECT;
+typedef STACK_OF(X509_OBJECT) Cryptography_STACK_OF_X509_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;
+static const long Cryptography_HAS_102_VERIFICATION;
+static const long Cryptography_HAS_110_VERIFICATION_PARAMS;
+static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER;
typedef ... Cryptography_STACK_OF_ASN1_OBJECT;
+typedef ... Cryptography_STACK_OF_X509_OBJECT;
+typedef ... X509_OBJECT;
typedef ... X509_STORE;
typedef ... X509_VERIFY_PARAM;
+typedef ... X509_STORE_CTX;
-typedef struct x509_store_ctx_st X509_STORE_CTX;
-struct x509_store_ctx_st {
- X509_STORE *ctx;
- int current_method;
- X509 *cert;
- Cryptography_STACK_OF_X509 *untrusted;
- Cryptography_STACK_OF_X509_CRL *crls;
- X509_VERIFY_PARAM *param;
- void *other_ctx;
- int (*verify)(X509_STORE_CTX *);
- int (*verify_cb)(int, X509_STORE_CTX *);
- int (*get_issuer)(X509 **, X509_STORE_CTX *, X509 *);
- ...;
-};
+typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **, X509_STORE_CTX *, X509 *);
/* 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
@@ -136,6 +123,16 @@ 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;
+
+static const long X509_LU_X509;
+static const long X509_LU_CRL;
+
+static const long X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT;
+static const long X509_CHECK_FLAG_NO_WILDCARDS;
+static const long X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS;
+static const long X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS;
+static const long X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS;
+static const long X509_CHECK_FLAG_NEVER_CHECK_SUBJECT;
"""
FUNCTIONS = """
@@ -151,7 +148,6 @@ int X509_STORE_set_default_paths(X509_STORE *);
int X509_STORE_set_flags(X509_STORE *, unsigned long);
void X509_STORE_free(X509_STORE *);
-
/* X509_STORE_CTX */
X509_STORE_CTX *X509_STORE_CTX_new(void);
void X509_STORE_CTX_cleanup(X509_STORE_CTX *);
@@ -175,6 +171,7 @@ 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);
+int X509_STORE_CTX_get1_issuer(X509 **, X509_STORE_CTX *, X509 *);
/* X509_VERIFY_PARAM */
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void);
@@ -189,9 +186,11 @@ 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 *);
-"""
+void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *);
+/* this CRYPTO_EX_DATA function became a macro in 1.1.0 */
+int X509_STORE_CTX_get_ex_new_index(long, void *, CRYPTO_EX_new *,
+ CRYPTO_EX_dup *, CRYPTO_EX_free *);
-MACROS = """
/* X509_STORE_CTX */
void X509_STORE_CTX_set0_crls(X509_STORE_CTX *,
Cryptography_STACK_OF_X509_CRL *);
@@ -205,143 +204,74 @@ int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *, const char *,
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 *);
+
+int sk_X509_OBJECT_num(Cryptography_STACK_OF_X509_OBJECT *);
+X509_OBJECT *sk_X509_OBJECT_value(Cryptography_STACK_OF_X509_OBJECT *, int);
+X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *);
+Cryptography_STACK_OF_X509_OBJECT *X509_STORE_get0_objects(X509_STORE *);
+X509 *X509_OBJECT_get0_X509(X509_OBJECT *);
+int X509_OBJECT_get_type(const X509_OBJECT *);
+
+/* added in 1.1.0 */
+X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *);
+X509_STORE_CTX_get_issuer_fn X509_STORE_get_get_issuer(X509_STORE *);
+void X509_STORE_set_get_issuer(X509_STORE *, X509_STORE_CTX_get_issuer_fn);
"""
CUSTOMIZATIONS = """
-/* OpenSSL 1.0.2+ verification error codes */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
-static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 1;
+#if !CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_102_VERIFICATION = 1;
#else
-static const long Cryptography_HAS_102_VERIFICATION_ERROR_CODES = 0;
+static const long Cryptography_HAS_102_VERIFICATION = 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 && !defined(LIBRESSL_VERSION_NUMBER)
-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;
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 || CRYPTOGRAPHY_IS_LIBRESSL
+static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 0;
+#ifndef X509_CHECK_FLAG_NEVER_CHECK_SUBJECT
+static const long X509_CHECK_FLAG_NEVER_CHECK_SUBJECT = 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;
+static const long Cryptography_HAS_110_VERIFICATION_PARAMS = 1;
#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
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110 && !CRYPTOGRAPHY_IS_LIBRESSL
+Cryptography_STACK_OF_X509_OBJECT *X509_STORE_get0_objects(X509_STORE *ctx) {
+ return ctx->objs;
+}
+X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *store) {
+ return store->param;
+}
+int X509_OBJECT_get_type(const X509_OBJECT *x) {
+ return x->type;
+}
-/* 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;
+/* from x509/x509_vfy.c */
+X509 *X509_STORE_CTX_get0_cert(X509_STORE_CTX *ctx)
+{
+ return ctx->cert;
+}
+
+X509 *X509_OBJECT_get0_X509(X509_OBJECT *x) {
+ return x->data.x509;
+}
#endif
-/* OpenSSL 0.9.8recent+ */
-#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
-static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 1;
+#if CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER = 0;
+typedef void *X509_STORE_CTX_get_issuer_fn;
+X509_STORE_CTX_get_issuer_fn (*X509_STORE_get_get_issuer)(X509_STORE *) = NULL;
+void (*X509_STORE_set_get_issuer)(X509_STORE *,
+ X509_STORE_CTX_get_issuer_fn) = NULL;
#else
-static const long Cryptography_HAS_X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
-static const long X509_V_FLAG_CHECK_SS_SIGNATURE = 0;
+static const long Cryptography_HAS_X509_STORE_CTX_GET_ISSUER = 1;
#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/_cffi_src/openssl/x509name.py b/src/_cffi_src/openssl/x509name.py
index be5b3a75..f88c8b06 100644
--- a/src/_cffi_src/openssl/x509name.py
+++ b/src/_cffi_src/openssl/x509name.py
@@ -15,49 +15,73 @@ typedef STACK_OF(X509_NAME_ENTRY) Cryptography_STACK_OF_X509_NAME_ENTRY;
"""
TYPES = """
+typedef ... Cryptography_STACK_OF_X509_NAME_ENTRY;
typedef ... X509_NAME;
typedef ... X509_NAME_ENTRY;
typedef ... Cryptography_STACK_OF_X509_NAME;
-typedef ... Cryptography_STACK_OF_X509_NAME_ENTRY;
"""
FUNCTIONS = """
X509_NAME *X509_NAME_new(void);
void X509_NAME_free(X509_NAME *);
-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_txt(X509_NAME *, const char *, int,
const unsigned char *, int, int, int);
-int X509_NAME_add_entry_by_OBJ(X509_NAME *, ASN1_OBJECT *, int,
- unsigned char *, int, int, int);
-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 *);
-"""
+int Cryptography_X509_NAME_ENTRY_set(X509_NAME_ENTRY *);
+/* These became const X509_NAME * in 1.1.0 */
+int X509_NAME_entry_count(X509_NAME *);
+X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *, int);
+char *X509_NAME_oneline(X509_NAME *, char *, int);
+int X509_NAME_print_ex(BIO *, X509_NAME *, int, unsigned long);
+
+/* These became const X509_NAME_ENTRY * in 1.1.0 */
+ASN1_OBJECT *X509_NAME_ENTRY_get_object(X509_NAME_ENTRY *);
+ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *);
+int X509_NAME_add_entry(X509_NAME *, X509_NAME_ENTRY *, int, int);
+
+/* this became const unsigned char * in 1.1.0 */
+int X509_NAME_add_entry_by_NID(X509_NAME *, int, int, unsigned char *,
+ int, int, int);
+
+/* These became const ASN1_OBJECT * in 1.1.0 */
+X509_NAME_ENTRY *X509_NAME_ENTRY_create_by_OBJ(X509_NAME_ENTRY **,
+ ASN1_OBJECT *, int,
+ const unsigned char *, int);
+int X509_NAME_add_entry_by_OBJ(X509_NAME *, ASN1_OBJECT *, int,
+ unsigned char *, int, int, int);
-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 *);
int sk_X509_NAME_ENTRY_num(Cryptography_STACK_OF_X509_NAME_ENTRY *);
+Cryptography_STACK_OF_X509_NAME_ENTRY *sk_X509_NAME_ENTRY_new_null(void);
+int sk_X509_NAME_ENTRY_push(Cryptography_STACK_OF_X509_NAME_ENTRY *,
+ X509_NAME_ENTRY *);
X509_NAME_ENTRY *sk_X509_NAME_ENTRY_value(
Cryptography_STACK_OF_X509_NAME_ENTRY *, int);
+Cryptography_STACK_OF_X509_NAME_ENTRY *sk_X509_NAME_ENTRY_dup(
+ Cryptography_STACK_OF_X509_NAME_ENTRY *
+);
"""
CUSTOMIZATIONS = """
+#if CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+int Cryptography_X509_NAME_ENTRY_set(X509_NAME_ENTRY *ne) {
+ return X509_NAME_ENTRY_set(ne);
+}
+#else
+int Cryptography_X509_NAME_ENTRY_set(X509_NAME_ENTRY *ne) {
+ return ne->set;
+}
+#endif
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/openssl/x509v3.py b/src/_cffi_src/openssl/x509v3.py
index 166fa59d..59681206 100644
--- a/src/_cffi_src/openssl/x509v3.py
+++ b/src/_cffi_src/openssl/x509v3.py
@@ -14,11 +14,8 @@ INCLUDES = """
* together with another opaque typedef for the same name in the TYPES section.
* Note that the result is an opaque type.
*/
-#if OPENSSL_VERSION_NUMBER >= 0x10000000
typedef LHASH_OF(CONF_VALUE) Cryptography_LHASH_OF_CONF_VALUE;
-#else
-typedef LHASH Cryptography_LHASH_OF_CONF_VALUE;
-#endif
+
typedef STACK_OF(ACCESS_DESCRIPTION) Cryptography_STACK_OF_ACCESS_DESCRIPTION;
typedef STACK_OF(DIST_POINT) Cryptography_STACK_OF_DIST_POINT;
typedef STACK_OF(POLICYQUALINFO) Cryptography_STACK_OF_POLICYQUALINFO;
@@ -33,6 +30,8 @@ typedef ... Cryptography_STACK_OF_POLICYQUALINFO;
typedef ... Cryptography_STACK_OF_POLICYINFO;
typedef ... Cryptography_STACK_OF_ASN1_INTEGER;
typedef ... Cryptography_STACK_OF_GENERAL_SUBTREE;
+typedef ... EXTENDED_KEY_USAGE;
+typedef ... CONF;
typedef struct {
X509 *issuer_cert;
@@ -42,12 +41,6 @@ typedef struct {
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;
@@ -59,7 +52,8 @@ static const int GEN_IPADD;
static const int GEN_RID;
typedef struct {
- ...;
+ ASN1_OBJECT *type_id;
+ ASN1_TYPE *value;
} OTHERNAME;
typedef struct {
@@ -76,6 +70,11 @@ typedef struct {
Cryptography_STACK_OF_GENERAL_SUBTREE *excludedSubtrees;
} NAME_CONSTRAINTS;
+typedef struct {
+ ASN1_INTEGER *requireExplicitPolicy;
+ ASN1_INTEGER *inhibitPolicyMapping;
+} POLICY_CONSTRAINTS;
+
typedef struct {
int type;
@@ -143,6 +142,15 @@ typedef struct {
} DIST_POINT;
typedef struct {
+ DIST_POINT_NAME *distpoint;
+ int onlyuser;
+ int onlyCA;
+ ASN1_BIT_STRING *onlysomereasons;
+ int indirectCRL;
+ int onlyattr;
+} ISSUING_DIST_POINT;
+
+typedef struct {
ASN1_STRING *organization;
Cryptography_STACK_OF_ASN1_INTEGER *noticenos;
} NOTICEREF;
@@ -165,35 +173,55 @@ typedef struct {
ASN1_OBJECT *policyid;
Cryptography_STACK_OF_POLICYQUALINFO *qualifiers;
} POLICYINFO;
+
+typedef void (*sk_GENERAL_NAME_freefunc)(GENERAL_NAME *);
+typedef void (*sk_DIST_POINT_freefunc)(DIST_POINT *);
+typedef void (*sk_POLICYINFO_freefunc)(POLICYINFO *);
+typedef void (*sk_ACCESS_DESCRIPTION_freefunc)(ACCESS_DESCRIPTION *);
"""
FUNCTIONS = """
int X509V3_EXT_add_alias(int, int);
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 *);
+GENERAL_NAMES *GENERAL_NAMES_new(void);
void GENERAL_NAMES_free(GENERAL_NAMES *);
void *X509V3_EXT_d2i(X509_EXTENSION *);
-"""
-
-MACROS = """
+int X509_check_ca(X509 *);
+/* X509 became a const arg in 1.1.0 */
+void *X509_get_ext_d2i(X509 *, int, int *, int *);
+/* The last two char * args became const char * in 1.1.0 */
+X509_EXTENSION *X509V3_EXT_nconf(CONF *, X509V3_CTX *, char *, char *);
/* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the
x509v3.h header. */
-int i2d_BASIC_CONSTRAINTS(BASIC_CONSTRAINTS *, unsigned char **);
BASIC_CONSTRAINTS *BASIC_CONSTRAINTS_new(void);
void BASIC_CONSTRAINTS_free(BASIC_CONSTRAINTS *);
/* This is a macro defined by a call to DECLARE_ASN1_FUNCTIONS in the
x509v3.h header. */
+AUTHORITY_KEYID *AUTHORITY_KEYID_new(void);
void AUTHORITY_KEYID_free(AUTHORITY_KEYID *);
NAME_CONSTRAINTS *NAME_CONSTRAINTS_new(void);
void NAME_CONSTRAINTS_free(NAME_CONSTRAINTS *);
+OTHERNAME *OTHERNAME_new(void);
+void OTHERNAME_free(OTHERNAME *);
+
+POLICY_CONSTRAINTS *POLICY_CONSTRAINTS_new(void);
+void POLICY_CONSTRAINTS_free(POLICY_CONSTRAINTS *);
+
void *X509V3_set_ctx_nodb(X509V3_CTX *);
+
+int i2d_GENERAL_NAMES(GENERAL_NAMES *, unsigned char **);
+GENERAL_NAMES *d2i_GENERAL_NAMES(GENERAL_NAMES **, const unsigned char **,
+ long);
+
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);
+void sk_GENERAL_NAME_pop_free(struct stack_st_GENERAL_NAME *,
+ sk_GENERAL_NAME_freefunc);
Cryptography_STACK_OF_ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_new_null(void);
int sk_ACCESS_DESCRIPTION_num(Cryptography_STACK_OF_ACCESS_DESCRIPTION *);
@@ -201,29 +229,56 @@ ACCESS_DESCRIPTION *sk_ACCESS_DESCRIPTION_value(
Cryptography_STACK_OF_ACCESS_DESCRIPTION *, int
);
void sk_ACCESS_DESCRIPTION_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *);
+void sk_ACCESS_DESCRIPTION_pop_free(Cryptography_STACK_OF_ACCESS_DESCRIPTION *,
+ sk_ACCESS_DESCRIPTION_freefunc);
int sk_ACCESS_DESCRIPTION_push(Cryptography_STACK_OF_ACCESS_DESCRIPTION *,
ACCESS_DESCRIPTION *);
+ACCESS_DESCRIPTION *ACCESS_DESCRIPTION_new(void);
+void ACCESS_DESCRIPTION_free(ACCESS_DESCRIPTION *);
+
X509_EXTENSION *X509V3_EXT_conf_nid(Cryptography_LHASH_OF_CONF_VALUE *,
X509V3_CTX *, int, char *);
-/* 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);
-
+Cryptography_STACK_OF_DIST_POINT *sk_DIST_POINT_new_null(void);
void sk_DIST_POINT_free(Cryptography_STACK_OF_DIST_POINT *);
int sk_DIST_POINT_num(Cryptography_STACK_OF_DIST_POINT *);
DIST_POINT *sk_DIST_POINT_value(Cryptography_STACK_OF_DIST_POINT *, int);
+int sk_DIST_POINT_push(Cryptography_STACK_OF_DIST_POINT *, DIST_POINT *);
+void sk_DIST_POINT_pop_free(Cryptography_STACK_OF_DIST_POINT *,
+ sk_DIST_POINT_freefunc);
+void CRL_DIST_POINTS_free(Cryptography_STACK_OF_DIST_POINT *);
void sk_POLICYINFO_free(Cryptography_STACK_OF_POLICYINFO *);
int sk_POLICYINFO_num(Cryptography_STACK_OF_POLICYINFO *);
POLICYINFO *sk_POLICYINFO_value(Cryptography_STACK_OF_POLICYINFO *, int);
+int sk_POLICYINFO_push(Cryptography_STACK_OF_POLICYINFO *, POLICYINFO *);
+Cryptography_STACK_OF_POLICYINFO *sk_POLICYINFO_new_null(void);
+void sk_POLICYINFO_pop_free(Cryptography_STACK_OF_POLICYINFO *,
+ sk_POLICYINFO_freefunc);
+void CERTIFICATEPOLICIES_free(Cryptography_STACK_OF_POLICYINFO *);
+
+POLICYINFO *POLICYINFO_new(void);
+void POLICYINFO_free(POLICYINFO *);
+
+POLICYQUALINFO *POLICYQUALINFO_new(void);
+void POLICYQUALINFO_free(POLICYQUALINFO *);
+
+NOTICEREF *NOTICEREF_new(void);
+void NOTICEREF_free(NOTICEREF *);
+
+USERNOTICE *USERNOTICE_new(void);
+void USERNOTICE_free(USERNOTICE *);
void sk_POLICYQUALINFO_free(Cryptography_STACK_OF_POLICYQUALINFO *);
int sk_POLICYQUALINFO_num(Cryptography_STACK_OF_POLICYQUALINFO *);
POLICYQUALINFO *sk_POLICYQUALINFO_value(Cryptography_STACK_OF_POLICYQUALINFO *,
int);
+int sk_POLICYQUALINFO_push(Cryptography_STACK_OF_POLICYQUALINFO *,
+ POLICYQUALINFO *);
+Cryptography_STACK_OF_POLICYQUALINFO *sk_POLICYQUALINFO_new_null(void);
+Cryptography_STACK_OF_GENERAL_SUBTREE *sk_GENERAL_SUBTREE_new_null(void);
void sk_GENERAL_SUBTREE_free(Cryptography_STACK_OF_GENERAL_SUBTREE *);
int sk_GENERAL_SUBTREE_num(Cryptography_STACK_OF_GENERAL_SUBTREE *);
GENERAL_SUBTREE *sk_GENERAL_SUBTREE_value(
@@ -232,14 +287,28 @@ GENERAL_SUBTREE *sk_GENERAL_SUBTREE_value(
int sk_GENERAL_SUBTREE_push(Cryptography_STACK_OF_GENERAL_SUBTREE *,
GENERAL_SUBTREE *);
+GENERAL_SUBTREE *GENERAL_SUBTREE_new(void);
+
void sk_ASN1_INTEGER_free(Cryptography_STACK_OF_ASN1_INTEGER *);
int sk_ASN1_INTEGER_num(Cryptography_STACK_OF_ASN1_INTEGER *);
ASN1_INTEGER *sk_ASN1_INTEGER_value(Cryptography_STACK_OF_ASN1_INTEGER *, int);
+int sk_ASN1_INTEGER_push(Cryptography_STACK_OF_ASN1_INTEGER *, ASN1_INTEGER *);
+Cryptography_STACK_OF_ASN1_INTEGER *sk_ASN1_INTEGER_new_null(void);
X509_EXTENSION *X509V3_EXT_i2d(int, int, void *);
+
+DIST_POINT *DIST_POINT_new(void);
+void DIST_POINT_free(DIST_POINT *);
+
+DIST_POINT_NAME *DIST_POINT_NAME_new(void);
+void DIST_POINT_NAME_free(DIST_POINT_NAME *);
+
+GENERAL_NAME *GENERAL_NAME_new(void);
+void GENERAL_NAME_free(GENERAL_NAME *);
+
+ISSUING_DIST_POINT *ISSUING_DIST_POINT_new(void);
+void ISSUING_DIST_POINT_free(ISSUING_DIST_POINT *);
"""
CUSTOMIZATIONS = """
"""
-
-CONDITIONAL_NAMES = {}
diff --git a/src/_cffi_src/utils.py b/src/_cffi_src/utils.py
index 65f9f120..eecd6ea1 100644
--- a/src/_cffi_src/utils.py
+++ b/src/_cffi_src/utils.py
@@ -4,61 +4,53 @@
from __future__ import absolute_import, division, print_function
+import os
import sys
+from distutils.ccompiler import new_compiler
+from distutils.dist import Distribution
from cffi import FFI
-def build_ffi_for_binding(module_name, module_prefix, modules, pre_include="",
- post_include="", libraries=[], extra_compile_args=[],
- extra_link_args=[]):
+# Load the cryptography __about__ to get the current package version
+base_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+about = {}
+with open(os.path.join(base_src, "cryptography", "__about__.py")) as f:
+ exec(f.read(), about)
+
+
+def build_ffi_for_binding(module_name, module_prefix, modules, 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.
+ * ``FUNCTIONS``: A string containing C declarations for functions & 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:
__import__(module_prefix + name)
module = sys.modules[module_prefix + 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(
module_name,
- cdef_source="\n".join(types + functions + macros),
+ cdef_source="\n".join(types + functions),
verify_source=verify_source,
libraries=libraries,
extra_compile_args=extra_compile_args,
@@ -71,6 +63,11 @@ def build_ffi_for_binding(module_name, module_prefix, modules, pre_include="",
def build_ffi(module_name, cdef_source, verify_source, libraries=[],
extra_compile_args=[], extra_link_args=[]):
ffi = FFI()
+ # Always add the CRYPTOGRAPHY_PACKAGE_VERSION to the shared object
+ cdef_source += "\nstatic const char *const CRYPTOGRAPHY_PACKAGE_VERSION;"
+ verify_source += '\n#define CRYPTOGRAPHY_PACKAGE_VERSION "{}"'.format(
+ about["__version__"]
+ )
ffi.cdef(cdef_source)
ffi.set_source(
module_name,
@@ -82,10 +79,23 @@ def build_ffi(module_name, cdef_source, verify_source, libraries=[],
return ffi
-def extra_link_args(platform):
- if platform != "win32":
- return []
+def extra_link_args(compiler_type):
+ if compiler_type == 'msvc':
+ # Enable NX and ASLR for Windows builds on MSVC. These are enabled by
+ # default on Python 3.3+ but not on 2.x.
+ return ['/NXCOMPAT', '/DYNAMICBASE']
else:
- # Enable NX and ASLR for Windows builds. These are enabled by default
- # on Python 3.3+ but not on 2.x.
- return ["/NXCOMPAT", "/DYNAMICBASE"]
+ return []
+
+
+def compiler_type():
+ """
+ Gets the compiler type from distutils. On Windows with MSVC it will be
+ "msvc". On macOS and linux it is "unix".
+ """
+ dist = Distribution()
+ dist.parse_config_files()
+ cmd = dist.get_command_obj('build')
+ cmd.ensure_finalized()
+ compiler = new_compiler(compiler=cmd.compiler)
+ return compiler.compiler_type
diff --git a/src/cryptography/__about__.py b/src/cryptography/__about__.py
index 9c28be2e..92d5042e 100644
--- a/src/cryptography/__about__.py
+++ b/src/cryptography/__about__.py
@@ -14,10 +14,10 @@ __summary__ = ("cryptography is a package which provides cryptographic recipes"
" and primitives to Python developers.")
__uri__ = "https://github.com/pyca/cryptography"
-__version__ = "1.0.dev1"
+__version__ = "3.0.dev1"
__author__ = "The cryptography developers"
__email__ = "cryptography-dev@python.org"
__license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2013-2015 {0}".format(__author__)
+__copyright__ = "Copyright 2013-2019 {}".format(__author__)
diff --git a/src/cryptography/__init__.py b/src/cryptography/__init__.py
index 985ebd6f..bd2a8102 100644
--- a/src/cryptography/__init__.py
+++ b/src/cryptography/__init__.py
@@ -11,6 +11,7 @@ from cryptography.__about__ import (
__author__, __copyright__, __email__, __license__, __summary__, __title__,
__uri__, __version__
)
+from cryptography.utils import CryptographyDeprecationWarning
__all__ = [
@@ -18,9 +19,10 @@ __all__ = [
"__email__", "__license__", "__copyright__",
]
-if sys.version_info[:2] == (2, 6):
+if sys.version_info[0] == 2:
warnings.warn(
- "Python 2.6 is no longer supported by the Python core team, please "
- "upgrade your Python.",
- DeprecationWarning
+ "Python 2 is no longer supported by the Python core team. Support for "
+ "it is now deprecated in cryptography, and will be removed in a "
+ "future release.",
+ CryptographyDeprecationWarning
)
diff --git a/src/cryptography/exceptions.py b/src/cryptography/exceptions.py
index a4292eb8..1d52d7dc 100644
--- a/src/cryptography/exceptions.py
+++ b/src/cryptography/exceptions.py
@@ -6,9 +6,6 @@ from __future__ import absolute_import, division, print_function
from enum import Enum
-from cryptography import utils
-from cryptography.hazmat.primitives import twofactor
-
class _Reasons(Enum):
BACKEND_MISSING_INTERFACE = 0
@@ -20,6 +17,9 @@ class _Reasons(Enum):
UNSUPPORTED_ELLIPTIC_CURVE = 6
UNSUPPORTED_SERIALIZATION = 7
UNSUPPORTED_X509 = 8
+ UNSUPPORTED_EXCHANGE_ALGORITHM = 9
+ UNSUPPORTED_DIFFIE_HELLMAN = 10
+ UNSUPPORTED_MAC = 11
class UnsupportedAlgorithm(Exception):
@@ -49,19 +49,10 @@ class InvalidSignature(Exception):
class InternalError(Exception):
- pass
+ def __init__(self, msg, err_code):
+ super(InternalError, self).__init__(msg)
+ self.err_code = err_code
class InvalidKey(Exception):
pass
-
-
-InvalidToken = utils.deprecated(
- twofactor.InvalidToken,
- __name__,
- (
- "The InvalidToken exception has moved to the "
- "cryptography.hazmat.primitives.twofactor module"
- ),
- utils.DeprecatedIn09
-)
diff --git a/src/cryptography/fernet.py b/src/cryptography/fernet.py
index 6fbe9f27..862d9466 100644
--- a/src/cryptography/fernet.py
+++ b/src/cryptography/fernet.py
@@ -12,6 +12,7 @@ import time
import six
+from cryptography import utils
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, padding
@@ -46,13 +47,14 @@ class Fernet(object):
return base64.urlsafe_b64encode(os.urandom(32))
def encrypt(self, data):
- current_time = int(time.time())
+ return self.encrypt_at_time(data, int(time.time()))
+
+ def encrypt_at_time(self, data, current_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.")
+ utils._check_bytes("data", data)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(data) + padder.finalize()
@@ -71,11 +73,21 @@ class Fernet(object):
return base64.urlsafe_b64encode(basic_parts + hmac)
def decrypt(self, token, ttl=None):
- if not isinstance(token, bytes):
- raise TypeError("token must be bytes.")
+ return self.decrypt_at_time(token, ttl, int(time.time()))
+
+ def decrypt_at_time(self, token, ttl, current_time):
+ timestamp, data = Fernet._get_unverified_token_data(token)
+ return self._decrypt_data(data, timestamp, ttl, current_time)
- current_time = int(time.time())
+ def extract_timestamp(self, token):
+ timestamp, data = Fernet._get_unverified_token_data(token)
+ # Verify the token was not tampered with.
+ self._verify_signature(data)
+ return timestamp
+ @staticmethod
+ def _get_unverified_token_data(token):
+ utils._check_bytes("token", token)
try:
data = base64.urlsafe_b64decode(token)
except (TypeError, binascii.Error):
@@ -88,11 +100,9 @@ class Fernet(object):
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
+ return timestamp, data
+
+ def _verify_signature(self, data):
h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
h.update(data[:-32])
try:
@@ -100,6 +110,16 @@ class Fernet(object):
except InvalidSignature:
raise InvalidToken
+ def _decrypt_data(self, data, timestamp, ttl, current_time):
+ if ttl is not None:
+ if timestamp + ttl < current_time:
+ raise InvalidToken
+
+ if current_time + _MAX_CLOCK_SKEW < timestamp:
+ raise InvalidToken
+
+ self._verify_signature(data)
+
iv = data[9:25]
ciphertext = data[25:-32]
decryptor = Cipher(
@@ -130,12 +150,32 @@ class MultiFernet(object):
self._fernets = fernets
def encrypt(self, msg):
- return self._fernets[0].encrypt(msg)
+ return self.encrypt_at_time(msg, int(time.time()))
+
+ def encrypt_at_time(self, msg, current_time):
+ return self._fernets[0].encrypt_at_time(msg, current_time)
+
+ def rotate(self, msg):
+ timestamp, data = Fernet._get_unverified_token_data(msg)
+ for f in self._fernets:
+ try:
+ p = f._decrypt_data(data, timestamp, None, None)
+ break
+ except InvalidToken:
+ pass
+ else:
+ raise InvalidToken
+
+ iv = os.urandom(16)
+ return self._fernets[0]._encrypt_from_parts(p, timestamp, iv)
def decrypt(self, msg, ttl=None):
+ return self.decrypt_at_time(msg, ttl, int(time.time()))
+
+ def decrypt_at_time(self, msg, ttl, current_time):
for f in self._fernets:
try:
- return f.decrypt(msg, ttl)
+ return f.decrypt_at_time(msg, ttl, current_time)
except InvalidToken:
pass
raise InvalidToken
diff --git a/src/cryptography/hazmat/__init__.py b/src/cryptography/hazmat/__init__.py
index 4b540884..9f06a994 100644
--- a/src/cryptography/hazmat/__init__.py
+++ b/src/cryptography/hazmat/__init__.py
@@ -1,5 +1,11 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.
+"""
+Hazardous Materials
+This is a "Hazardous Materials" module. You should ONLY use it if you're
+100% absolutely sure that you know what you're doing because this module
+is full of land mines, dragons, and dinosaurs with laser guns.
+"""
from __future__ import absolute_import, division, print_function
diff --git a/src/cryptography/hazmat/_der.py b/src/cryptography/hazmat/_der.py
new file mode 100644
index 00000000..51518d64
--- /dev/null
+++ b/src/cryptography/hazmat/_der.py
@@ -0,0 +1,156 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import six
+
+from cryptography.utils import int_from_bytes, int_to_bytes
+
+
+# This module contains a lightweight DER encoder and decoder. See X.690 for the
+# specification. This module intentionally does not implement the more complex
+# BER encoding, only DER.
+#
+# Note this implementation treats an element's constructed bit as part of the
+# tag. This is fine for DER, where the bit is always computable from the type.
+
+
+CONSTRUCTED = 0x20
+CONTEXT_SPECIFIC = 0x80
+
+INTEGER = 0x02
+BIT_STRING = 0x03
+OCTET_STRING = 0x04
+NULL = 0x05
+OBJECT_IDENTIFIER = 0x06
+SEQUENCE = 0x10 | CONSTRUCTED
+SET = 0x11 | CONSTRUCTED
+PRINTABLE_STRING = 0x13
+UTC_TIME = 0x17
+GENERALIZED_TIME = 0x18
+
+
+class DERReader(object):
+ def __init__(self, data):
+ self.data = memoryview(data)
+
+ def __enter__(self):
+ return self
+
+ def __exit__(self, exc_type, exc_value, tb):
+ if exc_value is None:
+ self.check_empty()
+
+ def is_empty(self):
+ return len(self.data) == 0
+
+ def check_empty(self):
+ if not self.is_empty():
+ raise ValueError("Invalid DER input: trailing data")
+
+ def read_byte(self):
+ if len(self.data) < 1:
+ raise ValueError("Invalid DER input: insufficient data")
+ ret = six.indexbytes(self.data, 0)
+ self.data = self.data[1:]
+ return ret
+
+ def read_bytes(self, n):
+ if len(self.data) < n:
+ raise ValueError("Invalid DER input: insufficient data")
+ ret = self.data[:n]
+ self.data = self.data[n:]
+ return ret
+
+ def read_any_element(self):
+ tag = self.read_byte()
+ # Tag numbers 31 or higher are stored in multiple bytes. No supported
+ # ASN.1 types use such tags, so reject these.
+ if tag & 0x1f == 0x1f:
+ raise ValueError("Invalid DER input: unexpected high tag number")
+ length_byte = self.read_byte()
+ if length_byte & 0x80 == 0:
+ # If the high bit is clear, the first length byte is the length.
+ length = length_byte
+ else:
+ # If the high bit is set, the first length byte encodes the length
+ # of the length.
+ length_byte &= 0x7f
+ if length_byte == 0:
+ raise ValueError(
+ "Invalid DER input: indefinite length form is not allowed "
+ "in DER"
+ )
+ length = 0
+ for i in range(length_byte):
+ length <<= 8
+ length |= self.read_byte()
+ if length == 0:
+ raise ValueError(
+ "Invalid DER input: length was not minimally-encoded"
+ )
+ if length < 0x80:
+ # If the length could have been encoded in short form, it must
+ # not use long form.
+ raise ValueError(
+ "Invalid DER input: length was not minimally-encoded"
+ )
+ body = self.read_bytes(length)
+ return tag, DERReader(body)
+
+ def read_element(self, expected_tag):
+ tag, body = self.read_any_element()
+ if tag != expected_tag:
+ raise ValueError("Invalid DER input: unexpected tag")
+ return body
+
+ def read_single_element(self, expected_tag):
+ with self:
+ return self.read_element(expected_tag)
+
+ def read_optional_element(self, expected_tag):
+ if len(self.data) > 0 and six.indexbytes(self.data, 0) == expected_tag:
+ return self.read_element(expected_tag)
+ return None
+
+ def as_integer(self):
+ if len(self.data) == 0:
+ raise ValueError("Invalid DER input: empty integer contents")
+ first = six.indexbytes(self.data, 0)
+ if first & 0x80 == 0x80:
+ raise ValueError("Negative DER integers are not supported")
+ # The first 9 bits must not all be zero or all be ones. Otherwise, the
+ # encoding should have been one byte shorter.
+ if len(self.data) > 1:
+ second = six.indexbytes(self.data, 1)
+ if first == 0 and second & 0x80 == 0:
+ raise ValueError(
+ "Invalid DER input: integer not minimally-encoded"
+ )
+ return int_from_bytes(self.data, "big")
+
+
+def encode_der_integer(x):
+ if not isinstance(x, six.integer_types):
+ raise ValueError("Value must be an integer")
+ if x < 0:
+ raise ValueError("Negative integers are not supported")
+ n = x.bit_length() // 8 + 1
+ return int_to_bytes(x, n)
+
+
+def encode_der(tag, *children):
+ length = 0
+ for child in children:
+ length += len(child)
+ chunks = [six.int2byte(tag)]
+ if length < 0x80:
+ chunks.append(six.int2byte(length))
+ else:
+ length_bytes = int_to_bytes(length)
+ chunks.append(six.int2byte(0x80 | len(length_bytes)))
+ chunks.append(length_bytes)
+ chunks.extend(children)
+ return b"".join(chunks)
diff --git a/src/cryptography/hazmat/_oid.py b/src/cryptography/hazmat/_oid.py
new file mode 100644
index 00000000..f98912f9
--- /dev/null
+++ b/src/cryptography/hazmat/_oid.py
@@ -0,0 +1,72 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import utils
+
+
+class ObjectIdentifier(object):
+ def __init__(self, dotted_string):
+ self._dotted_string = dotted_string
+
+ nodes = self._dotted_string.split(".")
+ intnodes = []
+
+ # There must be at least 2 nodes, the first node must be 0..2, and
+ # if less than 2, the second node cannot have a value outside the
+ # range 0..39. All nodes must be integers.
+ for node in nodes:
+ try:
+ node_value = int(node, 10)
+ except ValueError:
+ raise ValueError(
+ "Malformed OID: %s (non-integer nodes)" % (
+ self._dotted_string))
+ if node_value < 0:
+ raise ValueError(
+ "Malformed OID: %s (negative-integer nodes)" % (
+ self._dotted_string))
+ intnodes.append(node_value)
+
+ if len(nodes) < 2:
+ raise ValueError(
+ "Malformed OID: %s (insufficient number of nodes)" % (
+ self._dotted_string))
+
+ if intnodes[0] > 2:
+ raise ValueError(
+ "Malformed OID: %s (first node outside valid range)" % (
+ self._dotted_string))
+
+ if intnodes[0] < 2 and intnodes[1] >= 40:
+ raise ValueError(
+ "Malformed OID: %s (second node outside valid range)" % (
+ self._dotted_string))
+
+ def __eq__(self, other):
+ if not isinstance(other, ObjectIdentifier):
+ return NotImplemented
+
+ return self.dotted_string == other.dotted_string
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __repr__(self):
+ return "<ObjectIdentifier(oid={}, name={})>".format(
+ self.dotted_string,
+ self._name
+ )
+
+ def __hash__(self):
+ return hash(self.dotted_string)
+
+ @property
+ def _name(self):
+ # Lazy import to avoid an import cycle
+ from cryptography.x509.oid import _OID_NAMES
+ return _OID_NAMES.get(self, "Unknown OID")
+
+ dotted_string = utils.read_only_property("_dotted_string")
diff --git a/src/cryptography/hazmat/backends/__init__.py b/src/cryptography/hazmat/backends/__init__.py
index 256fee39..565bde78 100644
--- a/src/cryptography/hazmat/backends/__init__.py
+++ b/src/cryptography/hazmat/backends/__init__.py
@@ -4,31 +4,6 @@
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 = [
- # setuptools 11.3 deprecated support for the require parameter to
- # load(), and introduced the new resolve() method instead.
- # This can be removed if/when we can assume setuptools>=11.3. At
- # some point we may wish to add a warning, to push people along,
- # but at present this would result in too many warnings.
- ep.resolve() if hasattr(ep, "resolve") else ep.load(require=False)
- for ep in pkg_resources.iter_entry_points(
- "cryptography.backends"
- )
- ]
-
- return _available_backends_list
_default_backend = None
@@ -37,6 +12,7 @@ def default_backend():
global _default_backend
if _default_backend is None:
- _default_backend = MultiBackend(_available_backends())
+ from cryptography.hazmat.backends.openssl.backend import backend
+ _default_backend = backend
return _default_backend
diff --git a/src/cryptography/hazmat/backends/commoncrypto/backend.py b/src/cryptography/hazmat/backends/commoncrypto/backend.py
deleted file mode 100644
index 091fbb7c..00000000
--- a/src/cryptography/hazmat/backends/commoncrypto/backend.py
+++ /dev/null
@@ -1,244 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from 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
deleted file mode 100644
index 1ce8aec5..00000000
--- a/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
+++ /dev/null
@@ -1,193 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from cryptography import utils
-from cryptography.exceptions import (
- InvalidTag, UnsupportedAlgorithm, _Reasons
-)
-from cryptography.hazmat.primitives import ciphers, constant_time
-from cryptography.hazmat.primitives.ciphers import modes
-from cryptography.hazmat.primitives.ciphers.modes import (
- CFB, CFB8, CTR, OFB
-)
-
-
-@utils.register_interface(ciphers.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, ciphers.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, modes.ModeWithInitializationVector):
- iv_nonce = mode.initialization_vector
- elif isinstance(mode, modes.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(ciphers.AEADCipherContext)
-@utils.register_interface(ciphers.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
deleted file mode 100644
index a54e9833..00000000
--- a/src/cryptography/hazmat/backends/commoncrypto/hashes.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
-from cryptography.hazmat.primitives import hashes
-
-
-@utils.register_interface(hashes.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
deleted file mode 100644
index ae623d84..00000000
--- a/src/cryptography/hazmat/backends/commoncrypto/hmac.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from cryptography import utils
-from cryptography.exceptions import (
- InvalidSignature, UnsupportedAlgorithm, _Reasons
-)
-from cryptography.hazmat.primitives import constant_time, hashes, interfaces
-
-
-@utils.register_interface(interfaces.MACContext)
-@utils.register_interface(hashes.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
index 4d378e6b..20f4164e 100644
--- a/src/cryptography/hazmat/backends/interfaces.py
+++ b/src/cryptography/hazmat/backends/interfaces.py
@@ -57,7 +57,7 @@ class HMACBackend(object):
@abc.abstractmethod
def create_hmac_ctx(self, key, algorithm):
"""
- Create a MACContext for calculating a message authentication code.
+ Create a context for calculating a message authentication code.
"""
@@ -72,7 +72,7 @@ class CMACBackend(object):
@abc.abstractmethod
def create_cmac_ctx(self, algorithm):
"""
- Create a MACContext for calculating a message authentication code.
+ Create a context for calculating a message authentication code.
"""
@@ -212,7 +212,19 @@ class EllipticCurveBackend(object):
@abc.abstractmethod
def load_elliptic_curve_private_numbers(self, numbers):
"""
- Return an EllipticCurvePublicKey provider using the given numbers.
+ Return an EllipticCurvePrivateKey provider using the given numbers.
+ """
+
+ @abc.abstractmethod
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
+ """
+ Returns whether the exchange algorithm is supported by this backend.
+ """
+
+ @abc.abstractmethod
+ def derive_elliptic_curve_private_key(self, private_value, curve):
+ """
+ Compute the private key given the private value and curve.
"""
@@ -231,6 +243,12 @@ class PEMSerializationBackend(object):
Loads a public key from PEM encoded data.
"""
+ @abc.abstractmethod
+ def load_pem_parameters(self, data):
+ """
+ Load encryption parameters from PEM encoded data.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DERSerializationBackend(object):
@@ -247,6 +265,12 @@ class DERSerializationBackend(object):
Loads a public key from DER encoded data.
"""
+ @abc.abstractmethod
+ def load_der_parameters(self, data):
+ """
+ Load encryption parameters from DER encoded data.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class X509Backend(object):
@@ -280,13 +304,40 @@ class X509Backend(object):
Create and sign an X.509 CSR from a CSR builder object.
"""
+ @abc.abstractmethod
+ def create_x509_certificate(self, builder, private_key, algorithm):
+ """
+ Create and sign an X.509 certificate from a CertificateBuilder object.
+ """
+
+ @abc.abstractmethod
+ def create_x509_crl(self, builder, private_key, algorithm):
+ """
+ Create and sign an X.509 CertificateRevocationList from a
+ CertificateRevocationListBuilder object.
+ """
+
+ @abc.abstractmethod
+ def create_x509_revoked_certificate(self, builder):
+ """
+ Create a RevokedCertificate object from a RevokedCertificateBuilder
+ object.
+ """
+
+ @abc.abstractmethod
+ def x509_name_bytes(self, name):
+ """
+ Compute the DER encoded bytes of an X509 Name object.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DHBackend(object):
@abc.abstractmethod
- def generate_dh_parameters(self, key_size):
+ def generate_dh_parameters(self, generator, key_size):
"""
Generate a DHParameters instance with a modulus of key_size bits.
+ Using the given generator. Often 2 or 5.
"""
@abc.abstractmethod
@@ -297,37 +348,48 @@ class DHBackend(object):
"""
@abc.abstractmethod
- def generate_dh_private_key_and_parameters(self, key_size):
+ def generate_dh_private_key_and_parameters(self, generator, key_size):
"""
Generate a DHPrivateKey instance using key size only.
+ Using the given generator. Often 2 or 5.
"""
@abc.abstractmethod
def load_dh_private_numbers(self, numbers):
"""
- Returns a DHPrivateKey provider.
+ Load a DHPrivateKey from DHPrivateNumbers
"""
@abc.abstractmethod
def load_dh_public_numbers(self, numbers):
"""
- Returns a DHPublicKey provider.
+ Load a DHPublicKey from DHPublicNumbers.
"""
@abc.abstractmethod
def load_dh_parameter_numbers(self, numbers):
"""
- Returns a DHParameters provider.
+ Load DHParameters from DHParameterNumbers.
"""
@abc.abstractmethod
- def dh_exchange_algorithm_supported(self, exchange_algorithm):
+ def dh_parameters_supported(self, p, g, q=None):
"""
- Returns whether the exchange algorithm is supported by this backend.
+ Returns whether the backend supports DH with these parameter values.
"""
@abc.abstractmethod
- def dh_parameters_supported(self, p, g):
+ def dh_x942_serialization_supported(self):
"""
- Returns whether the backend supports DH with these parameter values.
+ Returns True if the backend supports the serialization of DH objects
+ with subgroup order (q).
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ScryptBackend(object):
+ @abc.abstractmethod
+ def derive_scrypt(self, key_material, salt, length, n, r, p):
+ """
+ Return bytes derived from provided Scrypt parameters.
"""
diff --git a/src/cryptography/hazmat/backends/multibackend.py b/src/cryptography/hazmat/backends/multibackend.py
deleted file mode 100644
index 6e911fd5..00000000
--- a/src/cryptography/hazmat/backends/multibackend.py
+++ /dev/null
@@ -1,353 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
-from cryptography.hazmat.backends.interfaces import (
- CMACBackend, CipherBackend, DERSerializationBackend, DSABackend,
- EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- PEMSerializationBackend, RSABackend, X509Backend
-)
-
-
-@utils.register_interface(CMACBackend)
-@utils.register_interface(CipherBackend)
-@utils.register_interface(DERSerializationBackend)
-@utils.register_interface(HashBackend)
-@utils.register_interface(HMACBackend)
-@utils.register_interface(PBKDF2HMACBackend)
-@utils.register_interface(RSABackend)
-@utils.register_interface(DSABackend)
-@utils.register_interface(EllipticCurveBackend)
-@utils.register_interface(PEMSerializationBackend)
-@utils.register_interface(X509Backend)
-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 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 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_der_private_key(self, data, password):
- for b in self._filtered_backends(DERSerializationBackend):
- return b.load_der_private_key(data, password)
-
- raise UnsupportedAlgorithm(
- "This backend does not support this key serialization.",
- _Reasons.UNSUPPORTED_SERIALIZATION
- )
-
- def load_der_public_key(self, data):
- for b in self._filtered_backends(DERSerializationBackend):
- return b.load_der_public_key(data)
-
- raise UnsupportedAlgorithm(
- "This backend does not support this key serialization.",
- _Reasons.UNSUPPORTED_SERIALIZATION
- )
-
- def load_pem_x509_certificate(self, data):
- for b in self._filtered_backends(X509Backend):
- return b.load_pem_x509_certificate(data)
-
- raise UnsupportedAlgorithm(
- "This backend does not support X.509.",
- _Reasons.UNSUPPORTED_X509
- )
-
- def load_der_x509_certificate(self, data):
- for b in self._filtered_backends(X509Backend):
- return b.load_der_x509_certificate(data)
-
- raise UnsupportedAlgorithm(
- "This backend does not support X.509.",
- _Reasons.UNSUPPORTED_X509
- )
-
- def load_der_x509_csr(self, data):
- for b in self._filtered_backends(X509Backend):
- return b.load_der_x509_csr(data)
-
- raise UnsupportedAlgorithm(
- "This backend does not support X.509.",
- _Reasons.UNSUPPORTED_X509
- )
-
- def load_pem_x509_csr(self, data):
- for b in self._filtered_backends(X509Backend):
- return b.load_pem_x509_csr(data)
-
- raise UnsupportedAlgorithm(
- "This backend does not support X.509.",
- _Reasons.UNSUPPORTED_X509
- )
-
- def create_x509_csr(self, builder, private_key, algorithm):
- for b in self._filtered_backends(X509Backend):
- return b.create_x509_csr(builder, private_key, algorithm)
-
- raise UnsupportedAlgorithm(
- "This backend does not support X.509.",
- _Reasons.UNSUPPORTED_X509
- )
diff --git a/src/cryptography/hazmat/backends/openssl/aead.py b/src/cryptography/hazmat/backends/openssl/aead.py
new file mode 100644
index 00000000..0cad15cc
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/aead.py
@@ -0,0 +1,162 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography.exceptions import InvalidTag
+
+
+_ENCRYPT = 1
+_DECRYPT = 0
+
+
+def _aead_cipher_name(cipher):
+ from cryptography.hazmat.primitives.ciphers.aead import (
+ AESCCM, AESGCM, ChaCha20Poly1305
+ )
+ if isinstance(cipher, ChaCha20Poly1305):
+ return b"chacha20-poly1305"
+ elif isinstance(cipher, AESCCM):
+ return "aes-{}-ccm".format(len(cipher._key) * 8).encode("ascii")
+ else:
+ assert isinstance(cipher, AESGCM)
+ return "aes-{}-gcm".format(len(cipher._key) * 8).encode("ascii")
+
+
+def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation):
+ evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name)
+ backend.openssl_assert(evp_cipher != backend._ffi.NULL)
+ ctx = backend._lib.EVP_CIPHER_CTX_new()
+ ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free)
+ res = backend._lib.EVP_CipherInit_ex(
+ ctx, evp_cipher,
+ backend._ffi.NULL,
+ backend._ffi.NULL,
+ backend._ffi.NULL,
+ int(operation == _ENCRYPT)
+ )
+ backend.openssl_assert(res != 0)
+ res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key))
+ backend.openssl_assert(res != 0)
+ res = backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, backend._lib.EVP_CTRL_AEAD_SET_IVLEN, len(nonce),
+ backend._ffi.NULL
+ )
+ backend.openssl_assert(res != 0)
+ if operation == _DECRYPT:
+ res = backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag
+ )
+ backend.openssl_assert(res != 0)
+ elif cipher_name.endswith(b"-ccm"):
+ res = backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL
+ )
+ backend.openssl_assert(res != 0)
+
+ nonce_ptr = backend._ffi.from_buffer(nonce)
+ key_ptr = backend._ffi.from_buffer(key)
+ res = backend._lib.EVP_CipherInit_ex(
+ ctx,
+ backend._ffi.NULL,
+ backend._ffi.NULL,
+ key_ptr,
+ nonce_ptr,
+ int(operation == _ENCRYPT)
+ )
+ backend.openssl_assert(res != 0)
+ return ctx
+
+
+def _set_length(backend, ctx, data_len):
+ intptr = backend._ffi.new("int *")
+ res = backend._lib.EVP_CipherUpdate(
+ ctx,
+ backend._ffi.NULL,
+ intptr,
+ backend._ffi.NULL,
+ data_len
+ )
+ backend.openssl_assert(res != 0)
+
+
+def _process_aad(backend, ctx, associated_data):
+ outlen = backend._ffi.new("int *")
+ res = backend._lib.EVP_CipherUpdate(
+ ctx, backend._ffi.NULL, outlen, associated_data, len(associated_data)
+ )
+ backend.openssl_assert(res != 0)
+
+
+def _process_data(backend, ctx, data):
+ outlen = backend._ffi.new("int *")
+ buf = backend._ffi.new("unsigned char[]", len(data))
+ res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data))
+ backend.openssl_assert(res != 0)
+ return backend._ffi.buffer(buf, outlen[0])[:]
+
+
+def _encrypt(backend, cipher, nonce, data, associated_data, tag_length):
+ from cryptography.hazmat.primitives.ciphers.aead import AESCCM
+ cipher_name = _aead_cipher_name(cipher)
+ ctx = _aead_setup(
+ backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT
+ )
+ # CCM requires us to pass the length of the data before processing anything
+ # However calling this with any other AEAD results in an error
+ if isinstance(cipher, AESCCM):
+ _set_length(backend, ctx, len(data))
+
+ _process_aad(backend, ctx, associated_data)
+ processed_data = _process_data(backend, ctx, data)
+ outlen = backend._ffi.new("int *")
+ res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen)
+ backend.openssl_assert(res != 0)
+ backend.openssl_assert(outlen[0] == 0)
+ tag_buf = backend._ffi.new("unsigned char[]", tag_length)
+ res = backend._lib.EVP_CIPHER_CTX_ctrl(
+ ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf
+ )
+ backend.openssl_assert(res != 0)
+ tag = backend._ffi.buffer(tag_buf)[:]
+
+ return processed_data + tag
+
+
+def _decrypt(backend, cipher, nonce, data, associated_data, tag_length):
+ from cryptography.hazmat.primitives.ciphers.aead import AESCCM
+ if len(data) < tag_length:
+ raise InvalidTag
+ tag = data[-tag_length:]
+ data = data[:-tag_length]
+ cipher_name = _aead_cipher_name(cipher)
+ ctx = _aead_setup(
+ backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT
+ )
+ # CCM requires us to pass the length of the data before processing anything
+ # However calling this with any other AEAD results in an error
+ if isinstance(cipher, AESCCM):
+ _set_length(backend, ctx, len(data))
+
+ _process_aad(backend, ctx, associated_data)
+ # CCM has a different error path if the tag doesn't match. Errors are
+ # raised in Update and Final is irrelevant.
+ if isinstance(cipher, AESCCM):
+ outlen = backend._ffi.new("int *")
+ buf = backend._ffi.new("unsigned char[]", len(data))
+ res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data))
+ if res != 1:
+ backend._consume_errors()
+ raise InvalidTag
+
+ processed_data = backend._ffi.buffer(buf, outlen[0])[:]
+ else:
+ processed_data = _process_data(backend, ctx, data)
+ outlen = backend._ffi.new("int *")
+ res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen)
+ if res == 0:
+ backend._consume_errors()
+ raise InvalidTag
+
+ return processed_data
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 85f65972..952c0f65 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -4,151 +4,105 @@
from __future__ import absolute_import, division, print_function
+import base64
import collections
+import contextlib
import itertools
from contextlib import contextmanager
import six
+from six.moves import range
from cryptography import utils, x509
-from cryptography.exceptions import (
- InternalError, UnsupportedAlgorithm, _Reasons
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat._der import (
+ INTEGER, NULL, SEQUENCE, encode_der, encode_der_integer
)
from cryptography.hazmat.backends.interfaces import (
- CMACBackend, CipherBackend, DERSerializationBackend, DSABackend,
+ CMACBackend, CipherBackend, DERSerializationBackend, DHBackend, DSABackend,
EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- PEMSerializationBackend, RSABackend, X509Backend
-)
-from cryptography.hazmat.backends.openssl.ciphers import (
- _AESCTRCipherContext, _CipherContext
+ PEMSerializationBackend, RSABackend, ScryptBackend, X509Backend
)
+from cryptography.hazmat.backends.openssl import aead
+from cryptography.hazmat.backends.openssl.ciphers import _CipherContext
from cryptography.hazmat.backends.openssl.cmac import _CMACContext
+from cryptography.hazmat.backends.openssl.decode_asn1 import (
+ _CRL_ENTRY_REASON_ENUM_TO_CODE
+)
+from cryptography.hazmat.backends.openssl.dh import (
+ _DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup
+)
from cryptography.hazmat.backends.openssl.dsa import (
_DSAParameters, _DSAPrivateKey, _DSAPublicKey
)
from cryptography.hazmat.backends.openssl.ec import (
_EllipticCurvePrivateKey, _EllipticCurvePublicKey
)
+from cryptography.hazmat.backends.openssl.ed25519 import (
+ _Ed25519PrivateKey, _Ed25519PublicKey
+)
+from cryptography.hazmat.backends.openssl.ed448 import (
+ _ED448_KEY_SIZE, _Ed448PrivateKey, _Ed448PublicKey
+)
+from cryptography.hazmat.backends.openssl.encode_asn1 import (
+ _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
+ _CRL_EXTENSION_ENCODE_HANDLERS, _EXTENSION_ENCODE_HANDLERS,
+ _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS,
+ _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS,
+ _encode_asn1_int_gc, _encode_asn1_str_gc, _encode_name_gc, _txt2obj_gc,
+)
from cryptography.hazmat.backends.openssl.hashes import _HashContext
from cryptography.hazmat.backends.openssl.hmac import _HMACContext
+from cryptography.hazmat.backends.openssl.ocsp import (
+ _OCSPRequest, _OCSPResponse
+)
+from cryptography.hazmat.backends.openssl.poly1305 import (
+ _POLY1305_KEY_SIZE, _Poly1305Context
+)
from cryptography.hazmat.backends.openssl.rsa import (
_RSAPrivateKey, _RSAPublicKey
)
+from cryptography.hazmat.backends.openssl.x25519 import (
+ _X25519PrivateKey, _X25519PublicKey
+)
+from cryptography.hazmat.backends.openssl.x448 import (
+ _X448PrivateKey, _X448PublicKey
+)
from cryptography.hazmat.backends.openssl.x509 import (
- _Certificate, _CertificateSigningRequest
+ _Certificate, _CertificateRevocationList,
+ _CertificateSigningRequest, _RevokedCertificate
)
-from cryptography.hazmat.bindings.openssl.binding import Binding
+from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
+from cryptography.hazmat.primitives.asymmetric import (
+ dsa, ec, ed25519, ed448, 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
+ AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, IDEA, SEED, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import (
- CBC, CFB, CFB8, CTR, ECB, GCM, OFB
+ CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS
)
+from cryptography.hazmat.primitives.kdf import scrypt
+from cryptography.hazmat.primitives.serialization import ssh
+from cryptography.x509 import ocsp
_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
-_OpenSSLError = collections.namedtuple("_OpenSSLError",
- ["code", "lib", "func", "reason"])
-
-
-def _encode_asn1_int(backend, x):
- """
- Converts a python integer to a ASN1_INTEGER. The returned ASN1_INTEGER 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.
-
- """
- # Convert Python integer to OpenSSL "bignum" in case value exceeds
- # machine's native integer limits (note: `int_to_bn` doesn't automatically
- # GC).
- i = backend._int_to_bn(x)
- i = backend._ffi.gc(i, backend._lib.BN_free)
-
- # Wrap in a ASN.1 integer. Don't GC -- as documented.
- i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL)
- assert i != backend._ffi.NULL
- return i
-def _encode_asn1_str(backend, data, length):
- """
- Create an ASN1_OCTET_STRING from a Python byte string.
- """
- s = backend._lib.ASN1_OCTET_STRING_new()
- s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free)
- backend._lib.ASN1_OCTET_STRING_set(s, data, length)
- return s
-
-
-def _encode_name(backend, attributes):
- subject = backend._lib.X509_NAME_new()
- subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
- for attribute in attributes:
- value = attribute.value.encode('utf8')
- obj = _txt2obj(backend, attribute.oid.dotted_string)
- res = backend._lib.X509_NAME_add_entry_by_OBJ(
- subject,
- obj,
- backend._lib.MBSTRING_UTF8,
- value,
- -1, -1, 0,
- )
- assert res == 1
- return subject
-
-
-def _txt2obj(backend, name):
- """
- Converts a Python string with an ASN.1 object ID in dotted form to a
- ASN1_OBJECT.
- """
- name = name.encode('ascii')
- obj = backend._lib.OBJ_txt2obj(name, 1)
- assert obj != backend._ffi.NULL
- obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free)
- return obj
-
-
-def _encode_basic_constraints(backend, basic_constraints, critical):
- obj = _txt2obj(backend, x509.OID_BASIC_CONSTRAINTS.dotted_string)
- assert obj is not None
- constraints = backend._lib.BASIC_CONSTRAINTS_new()
- constraints.ca = 255 if basic_constraints.ca else 0
- if basic_constraints.ca:
- constraints.pathlen = _encode_asn1_int(
- backend, basic_constraints.path_length
- )
-
- # Fetch the encoded payload.
- pp = backend._ffi.new('unsigned char **')
- r = backend._lib.i2d_BASIC_CONSTRAINTS(constraints, pp)
- assert r > 0
- pp = backend._ffi.gc(
- pp, lambda pointer: backend._lib.OPENSSL_free(pointer[0])
- )
-
- # Wrap that in an X509 extension object.
- extension = backend._lib.X509_EXTENSION_create_by_OBJ(
- backend._ffi.NULL,
- obj,
- 1 if critical else 0,
- _encode_asn1_str(backend, pp[0], r),
- )
- assert extension != backend._ffi.NULL
-
- # Return the wrapped extension.
- return extension
+# Not actually supported, just used as a marker for some serialization tests.
+class _RC2(object):
+ pass
@utils.register_interface(CipherBackend)
@utils.register_interface(CMACBackend)
@utils.register_interface(DERSerializationBackend)
+@utils.register_interface(DHBackend)
@utils.register_interface(DSABackend)
@utils.register_interface(EllipticCurveBackend)
@utils.register_interface(HashBackend)
@@ -157,6 +111,9 @@ def _encode_basic_constraints(backend, basic_constraints, critical):
@utils.register_interface(RSABackend)
@utils.register_interface(PEMSerializationBackend)
@utils.register_interface(X509Backend)
+@utils.register_interface_if(
+ binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend
+)
class Backend(object):
"""
OpenSSL API binding interfaces.
@@ -164,73 +121,110 @@ class Backend(object):
name = "openssl"
def __init__(self):
- self._binding = Binding()
+ self._binding = 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()
+ self._dh_types = [self._lib.EVP_PKEY_DH]
+ if self._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ self._dh_types.append(self._lib.EVP_PKEY_DHX)
- 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 openssl_assert(self, ok):
+ return binding._openssl_assert(self._lib, ok)
- def activate_osrandom_engine(self):
- # Unregister and free the current engine.
- self.activate_builtin_random()
+ def activate_builtin_random(self):
+ if self._lib.Cryptography_HAS_ENGINE:
+ # 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 built-in.
+ res = self._lib.RAND_set_rand_method(self._ffi.NULL)
+ self.openssl_assert(res == 1)
+ # decrement the structural reference from get_default_RAND
+ res = self._lib.ENGINE_finish(e)
+ self.openssl_assert(res == 1)
+
+ @contextlib.contextmanager
+ def _get_osurandom_engine(self):
# Fetches an engine by id and returns it. This creates a structural
# reference.
- e = self._lib.ENGINE_by_id(self._binding._osrandom_engine_id)
- assert e != self._ffi.NULL
+ e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id)
+ self.openssl_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()
+ self.openssl_assert(res == 1)
+
+ try:
+ yield e
+ finally:
+ # Decrement the structural ref incremented by ENGINE_by_id.
+ res = self._lib.ENGINE_free(e)
+ self.openssl_assert(res == 1)
+ # Decrement the functional ref incremented by ENGINE_init.
+ res = self._lib.ENGINE_finish(e)
+ self.openssl_assert(res == 1)
+
+ def activate_osrandom_engine(self):
+ if self._lib.Cryptography_HAS_ENGINE:
+ # Unregister and free the current engine.
+ self.activate_builtin_random()
+ with self._get_osurandom_engine() as e:
+ # Set the engine as the default RAND provider.
+ res = self._lib.ENGINE_set_default_RAND(e)
+ self.openssl_assert(res == 1)
+ # Reset the RNG to use the engine
+ res = self._lib.RAND_set_rand_method(self._ffi.NULL)
+ self.openssl_assert(res == 1)
+
+ def osrandom_engine_implementation(self):
+ buf = self._ffi.new("char[]", 64)
+ with self._get_osurandom_engine() as e:
+ res = self._lib.ENGINE_ctrl_cmd(e, b"get_implementation",
+ len(buf), buf,
+ self._ffi.NULL, 0)
+ self.openssl_assert(res > 0)
+ return self._ffi.string(buf).decode('ascii')
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
+ Example: OpenSSL 1.1.1d 10 Sep 2019
"""
return self._ffi.string(
- self._lib.SSLeay_version(self._lib.SSLEAY_VERSION)
+ self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION)
).decode("ascii")
+ def openssl_version_number(self):
+ return self._lib.OpenSSL_version_num()
+
def create_hmac_ctx(self, key, algorithm):
return _HMACContext(self, key, algorithm)
+ def _evp_md_from_algorithm(self, algorithm):
+ if algorithm.name == "blake2b" or algorithm.name == "blake2s":
+ alg = "{}{}".format(
+ algorithm.name, algorithm.digest_size * 8
+ ).encode("ascii")
+ else:
+ alg = algorithm.name.encode("ascii")
+
+ evp_md = self._lib.EVP_get_digestbyname(alg)
+ return evp_md
+
+ def _evp_md_non_null_from_algorithm(self, algorithm):
+ evp_md = self._evp_md_from_algorithm(algorithm)
+ self.openssl_assert(evp_md != self._ffi.NULL)
+ return evp_md
+
def hash_supported(self, algorithm):
- digest = self._lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
- return digest != self._ffi.NULL
+ evp_md = self._evp_md_from_algorithm(algorithm)
+ return evp_md != self._ffi.NULL
def hmac_supported(self, algorithm):
return self.hash_supported(algorithm)
@@ -239,14 +233,6 @@ class Backend(object):
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:
@@ -256,13 +242,13 @@ class Backend(object):
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(
+ raise ValueError("Duplicate registration for: {} {}.".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]:
+ for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]:
self.register_cipher_adapter(
AES,
mode_cls,
@@ -311,124 +297,65 @@ class Backend(object):
type(None),
GetCipherByName("rc4")
)
+ # We don't actually support RC2, this is just used by some tests.
self.register_cipher_adapter(
- AES,
- GCM,
- GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ _RC2, type(None), GetCipherByName("rc2")
)
+ self.register_cipher_adapter(
+ ChaCha20,
+ type(None),
+ GetCipherByName("chacha20")
+ )
+ self.register_cipher_adapter(AES, XTS, _get_xts_cipher)
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)
+ 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)
+ 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)
+ return self.hmac_supported(algorithm)
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
-
+ buf = self._ffi.new("unsigned char[]", length)
+ evp_md = self._evp_md_non_null_from_algorithm(algorithm)
+ key_material_ptr = self._ffi.from_buffer(key_material)
+ res = self._lib.PKCS5_PBKDF2_HMAC(
+ key_material_ptr,
+ len(key_material),
+ salt,
+ len(salt),
+ iterations,
+ evp_md,
+ length,
+ buf
+ )
+ self.openssl_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)
- )
- )
+ return binding._consume_errors(self._lib)
def _bn_to_int(self, bn):
assert bn != self._ffi.NULL
- if six.PY3:
- # Python 3 has constant time from_bytes, so use that.
- bn_num_bytes = (self._lib.BN_num_bits(bn) + 7) // 8
+ if not six.PY2:
+ # Python 3 has constant time from_bytes, so use that.
+ bn_num_bytes = self._lib.BN_num_bytes(bn)
bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes)
bin_len = self._lib.BN_bn2bin(bn, bin_ptr)
# A zero length means the BN has value 0
- assert bin_len >= 0
- assert bin_ptr != self._ffi.NULL
- return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
-
+ self.openssl_assert(bin_len >= 0)
+ val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+ if self._lib.BN_is_negative(bn):
+ val = -val
+ return val
else:
# Under Python 2 the best we can do is hex()
-
hex_cdata = self._lib.BN_bn2hex(bn)
- assert hex_cdata != self._ffi.NULL
+ self.openssl_assert(hex_cdata != self._ffi.NULL)
hex_str = self._ffi.string(hex_cdata)
self._lib.OPENSSL_free(hex_cdata)
return int(hex_str, 16)
@@ -445,30 +372,30 @@ class Backend(object):
if bn is None:
bn = self._ffi.NULL
- if six.PY3:
+ if not six.PY2:
# 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
+ self.openssl_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"
+ # Under Python 2 the best we can do is hex(), [2:] removes the 0x
+ # prefix.
+ hex_num = hex(num).rstrip("L")[2:].encode("ascii")
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
+ self.openssl_assert(res != 0)
+ self.openssl_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
+ self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
bn = self._int_to_bn(public_exponent)
@@ -477,7 +404,7 @@ class Backend(object):
res = self._lib.RSA_generate_key_ex(
rsa_cdata, key_size, bn, self._ffi.NULL
)
- assert res == 1
+ self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
@@ -498,18 +425,24 @@ class Backend(object):
numbers.public_numbers.n
)
rsa_cdata = self._lib.RSA_new()
- assert rsa_cdata != self._ffi.NULL
+ self.openssl_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)
+ p = self._int_to_bn(numbers.p)
+ q = self._int_to_bn(numbers.q)
+ d = self._int_to_bn(numbers.d)
+ dmp1 = self._int_to_bn(numbers.dmp1)
+ dmq1 = self._int_to_bn(numbers.dmq1)
+ iqmp = self._int_to_bn(numbers.iqmp)
+ e = self._int_to_bn(numbers.public_numbers.e)
+ n = self._int_to_bn(numbers.public_numbers.n)
+ res = self._lib.RSA_set0_factors(rsa_cdata, p, q)
+ self.openssl_assert(res == 1)
+ res = self._lib.RSA_set0_key(rsa_cdata, n, e, d)
+ self.openssl_assert(res == 1)
+ res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp)
+ self.openssl_assert(res == 1)
res = self._lib.RSA_blinding_on(rsa_cdata, self._ffi.NULL)
- assert res == 1
+ self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
@@ -517,22 +450,26 @@ class Backend(object):
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
+ self.openssl_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
+ e = self._int_to_bn(numbers.e)
+ n = self._int_to_bn(numbers.n)
+ res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL)
+ self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
- def _rsa_cdata_to_evp_pkey(self, rsa_cdata):
+ def _create_evp_pkey_gc(self):
evp_pkey = self._lib.EVP_PKEY_new()
- assert evp_pkey != self._ffi.NULL
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ return evp_pkey
+
+ def _rsa_cdata_to_evp_pkey(self, rsa_cdata):
+ evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata)
- assert res == 1
+ self.openssl_assert(res == 1)
return evp_pkey
def _bytes_to_bio(self, data):
@@ -542,22 +479,22 @@ class Backend(object):
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)
+ data_ptr = self._ffi.from_buffer(data)
bio = self._lib.BIO_new_mem_buf(
- data_char_p, len(data)
+ data_ptr, len(data)
)
- assert bio != self._ffi.NULL
+ self.openssl_assert(bio != self._ffi.NULL)
- return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_char_p)
+ return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr)
- def _create_mem_bio(self):
+ def _create_mem_bio_gc(self):
"""
Creates an empty memory BIO.
"""
bio_method = self._lib.BIO_s_mem()
- assert bio_method != self._ffi.NULL
+ self.openssl_assert(bio_method != self._ffi.NULL)
bio = self._lib.BIO_new(bio_method)
- assert bio != self._ffi.NULL
+ self.openssl_assert(bio != self._ffi.NULL)
bio = self._ffi.gc(bio, self._lib.BIO_free)
return bio
@@ -567,8 +504,8 @@ class Backend(object):
"""
buf = self._ffi.new("char **")
buf_len = self._lib.BIO_get_mem_data(bio, buf)
- assert buf_len > 0
- assert buf[0] != self._ffi.NULL
+ self.openssl_assert(buf_len > 0)
+ self.openssl_assert(buf[0] != self._ffi.NULL)
bio_data = self._ffi.buffer(buf[0], buf_len)[:]
return bio_data
@@ -578,24 +515,40 @@ class Backend(object):
pointer.
"""
- key_type = evp_pkey.type
+ key_type = self._lib.EVP_PKEY_id(evp_pkey)
if key_type == self._lib.EVP_PKEY_RSA:
rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
- assert rsa_cdata != self._ffi.NULL
+ self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_DSA:
dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
- assert dsa_cdata != self._ffi.NULL
+ self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
return _DSAPrivateKey(self, dsa_cdata, evp_pkey)
- elif (self._lib.Cryptography_HAS_EC == 1 and
- key_type == self._lib.EVP_PKEY_EC):
+ elif key_type == self._lib.EVP_PKEY_EC:
ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
- assert ec_cdata != self._ffi.NULL
+ self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
+ elif key_type in self._dh_types:
+ dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+ return _DHPrivateKey(self, dh_cdata, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
+ # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1
+ return _Ed25519PrivateKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
+ # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1
+ return _X448PrivateKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None):
+ # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0
+ return _X25519PrivateKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
+ # EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1
+ return _Ed448PrivateKey(self, evp_pkey)
else:
raise UnsupportedAlgorithm("Unsupported key type.")
@@ -605,71 +558,54 @@ class Backend(object):
pointer.
"""
- key_type = evp_pkey.type
+ key_type = self._lib.EVP_PKEY_id(evp_pkey)
if key_type == self._lib.EVP_PKEY_RSA:
rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey)
- assert rsa_cdata != self._ffi.NULL
+ self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
elif key_type == self._lib.EVP_PKEY_DSA:
dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey)
- assert dsa_cdata != self._ffi.NULL
+ self.openssl_assert(dsa_cdata != self._ffi.NULL)
dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free)
return _DSAPublicKey(self, dsa_cdata, evp_pkey)
- elif (self._lib.Cryptography_HAS_EC == 1 and
- key_type == self._lib.EVP_PKEY_EC):
+ elif key_type == self._lib.EVP_PKEY_EC:
ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey)
- assert ec_cdata != self._ffi.NULL
+ self.openssl_assert(ec_cdata != self._ffi.NULL)
ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
+ elif key_type in self._dh_types:
+ dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey)
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+ return _DHPublicKey(self, dh_cdata, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
+ # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1
+ return _Ed25519PublicKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
+ # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1
+ return _X448PublicKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None):
+ # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0
+ return _X25519PublicKey(self, evp_pkey)
+ elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None):
+ # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1
+ return _Ed448PublicKey(self, evp_pkey)
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)
+ def _oaep_hash_supported(self, algorithm):
+ if self._lib.Cryptography_HAS_RSA_OAEP_MD:
+ return isinstance(
+ algorithm, (
+ hashes.SHA1,
+ hashes.SHA224,
+ hashes.SHA256,
+ hashes.SHA384,
+ hashes.SHA512,
)
- 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)
@@ -677,25 +613,25 @@ class Backend(object):
if isinstance(padding, PKCS1v15):
return True
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
- return self._mgf1_hash_supported(padding._mgf._algorithm)
+ return self.hash_supported(padding._mgf._algorithm)
elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
- return isinstance(padding._mgf._algorithm, hashes.SHA1)
+ return (
+ self._oaep_hash_supported(padding._mgf._algorithm) and
+ self._oaep_hash_supported(padding._algorithm) and
+ (
+ (padding._label is None or len(padding._label) == 0) or
+ self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1
+ )
+ )
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.")
+ raise ValueError("Key size must be 1024 or 2048 or 3072 bits.")
ctx = self._lib.DSA_new()
- assert ctx != self._ffi.NULL
+ self.openssl_assert(ctx != self._ffi.NULL)
ctx = self._ffi.gc(ctx, self._lib.DSA_free)
res = self._lib.DSA_generate_parameters_ex(
@@ -703,18 +639,14 @@ class Backend(object):
self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
- assert res == 1
+ self.openssl_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._lib.DSAparams_dup(parameters._dsa_cdata)
+ self.openssl_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)
evp_pkey = self._dsa_cdata_to_evp_pkey(ctx)
@@ -724,19 +656,26 @@ class Backend(object):
parameters = self.generate_dsa_parameters(key_size)
return self.generate_dsa_private_key(parameters)
+ def _dsa_cdata_set_values(self, dsa_cdata, p, q, g, pub_key, priv_key):
+ res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g)
+ self.openssl_assert(res == 1)
+ res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key)
+ self.openssl_assert(res == 1)
+
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
+ self.openssl_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)
+ p = self._int_to_bn(parameter_numbers.p)
+ q = self._int_to_bn(parameter_numbers.q)
+ g = self._int_to_bn(parameter_numbers.g)
+ pub_key = self._int_to_bn(numbers.public_numbers.y)
+ priv_key = self._int_to_bn(numbers.x)
+ self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key)
evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata)
@@ -745,13 +684,15 @@ class Backend(object):
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
+ self.openssl_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)
+ p = self._int_to_bn(numbers.parameter_numbers.p)
+ q = self._int_to_bn(numbers.parameter_numbers.q)
+ g = self._int_to_bn(numbers.parameter_numbers.g)
+ pub_key = self._int_to_bn(numbers.y)
+ priv_key = self._ffi.NULL
+ self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key)
evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata)
@@ -760,119 +701,370 @@ class Backend(object):
def load_dsa_parameter_numbers(self, numbers):
dsa._check_dsa_parameters(numbers)
dsa_cdata = self._lib.DSA_new()
- assert dsa_cdata != self._ffi.NULL
+ self.openssl_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)
+ p = self._int_to_bn(numbers.p)
+ q = self._int_to_bn(numbers.q)
+ g = self._int_to_bn(numbers.g)
+ res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g)
+ self.openssl_assert(res == 1)
return _DSAParameters(self, dsa_cdata)
def _dsa_cdata_to_evp_pkey(self, dsa_cdata):
- evp_pkey = self._lib.EVP_PKEY_new()
- assert evp_pkey != self._ffi.NULL
- evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata)
- assert res == 1
+ self.openssl_assert(res == 1)
return evp_pkey
def dsa_hash_supported(self, algorithm):
- if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f:
- return isinstance(algorithm, hashes.SHA1)
- else:
- return self.hash_supported(algorithm)
+ 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
+ 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)
- )
+ return self.cipher_supported(
+ algorithm, CBC(b"\x00" * algorithm.block_size)
)
def create_cmac_ctx(self, algorithm):
return _CMACContext(self, algorithm)
- def create_x509_csr(self, builder, private_key, algorithm):
- if not isinstance(algorithm, hashes.HashAlgorithm):
- raise TypeError('Algorithm must be a registered hash algorithm.')
-
- if self._lib.OPENSSL_VERSION_NUMBER <= 0x10001000:
- if isinstance(private_key, _DSAPrivateKey):
- raise NotImplementedError(
- "Certificate signing requests aren't implemented for DSA"
- " keys on OpenSSL versions less than 1.0.1."
- )
- if isinstance(private_key, _EllipticCurvePrivateKey):
- raise NotImplementedError(
- "Certificate signing requests aren't implemented for EC"
- " keys on OpenSSL versions less than 1.0.1."
+ def _x509_check_signature_params(self, private_key, algorithm):
+ if isinstance(private_key,
+ (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
+ if algorithm is not None:
+ raise ValueError(
+ "algorithm must be None when signing via ed25519 or ed448"
)
+ elif not isinstance(private_key, (rsa.RSAPrivateKey, dsa.DSAPrivateKey,
+ ec.EllipticCurvePrivateKey)):
+ raise TypeError(
+ "Key must be rsa, dsa, ec, ed25519 or ed448 private key."
+ )
+ elif not isinstance(algorithm, hashes.HashAlgorithm):
+ raise TypeError("Algorithm must be a registered hash algorithm.")
+ elif (
+ isinstance(algorithm, hashes.MD5) and not
+ isinstance(private_key, rsa.RSAPrivateKey)
+ ):
+ raise ValueError(
+ "MD5 hash algorithm is only supported with RSA keys"
+ )
+
+ def create_x509_csr(self, builder, private_key, algorithm):
+ if not isinstance(builder, x509.CertificateSigningRequestBuilder):
+ raise TypeError('Builder type mismatch.')
+ self._x509_check_signature_params(private_key, algorithm)
# Resolve the signature algorithm.
- evp_md = self._lib.EVP_get_digestbyname(
- algorithm.name.encode('ascii')
- )
- assert evp_md != self._ffi.NULL
+ evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
# Create an empty request.
x509_req = self._lib.X509_REQ_new()
- assert x509_req != self._ffi.NULL
+ self.openssl_assert(x509_req != self._ffi.NULL)
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
# Set x509 version.
res = self._lib.X509_REQ_set_version(x509_req, x509.Version.v1.value)
- assert res == 1
+ self.openssl_assert(res == 1)
# Set subject name.
res = self._lib.X509_REQ_set_subject_name(
- x509_req, _encode_name(self, list(builder._subject_name))
+ x509_req, _encode_name_gc(self, builder._subject_name)
)
- assert res == 1
+ self.openssl_assert(res == 1)
# Set subject public key.
public_key = private_key.public_key()
res = self._lib.X509_REQ_set_pubkey(
x509_req, public_key._evp_pkey
)
- assert res == 1
+ self.openssl_assert(res == 1)
# Add extensions.
- extensions = self._lib.sk_X509_EXTENSION_new_null()
- assert extensions != self._ffi.NULL
- extensions = self._ffi.gc(
- extensions,
- self._lib.sk_X509_EXTENSION_free,
- )
- for extension in builder._extensions:
- if isinstance(extension.value, x509.BasicConstraints):
- extension = _encode_basic_constraints(
- self,
- extension.value,
- extension.critical
+ sk_extension = self._lib.sk_X509_EXTENSION_new_null()
+ self.openssl_assert(sk_extension != self._ffi.NULL)
+ sk_extension = self._ffi.gc(
+ sk_extension,
+ lambda x: self._lib.sk_X509_EXTENSION_pop_free(
+ x, self._ffi.addressof(
+ self._lib._original_lib, "X509_EXTENSION_free"
)
- else:
- raise NotImplementedError('Extension not yet supported.')
- res = self._lib.sk_X509_EXTENSION_push(extensions, extension)
- assert res == 1
- res = self._lib.X509_REQ_add_extensions(x509_req, extensions)
- assert res == 1
+ )
+ )
+ # Don't GC individual extensions because the memory is owned by
+ # sk_extensions and will be freed along with it.
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=sk_extension,
+ add_func=self._lib.sk_X509_EXTENSION_insert,
+ gc=False
+ )
+ res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension)
+ self.openssl_assert(res == 1)
# Sign the request using the requester's private key.
res = self._lib.X509_REQ_sign(
x509_req, private_key._evp_pkey, evp_md
)
- assert res > 0
+ if res == 0:
+ errors = self._consume_errors()
+ self.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
+ )
+
+ raise ValueError("Digest too big for RSA key")
return _CertificateSigningRequest(self, x509_req)
+ def create_x509_certificate(self, builder, private_key, algorithm):
+ if not isinstance(builder, x509.CertificateBuilder):
+ raise TypeError('Builder type mismatch.')
+ self._x509_check_signature_params(private_key, algorithm)
+
+ # Resolve the signature algorithm.
+ evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
+
+ # Create an empty certificate.
+ x509_cert = self._lib.X509_new()
+ x509_cert = self._ffi.gc(x509_cert, self._lib.X509_free)
+
+ # Set the x509 version.
+ res = self._lib.X509_set_version(x509_cert, builder._version.value)
+ self.openssl_assert(res == 1)
+
+ # Set the subject's name.
+ res = self._lib.X509_set_subject_name(
+ x509_cert, _encode_name_gc(self, builder._subject_name)
+ )
+ self.openssl_assert(res == 1)
+
+ # Set the subject's public key.
+ res = self._lib.X509_set_pubkey(
+ x509_cert, builder._public_key._evp_pkey
+ )
+ self.openssl_assert(res == 1)
+
+ # Set the certificate serial number.
+ serial_number = _encode_asn1_int_gc(self, builder._serial_number)
+ res = self._lib.X509_set_serialNumber(x509_cert, serial_number)
+ self.openssl_assert(res == 1)
+
+ # Set the "not before" time.
+ self._set_asn1_time(
+ self._lib.X509_getm_notBefore(x509_cert), builder._not_valid_before
+ )
+
+ # Set the "not after" time.
+ self._set_asn1_time(
+ self._lib.X509_getm_notAfter(x509_cert), builder._not_valid_after
+ )
+
+ # Add extensions.
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=x509_cert,
+ add_func=self._lib.X509_add_ext,
+ gc=True
+ )
+
+ # Set the issuer name.
+ res = self._lib.X509_set_issuer_name(
+ x509_cert, _encode_name_gc(self, builder._issuer_name)
+ )
+ self.openssl_assert(res == 1)
+
+ # Sign the certificate with the issuer's private key.
+ res = self._lib.X509_sign(
+ x509_cert, private_key._evp_pkey, evp_md
+ )
+ if res == 0:
+ errors = self._consume_errors()
+ self.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
+ )
+ raise ValueError("Digest too big for RSA key")
+
+ return _Certificate(self, x509_cert)
+
+ def _evp_md_x509_null_if_eddsa(self, private_key, algorithm):
+ if isinstance(private_key,
+ (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey)):
+ # OpenSSL requires us to pass NULL for EVP_MD for ed25519/ed448
+ return self._ffi.NULL
+ else:
+ return self._evp_md_non_null_from_algorithm(algorithm)
+
+ def _set_asn1_time(self, asn1_time, time):
+ if time.year >= 2050:
+ asn1_str = time.strftime('%Y%m%d%H%M%SZ').encode('ascii')
+ else:
+ asn1_str = time.strftime('%y%m%d%H%M%SZ').encode('ascii')
+ res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str)
+ self.openssl_assert(res == 1)
+
+ def _create_asn1_time(self, time):
+ asn1_time = self._lib.ASN1_TIME_new()
+ self.openssl_assert(asn1_time != self._ffi.NULL)
+ asn1_time = self._ffi.gc(asn1_time, self._lib.ASN1_TIME_free)
+ self._set_asn1_time(asn1_time, time)
+ return asn1_time
+
+ def create_x509_crl(self, builder, private_key, algorithm):
+ if not isinstance(builder, x509.CertificateRevocationListBuilder):
+ raise TypeError('Builder type mismatch.')
+ self._x509_check_signature_params(private_key, algorithm)
+
+ evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
+
+ # Create an empty CRL.
+ x509_crl = self._lib.X509_CRL_new()
+ x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
+
+ # Set the x509 CRL version. We only support v2 (integer value 1).
+ res = self._lib.X509_CRL_set_version(x509_crl, 1)
+ self.openssl_assert(res == 1)
+
+ # Set the issuer name.
+ res = self._lib.X509_CRL_set_issuer_name(
+ x509_crl, _encode_name_gc(self, builder._issuer_name)
+ )
+ self.openssl_assert(res == 1)
+
+ # Set the last update time.
+ last_update = self._create_asn1_time(builder._last_update)
+ res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update)
+ self.openssl_assert(res == 1)
+
+ # Set the next update time.
+ next_update = self._create_asn1_time(builder._next_update)
+ res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update)
+ self.openssl_assert(res == 1)
+
+ # Add extensions.
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_CRL_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=x509_crl,
+ add_func=self._lib.X509_CRL_add_ext,
+ gc=True
+ )
+
+ # add revoked certificates
+ for revoked_cert in builder._revoked_certificates:
+ # Duplicating because the X509_CRL takes ownership and will free
+ # this memory when X509_CRL_free is called.
+ revoked = self._lib.X509_REVOKED_dup(revoked_cert._x509_revoked)
+ self.openssl_assert(revoked != self._ffi.NULL)
+ res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked)
+ self.openssl_assert(res == 1)
+
+ res = self._lib.X509_CRL_sign(
+ x509_crl, private_key._evp_pkey, evp_md
+ )
+ if res == 0:
+ errors = self._consume_errors()
+ self.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_RSA,
+ self._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
+ )
+ )
+ raise ValueError("Digest too big for RSA key")
+
+ return _CertificateRevocationList(self, x509_crl)
+
+ def _create_x509_extensions(self, extensions, handlers, x509_obj,
+ add_func, gc):
+ for i, extension in enumerate(extensions):
+ x509_extension = self._create_x509_extension(
+ handlers, extension
+ )
+ self.openssl_assert(x509_extension != self._ffi.NULL)
+
+ if gc:
+ x509_extension = self._ffi.gc(
+ x509_extension, self._lib.X509_EXTENSION_free
+ )
+ res = add_func(x509_obj, x509_extension, i)
+ self.openssl_assert(res >= 1)
+
+ def _create_raw_x509_extension(self, extension, value):
+ obj = _txt2obj_gc(self, extension.oid.dotted_string)
+ return self._lib.X509_EXTENSION_create_by_OBJ(
+ self._ffi.NULL, obj, 1 if extension.critical else 0, value
+ )
+
+ def _create_x509_extension(self, handlers, extension):
+ if isinstance(extension.value, x509.UnrecognizedExtension):
+ value = _encode_asn1_str_gc(self, extension.value.value)
+ return self._create_raw_x509_extension(extension, value)
+ elif isinstance(extension.value, x509.TLSFeature):
+ asn1 = encode_der(
+ SEQUENCE,
+ *[
+ encode_der(INTEGER, encode_der_integer(x.value))
+ for x in extension.value
+ ]
+ )
+ value = _encode_asn1_str_gc(self, asn1)
+ return self._create_raw_x509_extension(extension, value)
+ elif isinstance(extension.value, x509.PrecertPoison):
+ value = _encode_asn1_str_gc(self, encode_der(NULL))
+ return self._create_raw_x509_extension(extension, value)
+ else:
+ try:
+ encode = handlers[extension.oid]
+ except KeyError:
+ raise NotImplementedError(
+ 'Extension not supported: {}'.format(extension.oid)
+ )
+
+ ext_struct = encode(self, extension.value)
+ nid = self._lib.OBJ_txt2nid(
+ extension.oid.dotted_string.encode("ascii")
+ )
+ self.openssl_assert(nid != self._lib.NID_undef)
+ return self._lib.X509V3_EXT_i2d(
+ nid, 1 if extension.critical else 0, ext_struct
+ )
+
+ def create_x509_revoked_certificate(self, builder):
+ if not isinstance(builder, x509.RevokedCertificateBuilder):
+ raise TypeError('Builder type mismatch.')
+
+ x509_revoked = self._lib.X509_REVOKED_new()
+ self.openssl_assert(x509_revoked != self._ffi.NULL)
+ x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free)
+ serial_number = _encode_asn1_int_gc(self, builder._serial_number)
+ res = self._lib.X509_REVOKED_set_serialNumber(
+ x509_revoked, serial_number
+ )
+ self.openssl_assert(res == 1)
+ rev_date = self._create_asn1_time(builder._revocation_date)
+ res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date)
+ self.openssl_assert(res == 1)
+ # add CRL entry extensions
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=x509_revoked,
+ add_func=self._lib.X509_REVOKED_add_ext,
+ gc=True
+ )
+ return _RevokedCertificate(self, None, x509_revoked)
+
def load_pem_private_key(self, data, password):
return self._load_key(
self._lib.PEM_read_bio_PrivateKey,
@@ -895,7 +1087,7 @@ class Backend(object):
# embedded in a subjectPublicKeyInfo)
self._consume_errors()
res = self._lib.BIO_reset(mem_bio.bio)
- assert res == 1
+ self.openssl_assert(res == 1)
rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey(
mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
)
@@ -906,22 +1098,24 @@ class Backend(object):
else:
self._handle_key_loading_error()
+ def load_pem_parameters(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ # only DH is supported currently
+ dh_cdata = self._lib.PEM_read_bio_DHparams(
+ mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL)
+ if dh_cdata != self._ffi.NULL:
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+ return _DHParameters(self, dh_cdata)
+ else:
+ self._handle_key_loading_error()
+
def load_der_private_key(self, data, password):
- # OpenSSL has a function called d2i_AutoPrivateKey that can simplify
- # this. Unfortunately it doesn't properly support PKCS8 on OpenSSL
- # 0.9.8 so we can't use it. Instead we sequentially try to load it 3
- # different ways. First we'll try to load it as a traditional key
+ # OpenSSL has a function called d2i_AutoPrivateKey that in theory
+ # handles this automatically, however it doesn't handle encrypted
+ # private keys. Instead we try to load the key two different ways.
+ # First we'll try to load it as a traditional key.
bio_data = self._bytes_to_bio(data)
key = self._evp_pkey_from_der_traditional_key(bio_data, password)
- if not key:
- # Okay so it's not a traditional key. Let's try
- # PKCS8 unencrypted. OpenSSL 0.9.8 can't load unencrypted
- # PKCS8 keys using d2i_PKCS8PrivateKey_bio so we do this instead.
- # Reset the memory BIO so we can read the data again.
- res = self._lib.BIO_reset(bio_data.bio)
- assert res == 1
- key = self._evp_pkey_from_der_unencrypted_pkcs8(bio_data, password)
-
if key:
return self._evp_pkey_to_private_key(key)
else:
@@ -948,24 +1142,6 @@ class Backend(object):
self._consume_errors()
return None
- def _evp_pkey_from_der_unencrypted_pkcs8(self, bio_data, password):
- info = self._lib.d2i_PKCS8_PRIV_KEY_INFO_bio(
- bio_data.bio, self._ffi.NULL
- )
- info = self._ffi.gc(info, self._lib.PKCS8_PRIV_KEY_INFO_free)
- if info != self._ffi.NULL:
- key = self._lib.EVP_PKCS82PKEY(info)
- assert key != self._ffi.NULL
- key = self._ffi.gc(key, self._lib.EVP_PKEY_free)
- if password is not None:
- raise TypeError(
- "Password was given but private key is not encrypted."
- )
- return key
- else:
- self._consume_errors()
- return None
-
def load_der_public_key(self, data):
mem_bio = self._bytes_to_bio(data)
evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL)
@@ -978,7 +1154,7 @@ class Backend(object):
# embedded in a subjectPublicKeyInfo)
self._consume_errors()
res = self._lib.BIO_reset(mem_bio.bio)
- assert res == 1
+ self.openssl_assert(res == 1)
rsa_cdata = self._lib.d2i_RSAPublicKey_bio(
mem_bio.bio, self._ffi.NULL
)
@@ -989,6 +1165,28 @@ class Backend(object):
else:
self._handle_key_loading_error()
+ def load_der_parameters(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ dh_cdata = self._lib.d2i_DHparams_bio(
+ mem_bio.bio, self._ffi.NULL
+ )
+ if dh_cdata != self._ffi.NULL:
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+ return _DHParameters(self, dh_cdata)
+ elif self._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ # We check to see if the is dhx.
+ self._consume_errors()
+ res = self._lib.BIO_reset(mem_bio.bio)
+ self.openssl_assert(res == 1)
+ dh_cdata = self._lib.Cryptography_d2i_DHxparams_bio(
+ mem_bio.bio, self._ffi.NULL
+ )
+ if dh_cdata != self._ffi.NULL:
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+ return _DHParameters(self, dh_cdata)
+
+ self._handle_key_loading_error()
+
def load_pem_x509_certificate(self, data):
mem_bio = self._bytes_to_bio(data)
x509 = self._lib.PEM_read_bio_X509(
@@ -996,7 +1194,10 @@ class Backend(object):
)
if x509 == self._ffi.NULL:
self._consume_errors()
- raise ValueError("Unable to load certificate")
+ raise ValueError(
+ "Unable to load certificate. See https://cryptography.io/en/la"
+ "test/faq/#why-can-t-i-import-my-pem-file for more details."
+ )
x509 = self._ffi.gc(x509, self._lib.X509_free)
return _Certificate(self, x509)
@@ -1011,6 +1212,31 @@ class Backend(object):
x509 = self._ffi.gc(x509, self._lib.X509_free)
return _Certificate(self, x509)
+ def load_pem_x509_crl(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ x509_crl = self._lib.PEM_read_bio_X509_CRL(
+ mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+ )
+ if x509_crl == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError(
+ "Unable to load CRL. See https://cryptography.io/en/la"
+ "test/faq/#why-can-t-i-import-my-pem-file for more details."
+ )
+
+ x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
+ return _CertificateRevocationList(self, x509_crl)
+
+ def load_der_x509_crl(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL)
+ if x509_crl == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Unable to load CRL")
+
+ x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free)
+ return _CertificateRevocationList(self, x509_crl)
+
def load_pem_x509_csr(self, data):
mem_bio = self._bytes_to_bio(data)
x509_req = self._lib.PEM_read_bio_X509_REQ(
@@ -1018,7 +1244,10 @@ class Backend(object):
)
if x509_req == self._ffi.NULL:
self._consume_errors()
- raise ValueError("Unable to load request")
+ raise ValueError(
+ "Unable to load request. See https://cryptography.io/en/la"
+ "test/faq/#why-can-t-i-import-my-pem-file for more details."
+ )
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
return _CertificateSigningRequest(self, x509_req)
@@ -1036,31 +1265,47 @@ class Backend(object):
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)
+ userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *")
+ if password is not None:
+ utils._check_byteslike("password", password)
+ password_ptr = self._ffi.from_buffer(password)
+ userdata.password = password_ptr
+ userdata.length = len(password)
evp_pkey = openssl_read_func(
mem_bio.bio,
self._ffi.NULL,
- password_callback,
- self._ffi.NULL
+ self._ffi.addressof(
+ self._lib._original_lib, "Cryptography_pem_password_cb"
+ ),
+ userdata,
)
if evp_pkey == self._ffi.NULL:
- if password_func.exception is not None:
+ if userdata.error != 0:
errors = self._consume_errors()
- assert errors
- raise password_func.exception
+ self.openssl_assert(errors)
+ if userdata.error == -1:
+ raise TypeError(
+ "Password was not given but private key is encrypted"
+ )
+ else:
+ assert userdata.error == -2
+ raise ValueError(
+ "Passwords longer than {} bytes are not supported "
+ "by this backend.".format(userdata.maxsize - 1)
+ )
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:
+ if password is not None and userdata.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 not None and userdata.called == 1) or
password is None
)
@@ -1070,33 +1315,23 @@ class Backend(object):
errors = self._consume_errors()
if not errors:
- raise ValueError("Could not unserialize key data.")
+ raise ValueError("Could not deserialize 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
- ),
- (
+ elif (
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT
+ ) or errors[0]._lib_reason_match(
self._lib.ERR_LIB_PKCS12,
- self._lib.PKCS12_F_PKCS12_PBE_CRYPT,
- self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR,
+ 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
+ elif (
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM
+ ) or errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION
)
):
raise UnsupportedAlgorithm(
@@ -1105,70 +1340,52 @@ class Backend(object):
)
elif any(
- error[1:] == (
+ error._lib_reason_match(
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
- )
+ raise ValueError("Unsupported public key algorithm.")
else:
- assert errors[0][1] in (
+ assert errors[0].lib in (
self._lib.ERR_LIB_EVP,
self._lib.ERR_LIB_PEM,
self._lib.ERR_LIB_ASN1,
)
- raise ValueError("Could not unserialize key data.")
+ raise ValueError("Could not deserialize 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)
+ group = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
- if ctx == self._ffi.NULL:
+ if group == self._ffi.NULL:
errors = self._consume_errors()
- assert (
+ self.openssl_assert(
curve_nid == self._lib.NID_undef or
- errors[0][1:] == (
+ errors[0]._lib_reason_match(
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)
+ self.openssl_assert(curve_nid != self._lib.NID_undef)
+ self._lib.EC_GROUP_free(group)
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):
@@ -1177,65 +1394,255 @@ class Backend(object):
"""
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)
+ ec_cdata = self._ec_key_new_by_curve(curve)
res = self._lib.EC_KEY_generate_key(ec_cdata)
- assert res == 1
-
- res = self._lib.EC_KEY_check_key(ec_cdata)
- assert res == 1
+ self.openssl_assert(res == 1)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
else:
raise UnsupportedAlgorithm(
- "Backend object does not support {0}.".format(curve.name),
+ "Backend object does not support {}.".format(curve.name),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
def load_elliptic_curve_private_numbers(self, numbers):
public = numbers.public_numbers
- curve_nid = self._elliptic_curve_to_nid(public.curve)
+ ec_cdata = self._ec_key_new_by_curve(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)
+ private_value = self._ffi.gc(
+ self._int_to_bn(numbers.private_value), self._lib.BN_clear_free
+ )
+ res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value)
+ self.openssl_assert(res == 1)
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
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
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_new_by_curve(numbers.curve)
ec_cdata = self._ec_key_set_public_key_affine_coordinates(
ec_cdata, numbers.x, numbers.y)
evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
+ def load_elliptic_curve_public_bytes(self, curve, point_bytes):
+ ec_cdata = self._ec_key_new_by_curve(curve)
+ group = self._lib.EC_KEY_get0_group(ec_cdata)
+ self.openssl_assert(group != self._ffi.NULL)
+ point = self._lib.EC_POINT_new(group)
+ self.openssl_assert(point != self._ffi.NULL)
+ point = self._ffi.gc(point, self._lib.EC_POINT_free)
+ with self._tmp_bn_ctx() as bn_ctx:
+ res = self._lib.EC_POINT_oct2point(
+ group, point, point_bytes, len(point_bytes), bn_ctx
+ )
+ if res != 1:
+ self._consume_errors()
+ raise ValueError("Invalid public bytes for the given curve")
+
+ res = self._lib.EC_KEY_set_public_key(ec_cdata, point)
+ self.openssl_assert(res == 1)
+ evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
+ return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey)
+
+ def derive_elliptic_curve_private_key(self, private_value, curve):
+ ec_cdata = self._ec_key_new_by_curve(curve)
+
+ get_func, group = self._ec_key_determine_group_get_func(ec_cdata)
+
+ point = self._lib.EC_POINT_new(group)
+ self.openssl_assert(point != self._ffi.NULL)
+ point = self._ffi.gc(point, self._lib.EC_POINT_free)
+
+ value = self._int_to_bn(private_value)
+ value = self._ffi.gc(value, self._lib.BN_clear_free)
+
+ with self._tmp_bn_ctx() as bn_ctx:
+ res = self._lib.EC_POINT_mul(group, point, value, self._ffi.NULL,
+ self._ffi.NULL, bn_ctx)
+ self.openssl_assert(res == 1)
+
+ bn_x = self._lib.BN_CTX_get(bn_ctx)
+ bn_y = self._lib.BN_CTX_get(bn_ctx)
+
+ res = get_func(group, point, bn_x, bn_y, bn_ctx)
+ self.openssl_assert(res == 1)
+
+ res = self._lib.EC_KEY_set_public_key(ec_cdata, point)
+ self.openssl_assert(res == 1)
+ private = self._int_to_bn(private_value)
+ private = self._ffi.gc(private, self._lib.BN_clear_free)
+ res = self._lib.EC_KEY_set_private_key(ec_cdata, private)
+ self.openssl_assert(res == 1)
+
+ evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata)
+
+ return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey)
+
+ def _ec_key_new_by_curve(self, curve):
+ curve_nid = self._elliptic_curve_to_nid(curve)
+ ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
+ self.openssl_assert(ec_cdata != self._ffi.NULL)
+ return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free)
+
+ def load_der_ocsp_request(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ request = self._lib.d2i_OCSP_REQUEST_bio(mem_bio.bio, self._ffi.NULL)
+ if request == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Unable to load OCSP request")
+
+ request = self._ffi.gc(request, self._lib.OCSP_REQUEST_free)
+ return _OCSPRequest(self, request)
+
+ def load_der_ocsp_response(self, data):
+ mem_bio = self._bytes_to_bio(data)
+ response = self._lib.d2i_OCSP_RESPONSE_bio(mem_bio.bio, self._ffi.NULL)
+ if response == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Unable to load OCSP response")
+
+ response = self._ffi.gc(response, self._lib.OCSP_RESPONSE_free)
+ return _OCSPResponse(self, response)
+
+ def create_ocsp_request(self, builder):
+ ocsp_req = self._lib.OCSP_REQUEST_new()
+ self.openssl_assert(ocsp_req != self._ffi.NULL)
+ ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free)
+ cert, issuer, algorithm = builder._request
+ evp_md = self._evp_md_non_null_from_algorithm(algorithm)
+ certid = self._lib.OCSP_cert_to_id(
+ evp_md, cert._x509, issuer._x509
+ )
+ self.openssl_assert(certid != self._ffi.NULL)
+ onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid)
+ self.openssl_assert(onereq != self._ffi.NULL)
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=ocsp_req,
+ add_func=self._lib.OCSP_REQUEST_add_ext,
+ gc=True,
+ )
+ return _OCSPRequest(self, ocsp_req)
+
+ def _create_ocsp_basic_response(self, builder, private_key, algorithm):
+ self._x509_check_signature_params(private_key, algorithm)
+
+ basic = self._lib.OCSP_BASICRESP_new()
+ self.openssl_assert(basic != self._ffi.NULL)
+ basic = self._ffi.gc(basic, self._lib.OCSP_BASICRESP_free)
+ evp_md = self._evp_md_non_null_from_algorithm(
+ builder._response._algorithm
+ )
+ certid = self._lib.OCSP_cert_to_id(
+ evp_md, builder._response._cert._x509,
+ builder._response._issuer._x509
+ )
+ self.openssl_assert(certid != self._ffi.NULL)
+ certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free)
+ if builder._response._revocation_reason is None:
+ reason = -1
+ else:
+ reason = _CRL_ENTRY_REASON_ENUM_TO_CODE[
+ builder._response._revocation_reason
+ ]
+ if builder._response._revocation_time is None:
+ rev_time = self._ffi.NULL
+ else:
+ rev_time = self._create_asn1_time(
+ builder._response._revocation_time
+ )
+
+ next_update = self._ffi.NULL
+ if builder._response._next_update is not None:
+ next_update = self._create_asn1_time(
+ builder._response._next_update
+ )
+
+ this_update = self._create_asn1_time(builder._response._this_update)
+
+ res = self._lib.OCSP_basic_add1_status(
+ basic,
+ certid,
+ builder._response._cert_status.value,
+ reason,
+ rev_time,
+ this_update,
+ next_update
+ )
+ self.openssl_assert(res != self._ffi.NULL)
+ # okay, now sign the basic structure
+ evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
+ responder_cert, responder_encoding = builder._responder_id
+ flags = self._lib.OCSP_NOCERTS
+ if responder_encoding is ocsp.OCSPResponderEncoding.HASH:
+ flags |= self._lib.OCSP_RESPID_KEY
+
+ if builder._certs is not None:
+ for cert in builder._certs:
+ res = self._lib.OCSP_basic_add1_cert(basic, cert._x509)
+ self.openssl_assert(res == 1)
+
+ self._create_x509_extensions(
+ extensions=builder._extensions,
+ handlers=_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS,
+ x509_obj=basic,
+ add_func=self._lib.OCSP_BASICRESP_add_ext,
+ gc=True,
+ )
+
+ res = self._lib.OCSP_basic_sign(
+ basic, responder_cert._x509, private_key._evp_pkey,
+ evp_md, self._ffi.NULL, flags
+ )
+ if res != 1:
+ errors = self._consume_errors()
+ self.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_X509,
+ self._lib.X509_R_KEY_VALUES_MISMATCH
+ )
+ )
+ raise ValueError("responder_cert must be signed by private_key")
+
+ return basic
+
+ def create_ocsp_response(self, response_status, builder, private_key,
+ algorithm):
+ if response_status is ocsp.OCSPResponseStatus.SUCCESSFUL:
+ basic = self._create_ocsp_basic_response(
+ builder, private_key, algorithm
+ )
+ else:
+ basic = self._ffi.NULL
+
+ ocsp_resp = self._lib.OCSP_response_create(
+ response_status.value, basic
+ )
+ self.openssl_assert(ocsp_resp != self._ffi.NULL)
+ ocsp_resp = self._ffi.gc(ocsp_resp, self._lib.OCSP_RESPONSE_free)
+ return _OCSPResponse(self, ocsp_resp)
+
+ def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve):
+ return (
+ self.elliptic_curve_supported(curve) and
+ isinstance(algorithm, ec.ECDH)
+ )
+
def _ec_cdata_to_evp_pkey(self, ec_cdata):
- evp_pkey = self._lib.EVP_PKEY_new()
- assert evp_pkey != self._ffi.NULL
- evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata)
- assert res == 1
+ self.openssl_assert(res == 1)
return evp_pkey
def _elliptic_curve_to_nid(self, curve):
@@ -1253,7 +1660,7 @@ class Backend(object):
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),
+ "{} is not a supported elliptic curve".format(curve.name),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
return curve_nid
@@ -1261,7 +1668,7 @@ class Backend(object):
@contextmanager
def _tmp_bn_ctx(self):
bn_ctx = self._lib.BN_CTX_new()
- assert bn_ctx != self._ffi.NULL
+ self.openssl_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:
@@ -1269,41 +1676,36 @@ class Backend(object):
finally:
self._lib.BN_CTX_end(bn_ctx)
- def _ec_key_determine_group_get_set_funcs(self, ctx):
+ def _ec_key_determine_group_get_func(self, ctx):
"""
- Given an EC_KEY determine the group and what methods are required to
- get/set point coordinates.
+ Given an EC_KEY determine the group and what function is required to
+ get point coordinates.
"""
- assert ctx != self._ffi.NULL
+ self.openssl_assert(ctx != self._ffi.NULL)
nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field")
- assert nid_two_field != self._lib.NID_undef
+ self.openssl_assert(nid_two_field != self._lib.NID_undef)
group = self._lib.EC_KEY_get0_group(ctx)
- assert group != self._ffi.NULL
+ self.openssl_assert(group != self._ffi.NULL)
method = self._lib.EC_GROUP_method_of(group)
- assert method != self._ffi.NULL
+ self.openssl_assert(method != self._ffi.NULL)
nid = self._lib.EC_METHOD_get_field_type(method)
- assert nid != self._lib.NID_undef
+ self.openssl_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
+ assert get_func
- return set_func, get_func, group
+ return 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.
"""
@@ -1313,36 +1715,9 @@ class Backend(object):
"Invalid EC key. Both x and y must be non-negative."
)
- 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)
-
- bn_x = self._int_to_bn(x)
- bn_y = self._int_to_bn(y)
-
- 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
-
- res = self._lib.BN_cmp(bn_x, check_x)
- assert res == 0
- res = self._lib.BN_cmp(bn_y, check_y)
- assert res == 0
-
- res = self._lib.EC_KEY_set_public_key(ctx, point)
- assert res == 1
-
- res = self._lib.EC_KEY_check_key(ctx)
+ x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free)
+ y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free)
+ res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y)
if res != 1:
self._consume_errors()
raise ValueError("Invalid EC key.")
@@ -1350,15 +1725,14 @@ class Backend(object):
return ctx
def _private_key_bytes(self, encoding, format, encryption_algorithm,
- evp_pkey, cdata):
+ key, evp_pkey, cdata):
+ # validate argument types
if not isinstance(encoding, serialization.Encoding):
raise TypeError("encoding must be an item from the Encoding enum")
-
if not isinstance(format, serialization.PrivateFormat):
raise TypeError(
"format must be an item from the PrivateFormat enum"
)
-
if not isinstance(encryption_algorithm,
serialization.KeySerializationEncryption):
raise TypeError(
@@ -1366,19 +1740,13 @@ class Backend(object):
"instance"
)
+ # validate password
if isinstance(encryption_algorithm, serialization.NoEncryption):
password = b""
- passlen = 0
- evp_cipher = self._ffi.NULL
elif isinstance(encryption_algorithm,
serialization.BestAvailableEncryption):
- # This is a curated value that we will update over time.
- evp_cipher = self._lib.EVP_get_cipherbyname(
- b"aes-256-cbc"
- )
password = encryption_algorithm.password
- passlen = len(password)
- if passlen > 1023:
+ if len(password) > 1023:
raise ValueError(
"Passwords longer than 1023 bytes are not supported by "
"this backend"
@@ -1386,95 +1754,693 @@ class Backend(object):
else:
raise ValueError("Unsupported encryption type")
- if encoding is serialization.Encoding.PEM:
- if format is serialization.PrivateFormat.PKCS8:
+ # PKCS8 + PEM/DER
+ if format is serialization.PrivateFormat.PKCS8:
+ if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey
- key = evp_pkey
- elif format is serialization.PrivateFormat.TraditionalOpenSSL:
- if evp_pkey.type == self._lib.EVP_PKEY_RSA:
+ elif encoding is serialization.Encoding.DER:
+ write_bio = self._lib.i2d_PKCS8PrivateKey_bio
+ else:
+ raise ValueError("Unsupported encoding for PKCS8")
+ return self._private_key_bytes_via_bio(
+ write_bio, evp_pkey, password
+ )
+
+ # TraditionalOpenSSL + PEM/DER
+ if format is serialization.PrivateFormat.TraditionalOpenSSL:
+ key_type = self._lib.EVP_PKEY_id(evp_pkey)
+
+ if encoding is serialization.Encoding.PEM:
+ if key_type == self._lib.EVP_PKEY_RSA:
write_bio = self._lib.PEM_write_bio_RSAPrivateKey
- elif evp_pkey.type == self._lib.EVP_PKEY_DSA:
+ elif key_type == self._lib.EVP_PKEY_DSA:
write_bio = self._lib.PEM_write_bio_DSAPrivateKey
- elif (self._lib.Cryptography_HAS_EC == 1 and
- evp_pkey.type == self._lib.EVP_PKEY_EC):
+ elif key_type == self._lib.EVP_PKEY_EC:
write_bio = self._lib.PEM_write_bio_ECPrivateKey
+ else:
+ raise ValueError(
+ "Unsupported key type for TraditionalOpenSSL"
+ )
+ return self._private_key_bytes_via_bio(
+ write_bio, cdata, password
+ )
- key = cdata
- elif encoding is serialization.Encoding.DER:
- if format is serialization.PrivateFormat.TraditionalOpenSSL:
- if not isinstance(
- encryption_algorithm, serialization.NoEncryption
- ):
+ if encoding is serialization.Encoding.DER:
+ if password:
raise ValueError(
"Encryption is not supported for DER encoded "
"traditional OpenSSL keys"
)
+ if key_type == self._lib.EVP_PKEY_RSA:
+ write_bio = self._lib.i2d_RSAPrivateKey_bio
+ elif key_type == self._lib.EVP_PKEY_EC:
+ write_bio = self._lib.i2d_ECPrivateKey_bio
+ elif key_type == self._lib.EVP_PKEY_DSA:
+ write_bio = self._lib.i2d_DSAPrivateKey_bio
+ else:
+ raise ValueError(
+ "Unsupported key type for TraditionalOpenSSL"
+ )
+ return self._bio_func_output(write_bio, cdata)
- return self._private_key_bytes_traditional_der(
- evp_pkey.type, cdata
- )
- elif format is serialization.PrivateFormat.PKCS8:
- write_bio = self._lib.i2d_PKCS8PrivateKey_bio
- key = evp_pkey
+ raise ValueError(
+ "Unsupported encoding for TraditionalOpenSSL"
+ )
+
+ # Anything that key-specific code was supposed to handle earlier,
+ # like Raw.
+ raise ValueError("format is invalid with this key")
+
+ def _private_key_bytes_via_bio(self, write_bio, evp_pkey, password):
+ if not password:
+ evp_cipher = self._ffi.NULL
+ else:
+ # This is a curated value that we will update over time.
+ evp_cipher = self._lib.EVP_get_cipherbyname(b"aes-256-cbc")
- bio = self._create_mem_bio()
- res = write_bio(
- bio,
- key,
+ return self._bio_func_output(
+ write_bio,
+ evp_pkey,
evp_cipher,
password,
- passlen,
+ len(password),
self._ffi.NULL,
self._ffi.NULL
)
- assert res == 1
- return self._read_mem_bio(bio)
- def _private_key_bytes_traditional_der(self, key_type, cdata):
- if key_type == self._lib.EVP_PKEY_RSA:
- write_bio = self._lib.i2d_RSAPrivateKey_bio
- elif (self._lib.Cryptography_HAS_EC == 1 and
- key_type == self._lib.EVP_PKEY_EC):
- write_bio = self._lib.i2d_ECPrivateKey_bio
- elif key_type == self._lib.EVP_PKEY_DSA:
- write_bio = self._lib.i2d_DSAPrivateKey_bio
-
- bio = self._create_mem_bio()
- res = write_bio(bio, cdata)
- assert res == 1
+ def _bio_func_output(self, write_bio, *args):
+ bio = self._create_mem_bio_gc()
+ res = write_bio(bio, *args)
+ self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
- def _public_key_bytes(self, encoding, format, evp_pkey, cdata):
+ def _public_key_bytes(self, encoding, format, key, evp_pkey, cdata):
if not isinstance(encoding, serialization.Encoding):
raise TypeError("encoding must be an item from the Encoding enum")
-
if not isinstance(format, serialization.PublicFormat):
raise TypeError(
"format must be an item from the PublicFormat enum"
)
+ # SubjectPublicKeyInfo + PEM/DER
if format is serialization.PublicFormat.SubjectPublicKeyInfo:
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_PUBKEY
elif encoding is serialization.Encoding.DER:
write_bio = self._lib.i2d_PUBKEY_bio
+ else:
+ raise ValueError(
+ "SubjectPublicKeyInfo works only with PEM or DER encoding"
+ )
+ return self._bio_func_output(write_bio, evp_pkey)
- key = evp_pkey
- elif format is serialization.PublicFormat.PKCS1:
+ # PKCS1 + PEM/DER
+ if format is serialization.PublicFormat.PKCS1:
# Only RSA is supported here.
- assert evp_pkey.type == self._lib.EVP_PKEY_RSA
+ key_type = self._lib.EVP_PKEY_id(evp_pkey)
+ if key_type != self._lib.EVP_PKEY_RSA:
+ raise ValueError("PKCS1 format is supported only for RSA keys")
+
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_RSAPublicKey
elif encoding is serialization.Encoding.DER:
write_bio = self._lib.i2d_RSAPublicKey_bio
+ else:
+ raise ValueError(
+ "PKCS1 works only with PEM or DER encoding"
+ )
+ return self._bio_func_output(write_bio, cdata)
+
+ # OpenSSH + OpenSSH
+ if format is serialization.PublicFormat.OpenSSH:
+ if encoding is serialization.Encoding.OpenSSH:
+ return self._openssh_public_key_bytes(key)
- key = cdata
+ raise ValueError(
+ "OpenSSH format must be used with OpenSSH encoding"
+ )
- bio = self._create_mem_bio()
- res = write_bio(bio, key)
- assert res == 1
+ # Anything that key-specific code was supposed to handle earlier,
+ # like Raw, CompressedPoint, UncompressedPoint
+ raise ValueError("format is invalid with this key")
+
+ def _openssh_public_key_bytes(self, key):
+ if isinstance(key, rsa.RSAPublicKey):
+ public_numbers = key.public_numbers()
+ return b"ssh-rsa " + base64.b64encode(
+ ssh._ssh_write_string(b"ssh-rsa") +
+ ssh._ssh_write_mpint(public_numbers.e) +
+ ssh._ssh_write_mpint(public_numbers.n)
+ )
+ elif isinstance(key, dsa.DSAPublicKey):
+ public_numbers = key.public_numbers()
+ parameter_numbers = public_numbers.parameter_numbers
+ return b"ssh-dss " + base64.b64encode(
+ ssh._ssh_write_string(b"ssh-dss") +
+ ssh._ssh_write_mpint(parameter_numbers.p) +
+ ssh._ssh_write_mpint(parameter_numbers.q) +
+ ssh._ssh_write_mpint(parameter_numbers.g) +
+ ssh._ssh_write_mpint(public_numbers.y)
+ )
+ elif isinstance(key, ed25519.Ed25519PublicKey):
+ raw_bytes = key.public_bytes(serialization.Encoding.Raw,
+ serialization.PublicFormat.Raw)
+ return b"ssh-ed25519 " + base64.b64encode(
+ ssh._ssh_write_string(b"ssh-ed25519") +
+ ssh._ssh_write_string(raw_bytes)
+ )
+ elif isinstance(key, ec.EllipticCurvePublicKey):
+ public_numbers = key.public_numbers()
+ try:
+ curve_name = {
+ ec.SECP256R1: b"nistp256",
+ ec.SECP384R1: b"nistp384",
+ ec.SECP521R1: b"nistp521",
+ }[type(public_numbers.curve)]
+ except KeyError:
+ raise ValueError(
+ "Only SECP256R1, SECP384R1, and SECP521R1 curves are "
+ "supported by the SSH public key format"
+ )
+
+ point = key.public_bytes(
+ serialization.Encoding.X962,
+ serialization.PublicFormat.UncompressedPoint
+ )
+ return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode(
+ ssh._ssh_write_string(b"ecdsa-sha2-" + curve_name) +
+ ssh._ssh_write_string(curve_name) +
+ ssh._ssh_write_string(point)
+ )
+ else:
+ raise ValueError(
+ "OpenSSH encoding is not supported for this key type"
+ )
+
+ def _parameter_bytes(self, encoding, format, cdata):
+ if encoding is serialization.Encoding.OpenSSH:
+ raise TypeError(
+ "OpenSSH encoding is not supported"
+ )
+
+ # Only DH is supported here currently.
+ q = self._ffi.new("BIGNUM **")
+ self._lib.DH_get0_pqg(cdata,
+ self._ffi.NULL,
+ q,
+ self._ffi.NULL)
+ if encoding is serialization.Encoding.PEM:
+ if q[0] != self._ffi.NULL:
+ write_bio = self._lib.PEM_write_bio_DHxparams
+ else:
+ write_bio = self._lib.PEM_write_bio_DHparams
+ elif encoding is serialization.Encoding.DER:
+ if q[0] != self._ffi.NULL:
+ write_bio = self._lib.Cryptography_i2d_DHxparams_bio
+ else:
+ write_bio = self._lib.i2d_DHparams_bio
+ else:
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ bio = self._create_mem_bio_gc()
+ res = write_bio(bio, cdata)
+ self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
+ def generate_dh_parameters(self, generator, key_size):
+ if key_size < 512:
+ raise ValueError("DH key_size must be at least 512 bits")
+
+ if generator not in (2, 5):
+ raise ValueError("DH generator must be 2 or 5")
+
+ dh_param_cdata = self._lib.DH_new()
+ self.openssl_assert(dh_param_cdata != self._ffi.NULL)
+ dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free)
+
+ res = self._lib.DH_generate_parameters_ex(
+ dh_param_cdata,
+ key_size,
+ generator,
+ self._ffi.NULL
+ )
+ self.openssl_assert(res == 1)
+
+ return _DHParameters(self, dh_param_cdata)
+
+ def _dh_cdata_to_evp_pkey(self, dh_cdata):
+ evp_pkey = self._create_evp_pkey_gc()
+ res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata)
+ self.openssl_assert(res == 1)
+ return evp_pkey
+
+ def generate_dh_private_key(self, parameters):
+ dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self)
+
+ res = self._lib.DH_generate_key(dh_key_cdata)
+ self.openssl_assert(res == 1)
+
+ evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata)
+
+ return _DHPrivateKey(self, dh_key_cdata, evp_pkey)
+
+ def generate_dh_private_key_and_parameters(self, generator, key_size):
+ return self.generate_dh_private_key(
+ self.generate_dh_parameters(generator, key_size))
+
+ def load_dh_private_numbers(self, numbers):
+ parameter_numbers = numbers.public_numbers.parameter_numbers
+
+ dh_cdata = self._lib.DH_new()
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+
+ p = self._int_to_bn(parameter_numbers.p)
+ g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
+ pub_key = self._int_to_bn(numbers.public_numbers.y)
+ priv_key = self._int_to_bn(numbers.x)
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
+ self.openssl_assert(res == 1)
+
+ res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key)
+ self.openssl_assert(res == 1)
+
+ codes = self._ffi.new("int[]", 1)
+ res = self._lib.Cryptography_DH_check(dh_cdata, codes)
+ self.openssl_assert(res == 1)
+
+ # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not
+ # equal 11 when the generator is 2 (a quadratic nonresidue).
+ # We want to ignore that error because p % 24 == 23 is also fine.
+ # Specifically, g is then a quadratic residue. Within the context of
+ # Diffie-Hellman this means it can only generate half the possible
+ # values. That sounds bad, but quadratic nonresidues leak a bit of
+ # the key to the attacker in exchange for having the full key space
+ # available. See: https://crypto.stackexchange.com/questions/12961
+ if codes[0] != 0 and not (
+ parameter_numbers.g == 2 and
+ codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0
+ ):
+ raise ValueError(
+ "DH private numbers did not pass safety checks."
+ )
+
+ evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata)
+
+ return _DHPrivateKey(self, dh_cdata, evp_pkey)
+
+ def load_dh_public_numbers(self, numbers):
+ dh_cdata = self._lib.DH_new()
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+
+ parameter_numbers = numbers.parameter_numbers
+
+ p = self._int_to_bn(parameter_numbers.p)
+ g = self._int_to_bn(parameter_numbers.g)
+
+ if parameter_numbers.q is not None:
+ q = self._int_to_bn(parameter_numbers.q)
+ else:
+ q = self._ffi.NULL
+
+ pub_key = self._int_to_bn(numbers.y)
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
+ self.openssl_assert(res == 1)
+
+ res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL)
+ self.openssl_assert(res == 1)
+
+ evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata)
+
+ return _DHPublicKey(self, dh_cdata, evp_pkey)
+
+ def load_dh_parameter_numbers(self, numbers):
+ dh_cdata = self._lib.DH_new()
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+
+ p = self._int_to_bn(numbers.p)
+ g = self._int_to_bn(numbers.g)
+
+ if numbers.q is not None:
+ q = self._int_to_bn(numbers.q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
+ self.openssl_assert(res == 1)
+
+ return _DHParameters(self, dh_cdata)
+
+ def dh_parameters_supported(self, p, g, q=None):
+ dh_cdata = self._lib.DH_new()
+ self.openssl_assert(dh_cdata != self._ffi.NULL)
+ dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free)
+
+ p = self._int_to_bn(p)
+ g = self._int_to_bn(g)
+
+ if q is not None:
+ q = self._int_to_bn(q)
+ else:
+ q = self._ffi.NULL
+
+ res = self._lib.DH_set0_pqg(dh_cdata, p, q, g)
+ self.openssl_assert(res == 1)
+
+ codes = self._ffi.new("int[]", 1)
+ res = self._lib.Cryptography_DH_check(dh_cdata, codes)
+ self.openssl_assert(res == 1)
+
+ return codes[0] == 0
+
+ def dh_x942_serialization_supported(self):
+ return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1
+
+ def x509_name_bytes(self, name):
+ x509_name = _encode_name_gc(self, name)
+ pp = self._ffi.new("unsigned char **")
+ res = self._lib.i2d_X509_NAME(x509_name, pp)
+ self.openssl_assert(pp[0] != self._ffi.NULL)
+ pp = self._ffi.gc(
+ pp, lambda pointer: self._lib.OPENSSL_free(pointer[0])
+ )
+ self.openssl_assert(res > 0)
+ return self._ffi.buffer(pp[0], res)[:]
+
+ def x25519_load_public_bytes(self, data):
+ # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
+ # switch this to EVP_PKEY_new_raw_public_key
+ if len(data) != 32:
+ raise ValueError("An X25519 public key is 32 bytes long")
+
+ evp_pkey = self._create_evp_pkey_gc()
+ res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519)
+ self.openssl_assert(res == 1)
+ res = self._lib.EVP_PKEY_set1_tls_encodedpoint(
+ evp_pkey, data, len(data)
+ )
+ self.openssl_assert(res == 1)
+ return _X25519PublicKey(self, evp_pkey)
+
+ def x25519_load_private_bytes(self, data):
+ # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
+ # switch this to EVP_PKEY_new_raw_private_key and drop the
+ # zeroed_bytearray garbage.
+ # OpenSSL only has facilities for loading PKCS8 formatted private
+ # keys using the algorithm identifiers specified in
+ # https://tools.ietf.org/html/draft-ietf-curdle-pkix-09.
+ # This is the standard PKCS8 prefix for a 32 byte X25519 key.
+ # The form is:
+ # 0:d=0 hl=2 l= 46 cons: SEQUENCE
+ # 2:d=1 hl=2 l= 1 prim: INTEGER :00
+ # 5:d=1 hl=2 l= 5 cons: SEQUENCE
+ # 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.110
+ # 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key)
+ # Of course there's a bit more complexity. In reality OCTET STRING
+ # contains an OCTET STRING of length 32! So the last two bytes here
+ # are \x04\x20, which is an OCTET STRING of length 32.
+ if len(data) != 32:
+ raise ValueError("An X25519 private key is 32 bytes long")
+
+ pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 '
+ with self._zeroed_bytearray(48) as ba:
+ ba[0:16] = pkcs8_prefix
+ ba[16:] = data
+ bio = self._bytes_to_bio(ba)
+ evp_pkey = self._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL)
+
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ self.openssl_assert(
+ self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519
+ )
+ return _X25519PrivateKey(self, evp_pkey)
+
+ def _evp_pkey_keygen_gc(self, nid):
+ evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL)
+ self.openssl_assert(evp_pkey_ctx != self._ffi.NULL)
+ evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free)
+ res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx)
+ self.openssl_assert(res == 1)
+ evp_ppkey = self._ffi.new("EVP_PKEY **")
+ res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey)
+ self.openssl_assert(res == 1)
+ self.openssl_assert(evp_ppkey[0] != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free)
+ return evp_pkey
+
+ def x25519_generate_key(self):
+ evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519)
+ return _X25519PrivateKey(self, evp_pkey)
+
+ def x25519_supported(self):
+ return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
+
+ def x448_load_public_bytes(self, data):
+ if len(data) != 56:
+ raise ValueError("An X448 public key is 56 bytes long")
+
+ evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
+ self._lib.NID_X448, self._ffi.NULL, data, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ return _X448PublicKey(self, evp_pkey)
+
+ def x448_load_private_bytes(self, data):
+ if len(data) != 56:
+ raise ValueError("An X448 private key is 56 bytes long")
+
+ data_ptr = self._ffi.from_buffer(data)
+ evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
+ self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+ return _X448PrivateKey(self, evp_pkey)
+
+ def x448_generate_key(self):
+ evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448)
+ return _X448PrivateKey(self, evp_pkey)
+
+ def x448_supported(self):
+ return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
+
+ def ed25519_supported(self):
+ return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
+
+ def ed25519_load_public_bytes(self, data):
+ utils._check_bytes("data", data)
+
+ if len(data) != ed25519._ED25519_KEY_SIZE:
+ raise ValueError("An Ed25519 public key is 32 bytes long")
+
+ evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
+ self._lib.NID_ED25519, self._ffi.NULL, data, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+
+ return _Ed25519PublicKey(self, evp_pkey)
+
+ def ed25519_load_private_bytes(self, data):
+ if len(data) != ed25519._ED25519_KEY_SIZE:
+ raise ValueError("An Ed25519 private key is 32 bytes long")
+
+ utils._check_byteslike("data", data)
+ data_ptr = self._ffi.from_buffer(data)
+ evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
+ self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+
+ return _Ed25519PrivateKey(self, evp_pkey)
+
+ def ed25519_generate_key(self):
+ evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519)
+ return _Ed25519PrivateKey(self, evp_pkey)
+
+ def ed448_supported(self):
+ return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B
+
+ def ed448_load_public_bytes(self, data):
+ utils._check_bytes("data", data)
+ if len(data) != _ED448_KEY_SIZE:
+ raise ValueError("An Ed448 public key is 57 bytes long")
+
+ evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
+ self._lib.NID_ED448, self._ffi.NULL, data, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+
+ return _Ed448PublicKey(self, evp_pkey)
+
+ def ed448_load_private_bytes(self, data):
+ utils._check_byteslike("data", data)
+ if len(data) != _ED448_KEY_SIZE:
+ raise ValueError("An Ed448 private key is 57 bytes long")
+
+ data_ptr = self._ffi.from_buffer(data)
+ evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
+ self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data)
+ )
+ self.openssl_assert(evp_pkey != self._ffi.NULL)
+ evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
+
+ return _Ed448PrivateKey(self, evp_pkey)
+
+ def ed448_generate_key(self):
+ evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448)
+ return _Ed448PrivateKey(self, evp_pkey)
+
+ def derive_scrypt(self, key_material, salt, length, n, r, p):
+ buf = self._ffi.new("unsigned char[]", length)
+ key_material_ptr = self._ffi.from_buffer(key_material)
+ res = self._lib.EVP_PBE_scrypt(
+ key_material_ptr, len(key_material), salt, len(salt), n, r, p,
+ scrypt._MEM_LIMIT, buf, length
+ )
+ if res != 1:
+ errors = self._consume_errors()
+ if not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111:
+ # This error is only added to the stack in 1.1.1+
+ self.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP,
+ self._lib.ERR_R_MALLOC_FAILURE
+ ) or
+ errors[0]._lib_reason_match(
+ self._lib.ERR_LIB_EVP,
+ self._lib.EVP_R_MEMORY_LIMIT_EXCEEDED
+ )
+ )
+
+ # memory required formula explained here:
+ # https://blog.filippo.io/the-scrypt-parameters/
+ min_memory = 128 * n * r // (1024**2)
+ raise MemoryError(
+ "Not enough memory to derive key. These parameters require"
+ " {} MB of memory.".format(min_memory)
+ )
+ return self._ffi.buffer(buf)[:]
+
+ def aead_cipher_supported(self, cipher):
+ cipher_name = aead._aead_cipher_name(cipher)
+ return (
+ self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL
+ )
+
+ @contextlib.contextmanager
+ def _zeroed_bytearray(self, length):
+ """
+ This method creates a bytearray, which we copy data into (hopefully
+ also from a mutable buffer that can be dynamically erased!), and then
+ zero when we're done.
+ """
+ ba = bytearray(length)
+ try:
+ yield ba
+ finally:
+ self._zero_data(ba, length)
+
+ def _zero_data(self, data, length):
+ # We clear things this way because at the moment we're not
+ # sure of a better way that can guarantee it overwrites the
+ # memory of a bytearray and doesn't just replace the underlying char *.
+ for i in range(length):
+ data[i] = 0
+
+ @contextlib.contextmanager
+ def _zeroed_null_terminated_buf(self, data):
+ """
+ This method takes bytes, which can be a bytestring or a mutable
+ buffer like a bytearray, and yields a null-terminated version of that
+ data. This is required because PKCS12_parse doesn't take a length with
+ its password char * and ffi.from_buffer doesn't provide null
+ termination. So, to support zeroing the data via bytearray we
+ need to build this ridiculous construct that copies the memory, but
+ zeroes it after use.
+ """
+ if data is None:
+ yield self._ffi.NULL
+ else:
+ data_len = len(data)
+ buf = self._ffi.new("char[]", data_len + 1)
+ self._ffi.memmove(buf, data, data_len)
+ try:
+ yield buf
+ finally:
+ # Cast to a uint8_t * so we can assign by integer
+ self._zero_data(self._ffi.cast("uint8_t *", buf), data_len)
+
+ def load_key_and_certificates_from_pkcs12(self, data, password):
+ if password is not None:
+ utils._check_byteslike("password", password)
+
+ bio = self._bytes_to_bio(data)
+ p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL)
+ if p12 == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Could not deserialize PKCS12 data")
+
+ p12 = self._ffi.gc(p12, self._lib.PKCS12_free)
+ evp_pkey_ptr = self._ffi.new("EVP_PKEY **")
+ x509_ptr = self._ffi.new("X509 **")
+ sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **")
+ with self._zeroed_null_terminated_buf(password) as password_buf:
+ res = self._lib.PKCS12_parse(
+ p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr
+ )
+
+ if res == 0:
+ self._consume_errors()
+ raise ValueError("Invalid password or PKCS12 data")
+
+ cert = None
+ key = None
+ additional_certificates = []
+
+ if evp_pkey_ptr[0] != self._ffi.NULL:
+ evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free)
+ key = self._evp_pkey_to_private_key(evp_pkey)
+
+ if x509_ptr[0] != self._ffi.NULL:
+ x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free)
+ cert = _Certificate(self, x509)
+
+ if sk_x509_ptr[0] != self._ffi.NULL:
+ sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free)
+ num = self._lib.sk_X509_num(sk_x509_ptr[0])
+ for i in range(num):
+ x509 = self._lib.sk_X509_value(sk_x509, i)
+ x509 = self._ffi.gc(x509, self._lib.X509_free)
+ self.openssl_assert(x509 != self._ffi.NULL)
+ additional_certificates.append(_Certificate(self, x509))
+
+ return (key, cert, additional_certificates)
+
+ def poly1305_supported(self):
+ return self._lib.Cryptography_HAS_POLY1305 == 1
+
+ def create_poly1305_ctx(self, key):
+ utils._check_byteslike("key", key)
+ if len(key) != _POLY1305_KEY_SIZE:
+ raise ValueError("A poly1305 key is 32 bytes long")
+
+ return _Poly1305Context(self, key)
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -1485,4 +2451,9 @@ class GetCipherByName(object):
return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii"))
+def _get_xts_cipher(backend, cipher, mode):
+ cipher_name = "aes-{}-xts".format(cipher.key_size // 2)
+ 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
index 64097c7b..1de81419 100644
--- a/src/cryptography/hazmat/backends/openssl/ciphers.py
+++ b/src/cryptography/hazmat/backends/openssl/ciphers.py
@@ -13,6 +13,7 @@ from cryptography.hazmat.primitives.ciphers import modes
@utils.register_interface(ciphers.CipherContext)
@utils.register_interface(ciphers.AEADCipherContext)
@utils.register_interface(ciphers.AEADEncryptionContext)
+@utils.register_interface(ciphers.AEADDecryptionContext)
class _CipherContext(object):
_ENCRYPT = 1
_DECRYPT = 0
@@ -25,9 +26,9 @@ class _CipherContext(object):
self._tag = None
if isinstance(self._cipher, ciphers.BlockCipherAlgorithm):
- self._block_size = self._cipher.block_size
+ self._block_size_bytes = self._cipher.block_size // 8
else:
- self._block_size = 1
+ self._block_size_bytes = 1
ctx = self._backend._lib.EVP_CIPHER_CTX_new()
ctx = self._backend._ffi.gc(
@@ -39,7 +40,7 @@ class _CipherContext(object):
adapter = registry[type(cipher), type(mode)]
except KeyError:
raise UnsupportedAlgorithm(
- "cipher {0} in {1} mode is not supported "
+ "cipher {} in {} mode is not supported "
"by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
@@ -47,17 +48,25 @@ class _CipherContext(object):
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
- )
+ msg = "cipher {0.name} ".format(cipher)
+ if mode is not None:
+ msg += "in {0.name} mode ".format(mode)
+ msg += (
+ "is not supported by this backend (Your version of OpenSSL "
+ "may be too old. Current version: {}.)"
+ ).format(self._backend.openssl_version_text())
+ raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER)
if isinstance(mode, modes.ModeWithInitializationVector):
- iv_nonce = mode.initialization_vector
+ iv_nonce = self._backend._ffi.from_buffer(
+ mode.initialization_vector
+ )
+ elif isinstance(mode, modes.ModeWithTweak):
+ iv_nonce = self._backend._ffi.from_buffer(mode.tweak)
elif isinstance(mode, modes.ModeWithNonce):
- iv_nonce = mode.nonce
+ iv_nonce = self._backend._ffi.from_buffer(mode.nonce)
+ elif isinstance(cipher, modes.ModeWithNonce):
+ iv_nonce = self._backend._ffi.from_buffer(cipher.nonce)
else:
iv_nonce = self._backend._ffi.NULL
# begin init with cipher and operation type
@@ -66,68 +75,75 @@ class _CipherContext(object):
self._backend._ffi.NULL,
self._backend._ffi.NULL,
operation)
- assert res != 0
+ self._backend.openssl_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
+ self._backend.openssl_assert(res != 0)
if isinstance(mode, modes.GCM):
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
- ctx, self._backend._lib.EVP_CTRL_GCM_SET_IVLEN,
+ ctx, self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN,
len(iv_nonce), self._backend._ffi.NULL
)
- assert res != 0
- if operation == self._DECRYPT:
+ self._backend.openssl_assert(res != 0)
+ if mode.tag is not None:
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
- ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
+ ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG,
len(mode.tag), mode.tag
)
- assert res != 0
+ self._backend.openssl_assert(res != 0)
+ self._tag = mode.tag
# pass key/iv
res = self._backend._lib.EVP_CipherInit_ex(
ctx,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
- cipher.key,
+ self._backend._ffi.from_buffer(cipher.key),
iv_nonce,
operation
)
- assert res != 0
+ self._backend.openssl_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, modes.GCM):
- return b""
-
- buf = self._backend._ffi.new("unsigned char[]",
- len(data) + self._block_size - 1)
+ buf = bytearray(len(data) + self._block_size_bytes - 1)
+ n = self.update_into(data, buf)
+ return bytes(buf[:n])
+
+ def update_into(self, data, buf):
+ if len(buf) < (len(data) + self._block_size_bytes - 1):
+ raise ValueError(
+ "buffer must be at least {} bytes for this "
+ "payload".format(len(data) + self._block_size_bytes - 1)
+ )
+
+ buf = self._backend._ffi.cast(
+ "unsigned char *", self._backend._ffi.from_buffer(buf)
+ )
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]]
+ res = self._backend._lib.EVP_CipherUpdate(
+ self._ctx, buf, outlen,
+ self._backend._ffi.from_buffer(data), len(data)
+ )
+ self._backend.openssl_assert(res != 0)
+ return 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, modes.GCM):
- self.update(b"")
-
- buf = self._backend._ffi.new("unsigned char[]", self._block_size)
+ if (
+ self._operation == self._DECRYPT and
+ isinstance(self._mode, modes.ModeWithAuthenticationTag) and
+ self.tag is None
+ ):
+ raise ValueError(
+ "Authentication tag must be provided when decrypting."
+ )
+
+ buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes)
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
if res == 0:
@@ -136,81 +152,53 @@ class _CipherContext(object):
if not errors and isinstance(self._mode, modes.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."
+ self._backend.openssl_assert(
+ errors[0]._lib_reason_match(
+ self._backend._lib.ERR_LIB_EVP,
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH
)
- else:
- raise self._backend._unknown_error(errors[0])
+ )
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length."
+ )
if (isinstance(self._mode, modes.GCM) and
self._operation == self._ENCRYPT):
- block_byte_size = self._block_size // 8
tag_buf = self._backend._ffi.new(
- "unsigned char[]", block_byte_size
+ "unsigned char[]", self._block_size_bytes
)
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
- self._ctx, self._backend._lib.EVP_CTRL_GCM_GET_TAG,
- block_byte_size, tag_buf
+ self._ctx, self._backend._lib.EVP_CTRL_AEAD_GET_TAG,
+ self._block_size_bytes, tag_buf
)
- assert res != 0
+ self._backend.openssl_assert(res != 0)
self._tag = self._backend._ffi.buffer(tag_buf)[:]
res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
- assert res == 1
+ self._backend.openssl_assert(res == 1)
return self._backend._ffi.buffer(buf)[:outlen[0]]
+ def finalize_with_tag(self, tag):
+ if len(tag) < self._mode._min_tag_length:
+ raise ValueError(
+ "Authentication tag must be {} bytes or longer.".format(
+ self._mode._min_tag_length)
+ )
+ res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
+ self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG,
+ len(tag), tag
+ )
+ self._backend.openssl_assert(res != 0)
+ self._tag = tag
+ return self.finalize()
+
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)
+ self._ctx, self._backend._ffi.NULL, outlen,
+ self._backend._ffi.from_buffer(data), len(data)
)
- assert res != 0
+ self._backend.openssl_assert(res != 0)
tag = utils.read_only_property("_tag")
-
-
-@utils.register_interface(ciphers.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
index 6c48ac34..d4d46f55 100644
--- a/src/cryptography/hazmat/backends/openssl/cmac.py
+++ b/src/cryptography/hazmat/backends/openssl/cmac.py
@@ -9,11 +9,10 @@ from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
-from cryptography.hazmat.primitives import constant_time, interfaces
+from cryptography.hazmat.primitives import constant_time
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):
@@ -33,13 +32,15 @@ class _CMACContext(object):
ctx = self._backend._lib.CMAC_CTX_new()
- assert ctx != self._backend._ffi.NULL
+ self._backend.openssl_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),
+ key_ptr = self._backend._ffi.from_buffer(self._key)
+ res = self._backend._lib.CMAC_Init(
+ ctx, key_ptr, len(self._key),
evp_cipher, self._backend._ffi.NULL
)
+ self._backend.openssl_assert(res == 1)
self._ctx = ctx
@@ -47,7 +48,7 @@ class _CMACContext(object):
def update(self, data):
res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
- assert res == 1
+ self._backend.openssl_assert(res == 1)
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", self._output_length)
@@ -55,7 +56,7 @@ class _CMACContext(object):
res = self._backend._lib.CMAC_Final(
self._ctx, buf, length
)
- assert res == 1
+ self._backend.openssl_assert(res == 1)
self._ctx = None
@@ -69,7 +70,7 @@ class _CMACContext(object):
res = self._backend._lib.CMAC_CTX_copy(
copied_ctx, self._ctx
)
- assert res == 1
+ self._backend.openssl_assert(res == 1)
return _CMACContext(
self._backend, self._algorithm, ctx=copied_ctx
)
diff --git a/src/cryptography/hazmat/backends/openssl/decode_asn1.py b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
new file mode 100644
index 00000000..7639e689
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/decode_asn1.py
@@ -0,0 +1,910 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import datetime
+import ipaddress
+
+import six
+
+from cryptography import x509
+from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE
+from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM
+from cryptography.x509.name import _ASN1_TYPE_TO_ENUM
+from cryptography.x509.oid import (
+ CRLEntryExtensionOID, CertificatePoliciesOID, ExtensionOID,
+ OCSPExtensionOID,
+)
+
+
+def _obj2txt(backend, obj):
+ # Set to 80 on the recommendation of
+ # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values
+ #
+ # But OIDs longer than this occur in real life (e.g. Active
+ # Directory makes some very long OIDs). So we need to detect
+ # and properly handle the case where the default buffer is not
+ # big enough.
+ #
+ buf_len = 80
+ buf = backend._ffi.new("char[]", buf_len)
+
+ # 'res' is the number of bytes that *would* be written if the
+ # buffer is large enough. If 'res' > buf_len - 1, we need to
+ # alloc a big-enough buffer and go again.
+ res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
+ if res > buf_len - 1: # account for terminating null byte
+ buf_len = res + 1
+ buf = backend._ffi.new("char[]", buf_len)
+ res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
+ backend.openssl_assert(res > 0)
+ return backend._ffi.buffer(buf, res)[:].decode()
+
+
+def _decode_x509_name_entry(backend, x509_name_entry):
+ obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry)
+ backend.openssl_assert(obj != backend._ffi.NULL)
+ data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry)
+ backend.openssl_assert(data != backend._ffi.NULL)
+ value = _asn1_string_to_utf8(backend, data)
+ oid = _obj2txt(backend, obj)
+ type = _ASN1_TYPE_TO_ENUM[data.type]
+
+ return x509.NameAttribute(x509.ObjectIdentifier(oid), value, type)
+
+
+def _decode_x509_name(backend, x509_name):
+ count = backend._lib.X509_NAME_entry_count(x509_name)
+ attributes = []
+ prev_set_id = -1
+ for x in range(count):
+ entry = backend._lib.X509_NAME_get_entry(x509_name, x)
+ attribute = _decode_x509_name_entry(backend, entry)
+ set_id = backend._lib.Cryptography_X509_NAME_ENTRY_set(entry)
+ if set_id != prev_set_id:
+ attributes.append({attribute})
+ else:
+ # is in the same RDN a previous entry
+ attributes[-1].add(attribute)
+ prev_set_id = set_id
+
+ return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes)
+
+
+def _decode_general_names(backend, gns):
+ num = backend._lib.sk_GENERAL_NAME_num(gns)
+ names = []
+ for i in range(num):
+ gn = backend._lib.sk_GENERAL_NAME_value(gns, i)
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ names.append(_decode_general_name(backend, gn))
+
+ return names
+
+
+def _decode_general_name(backend, gn):
+ if gn.type == backend._lib.GEN_DNS:
+ # Convert to bytes and then decode to utf8. We don't use
+ # asn1_string_to_utf8 here because it doesn't properly convert
+ # utf8 from ia5strings.
+ data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8")
+ # We don't use the constructor for DNSName so we can bypass validation
+ # This allows us to create DNSName objects that have unicode chars
+ # when a certificate (against the RFC) contains them.
+ return x509.DNSName._init_without_validation(data)
+ elif gn.type == backend._lib.GEN_URI:
+ # Convert to bytes and then decode to utf8. We don't use
+ # asn1_string_to_utf8 here because it doesn't properly convert
+ # utf8 from ia5strings.
+ data = _asn1_string_to_bytes(
+ backend, gn.d.uniformResourceIdentifier
+ ).decode("utf8")
+ # We don't use the constructor for URI so we can bypass validation
+ # This allows us to create URI objects that have unicode chars
+ # when a certificate (against the RFC) contains them.
+ return x509.UniformResourceIdentifier._init_without_validation(data)
+ elif gn.type == backend._lib.GEN_RID:
+ oid = _obj2txt(backend, gn.d.registeredID)
+ return x509.RegisteredID(x509.ObjectIdentifier(oid))
+ elif gn.type == backend._lib.GEN_IPADD:
+ data = _asn1_string_to_bytes(backend, gn.d.iPAddress)
+ data_len = len(data)
+ if data_len == 8 or data_len == 32:
+ # This is an IPv4 or IPv6 Network and not a single IP. This
+ # type of data appears in Name Constraints. Unfortunately,
+ # ipaddress doesn't support packed bytes + netmask. Additionally,
+ # IPv6Network can only handle CIDR rather than the full 16 byte
+ # netmask. To handle this we convert the netmask to integer, then
+ # find the first 0 bit, which will be the prefix. If another 1
+ # bit is present after that the netmask is invalid.
+ base = ipaddress.ip_address(data[:data_len // 2])
+ netmask = ipaddress.ip_address(data[data_len // 2:])
+ bits = bin(int(netmask))[2:]
+ prefix = bits.find('0')
+ # If no 0 bits are found it is a /32 or /128
+ if prefix == -1:
+ prefix = len(bits)
+
+ if "1" in bits[prefix:]:
+ raise ValueError("Invalid netmask")
+
+ ip = ipaddress.ip_network(base.exploded + u"/{}".format(prefix))
+ else:
+ ip = ipaddress.ip_address(data)
+
+ return x509.IPAddress(ip)
+ elif gn.type == backend._lib.GEN_DIRNAME:
+ return x509.DirectoryName(
+ _decode_x509_name(backend, gn.d.directoryName)
+ )
+ elif gn.type == backend._lib.GEN_EMAIL:
+ # Convert to bytes and then decode to utf8. We don't use
+ # asn1_string_to_utf8 here because it doesn't properly convert
+ # utf8 from ia5strings.
+ data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8")
+ # We don't use the constructor for RFC822Name so we can bypass
+ # validation. This allows us to create RFC822Name objects that have
+ # unicode chars when a certificate (against the RFC) contains them.
+ return x509.RFC822Name._init_without_validation(data)
+ elif gn.type == backend._lib.GEN_OTHERNAME:
+ type_id = _obj2txt(backend, gn.d.otherName.type_id)
+ value = _asn1_to_der(backend, gn.d.otherName.value)
+ return x509.OtherName(x509.ObjectIdentifier(type_id), value)
+ else:
+ # x400Address or ediPartyName
+ raise x509.UnsupportedGeneralNameType(
+ "{} is not a supported type".format(
+ x509._GENERAL_NAMES.get(gn.type, gn.type)
+ ),
+ gn.type
+ )
+
+
+def _decode_ocsp_no_check(backend, ext):
+ return x509.OCSPNoCheck()
+
+
+def _decode_crl_number(backend, ext):
+ asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext)
+ asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
+ return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int))
+
+
+def _decode_delta_crl_indicator(backend, ext):
+ asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext)
+ asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
+ return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int))
+
+
+class _X509ExtensionParser(object):
+ def __init__(self, ext_count, get_ext, handlers):
+ self.ext_count = ext_count
+ self.get_ext = get_ext
+ self.handlers = handlers
+
+ def parse(self, backend, x509_obj):
+ extensions = []
+ seen_oids = set()
+ for i in range(self.ext_count(backend, x509_obj)):
+ ext = self.get_ext(backend, x509_obj, i)
+ backend.openssl_assert(ext != backend._ffi.NULL)
+ crit = backend._lib.X509_EXTENSION_get_critical(ext)
+ critical = crit == 1
+ oid = x509.ObjectIdentifier(
+ _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))
+ )
+ if oid in seen_oids:
+ raise x509.DuplicateExtension(
+ "Duplicate {} extension found".format(oid), oid
+ )
+
+ # These OIDs are only supported in OpenSSL 1.1.0+ but we want
+ # to support them in all versions of OpenSSL so we decode them
+ # ourselves.
+ if oid == ExtensionOID.TLS_FEATURE:
+ # The extension contents are a SEQUENCE OF INTEGERs.
+ data = backend._lib.X509_EXTENSION_get_data(ext)
+ data_bytes = _asn1_string_to_bytes(backend, data)
+ features = DERReader(data_bytes).read_single_element(SEQUENCE)
+ parsed = []
+ while not features.is_empty():
+ parsed.append(features.read_element(INTEGER).as_integer())
+ # Map the features to their enum value.
+ value = x509.TLSFeature(
+ [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed]
+ )
+ extensions.append(x509.Extension(oid, critical, value))
+ seen_oids.add(oid)
+ continue
+ elif oid == ExtensionOID.PRECERT_POISON:
+ data = backend._lib.X509_EXTENSION_get_data(ext)
+ # The contents of the extension must be an ASN.1 NULL.
+ reader = DERReader(_asn1_string_to_bytes(backend, data))
+ reader.read_single_element(NULL).check_empty()
+ extensions.append(x509.Extension(
+ oid, critical, x509.PrecertPoison()
+ ))
+ seen_oids.add(oid)
+ continue
+
+ try:
+ handler = self.handlers[oid]
+ except KeyError:
+ # Dump the DER payload into an UnrecognizedExtension object
+ data = backend._lib.X509_EXTENSION_get_data(ext)
+ backend.openssl_assert(data != backend._ffi.NULL)
+ der = backend._ffi.buffer(data.data, data.length)[:]
+ unrecognized = x509.UnrecognizedExtension(oid, der)
+ extensions.append(
+ x509.Extension(oid, critical, unrecognized)
+ )
+ else:
+ ext_data = backend._lib.X509V3_EXT_d2i(ext)
+ if ext_data == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError(
+ "The {} extension is invalid and can't be "
+ "parsed".format(oid)
+ )
+
+ value = handler(backend, ext_data)
+ extensions.append(x509.Extension(oid, critical, value))
+
+ seen_oids.add(oid)
+
+ return x509.Extensions(extensions)
+
+
+def _decode_certificate_policies(backend, cp):
+ cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp)
+ cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free)
+
+ num = backend._lib.sk_POLICYINFO_num(cp)
+ certificate_policies = []
+ for i in range(num):
+ qualifiers = None
+ pi = backend._lib.sk_POLICYINFO_value(cp, i)
+ oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
+ if pi.qualifiers != backend._ffi.NULL:
+ qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
+ qualifiers = []
+ for j in range(qnum):
+ pqi = backend._lib.sk_POLICYQUALINFO_value(
+ pi.qualifiers, j
+ )
+ pqualid = x509.ObjectIdentifier(
+ _obj2txt(backend, pqi.pqualid)
+ )
+ if pqualid == CertificatePoliciesOID.CPS_QUALIFIER:
+ cpsuri = backend._ffi.buffer(
+ pqi.d.cpsuri.data, pqi.d.cpsuri.length
+ )[:].decode('ascii')
+ qualifiers.append(cpsuri)
+ else:
+ assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE
+ user_notice = _decode_user_notice(
+ backend, pqi.d.usernotice
+ )
+ qualifiers.append(user_notice)
+
+ certificate_policies.append(
+ x509.PolicyInformation(oid, qualifiers)
+ )
+
+ return x509.CertificatePolicies(certificate_policies)
+
+
+def _decode_user_notice(backend, un):
+ explicit_text = None
+ notice_reference = None
+
+ if un.exptext != backend._ffi.NULL:
+ explicit_text = _asn1_string_to_utf8(backend, un.exptext)
+
+ if un.noticeref != backend._ffi.NULL:
+ organization = _asn1_string_to_utf8(
+ backend, un.noticeref.organization
+ )
+
+ num = backend._lib.sk_ASN1_INTEGER_num(
+ un.noticeref.noticenos
+ )
+ notice_numbers = []
+ for i in range(num):
+ asn1_int = backend._lib.sk_ASN1_INTEGER_value(
+ un.noticeref.noticenos, i
+ )
+ notice_num = _asn1_integer_to_int(backend, asn1_int)
+ notice_numbers.append(notice_num)
+
+ notice_reference = x509.NoticeReference(
+ organization, notice_numbers
+ )
+
+ return x509.UserNotice(notice_reference, explicit_text)
+
+
+def _decode_basic_constraints(backend, bc_st):
+ basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st)
+ basic_constraints = backend._ffi.gc(
+ basic_constraints, backend._lib.BASIC_CONSTRAINTS_free
+ )
+ # The byte representation of an ASN.1 boolean true is \xff. OpenSSL
+ # chooses to just map this to its ordinal value, so true is 255 and
+ # false is 0.
+ ca = basic_constraints.ca == 255
+ path_length = _asn1_integer_to_int_or_none(
+ backend, basic_constraints.pathlen
+ )
+
+ return x509.BasicConstraints(ca, path_length)
+
+
+def _decode_subject_key_identifier(backend, asn1_string):
+ asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string)
+ asn1_string = backend._ffi.gc(
+ asn1_string, backend._lib.ASN1_OCTET_STRING_free
+ )
+ return x509.SubjectKeyIdentifier(
+ backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
+ )
+
+
+def _decode_authority_key_identifier(backend, akid):
+ akid = backend._ffi.cast("AUTHORITY_KEYID *", akid)
+ akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
+ key_identifier = None
+ authority_cert_issuer = None
+
+ if akid.keyid != backend._ffi.NULL:
+ key_identifier = backend._ffi.buffer(
+ akid.keyid.data, akid.keyid.length
+ )[:]
+
+ if akid.issuer != backend._ffi.NULL:
+ authority_cert_issuer = _decode_general_names(
+ backend, akid.issuer
+ )
+
+ authority_cert_serial_number = _asn1_integer_to_int_or_none(
+ backend, akid.serial
+ )
+
+ return x509.AuthorityKeyIdentifier(
+ key_identifier, authority_cert_issuer, authority_cert_serial_number
+ )
+
+
+def _decode_authority_information_access(backend, aia):
+ aia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia)
+ aia = backend._ffi.gc(
+ aia,
+ lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
+ x, backend._ffi.addressof(
+ backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
+ )
+ )
+ )
+ num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
+ access_descriptions = []
+ for i in range(num):
+ ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
+ backend.openssl_assert(ad.method != backend._ffi.NULL)
+ oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
+ backend.openssl_assert(ad.location != backend._ffi.NULL)
+ gn = _decode_general_name(backend, ad.location)
+ access_descriptions.append(x509.AccessDescription(oid, gn))
+
+ return x509.AuthorityInformationAccess(access_descriptions)
+
+
+def _decode_key_usage(backend, bit_string):
+ bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
+ bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free)
+ get_bit = backend._lib.ASN1_BIT_STRING_get_bit
+ digital_signature = get_bit(bit_string, 0) == 1
+ content_commitment = get_bit(bit_string, 1) == 1
+ key_encipherment = get_bit(bit_string, 2) == 1
+ data_encipherment = get_bit(bit_string, 3) == 1
+ key_agreement = get_bit(bit_string, 4) == 1
+ key_cert_sign = get_bit(bit_string, 5) == 1
+ crl_sign = get_bit(bit_string, 6) == 1
+ encipher_only = get_bit(bit_string, 7) == 1
+ decipher_only = get_bit(bit_string, 8) == 1
+ return x509.KeyUsage(
+ digital_signature,
+ content_commitment,
+ key_encipherment,
+ data_encipherment,
+ key_agreement,
+ key_cert_sign,
+ crl_sign,
+ encipher_only,
+ decipher_only
+ )
+
+
+def _decode_general_names_extension(backend, gns):
+ gns = backend._ffi.cast("GENERAL_NAMES *", gns)
+ gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
+ general_names = _decode_general_names(backend, gns)
+ return general_names
+
+
+def _decode_subject_alt_name(backend, ext):
+ return x509.SubjectAlternativeName(
+ _decode_general_names_extension(backend, ext)
+ )
+
+
+def _decode_issuer_alt_name(backend, ext):
+ return x509.IssuerAlternativeName(
+ _decode_general_names_extension(backend, ext)
+ )
+
+
+def _decode_name_constraints(backend, nc):
+ nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc)
+ nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
+ permitted = _decode_general_subtrees(backend, nc.permittedSubtrees)
+ excluded = _decode_general_subtrees(backend, nc.excludedSubtrees)
+ return x509.NameConstraints(
+ permitted_subtrees=permitted, excluded_subtrees=excluded
+ )
+
+
+def _decode_general_subtrees(backend, stack_subtrees):
+ if stack_subtrees == backend._ffi.NULL:
+ return None
+
+ num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees)
+ subtrees = []
+
+ for i in range(num):
+ obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i)
+ backend.openssl_assert(obj != backend._ffi.NULL)
+ name = _decode_general_name(backend, obj.base)
+ subtrees.append(name)
+
+ return subtrees
+
+
+def _decode_issuing_dist_point(backend, idp):
+ idp = backend._ffi.cast("ISSUING_DIST_POINT *", idp)
+ idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free)
+ if idp.distpoint != backend._ffi.NULL:
+ full_name, relative_name = _decode_distpoint(backend, idp.distpoint)
+ else:
+ full_name = None
+ relative_name = None
+
+ only_user = idp.onlyuser == 255
+ only_ca = idp.onlyCA == 255
+ indirect_crl = idp.indirectCRL == 255
+ only_attr = idp.onlyattr == 255
+ if idp.onlysomereasons != backend._ffi.NULL:
+ only_some_reasons = _decode_reasons(backend, idp.onlysomereasons)
+ else:
+ only_some_reasons = None
+
+ return x509.IssuingDistributionPoint(
+ full_name, relative_name, only_user, only_ca, only_some_reasons,
+ indirect_crl, only_attr
+ )
+
+
+def _decode_policy_constraints(backend, pc):
+ pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc)
+ pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
+
+ require_explicit_policy = _asn1_integer_to_int_or_none(
+ backend, pc.requireExplicitPolicy
+ )
+ inhibit_policy_mapping = _asn1_integer_to_int_or_none(
+ backend, pc.inhibitPolicyMapping
+ )
+
+ return x509.PolicyConstraints(
+ require_explicit_policy, inhibit_policy_mapping
+ )
+
+
+def _decode_extended_key_usage(backend, sk):
+ sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk)
+ sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
+ num = backend._lib.sk_ASN1_OBJECT_num(sk)
+ ekus = []
+
+ for i in range(num):
+ obj = backend._lib.sk_ASN1_OBJECT_value(sk, i)
+ backend.openssl_assert(obj != backend._ffi.NULL)
+ oid = x509.ObjectIdentifier(_obj2txt(backend, obj))
+ ekus.append(oid)
+
+ return x509.ExtendedKeyUsage(ekus)
+
+
+_DISTPOINT_TYPE_FULLNAME = 0
+_DISTPOINT_TYPE_RELATIVENAME = 1
+
+
+def _decode_dist_points(backend, cdps):
+ cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps)
+ cdps = backend._ffi.gc(cdps, backend._lib.CRL_DIST_POINTS_free)
+
+ num = backend._lib.sk_DIST_POINT_num(cdps)
+ dist_points = []
+ for i in range(num):
+ full_name = None
+ relative_name = None
+ crl_issuer = None
+ reasons = None
+ cdp = backend._lib.sk_DIST_POINT_value(cdps, i)
+ if cdp.reasons != backend._ffi.NULL:
+ reasons = _decode_reasons(backend, cdp.reasons)
+
+ if cdp.CRLissuer != backend._ffi.NULL:
+ crl_issuer = _decode_general_names(backend, cdp.CRLissuer)
+
+ # Certificates may have a crl_issuer/reasons and no distribution
+ # point so make sure it's not null.
+ if cdp.distpoint != backend._ffi.NULL:
+ full_name, relative_name = _decode_distpoint(
+ backend, cdp.distpoint
+ )
+
+ dist_points.append(
+ x509.DistributionPoint(
+ full_name, relative_name, reasons, crl_issuer
+ )
+ )
+
+ return dist_points
+
+
+# ReasonFlags ::= BIT STRING {
+# unused (0),
+# keyCompromise (1),
+# cACompromise (2),
+# affiliationChanged (3),
+# superseded (4),
+# cessationOfOperation (5),
+# certificateHold (6),
+# privilegeWithdrawn (7),
+# aACompromise (8) }
+_REASON_BIT_MAPPING = {
+ 1: x509.ReasonFlags.key_compromise,
+ 2: x509.ReasonFlags.ca_compromise,
+ 3: x509.ReasonFlags.affiliation_changed,
+ 4: x509.ReasonFlags.superseded,
+ 5: x509.ReasonFlags.cessation_of_operation,
+ 6: x509.ReasonFlags.certificate_hold,
+ 7: x509.ReasonFlags.privilege_withdrawn,
+ 8: x509.ReasonFlags.aa_compromise,
+}
+
+
+def _decode_reasons(backend, reasons):
+ # We will check each bit from RFC 5280
+ enum_reasons = []
+ for bit_position, reason in six.iteritems(_REASON_BIT_MAPPING):
+ if backend._lib.ASN1_BIT_STRING_get_bit(reasons, bit_position):
+ enum_reasons.append(reason)
+
+ return frozenset(enum_reasons)
+
+
+def _decode_distpoint(backend, distpoint):
+ if distpoint.type == _DISTPOINT_TYPE_FULLNAME:
+ full_name = _decode_general_names(backend, distpoint.name.fullname)
+ return full_name, None
+
+ # OpenSSL code doesn't test for a specific type for
+ # relativename, everything that isn't fullname is considered
+ # relativename. Per RFC 5280:
+ #
+ # DistributionPointName ::= CHOICE {
+ # fullName [0] GeneralNames,
+ # nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ rns = distpoint.name.relativename
+ rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns)
+ attributes = set()
+ for i in range(rnum):
+ rn = backend._lib.sk_X509_NAME_ENTRY_value(
+ rns, i
+ )
+ backend.openssl_assert(rn != backend._ffi.NULL)
+ attributes.add(
+ _decode_x509_name_entry(backend, rn)
+ )
+
+ relative_name = x509.RelativeDistinguishedName(attributes)
+
+ return None, relative_name
+
+
+def _decode_crl_distribution_points(backend, cdps):
+ dist_points = _decode_dist_points(backend, cdps)
+ return x509.CRLDistributionPoints(dist_points)
+
+
+def _decode_freshest_crl(backend, cdps):
+ dist_points = _decode_dist_points(backend, cdps)
+ return x509.FreshestCRL(dist_points)
+
+
+def _decode_inhibit_any_policy(backend, asn1_int):
+ asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int)
+ asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
+ skip_certs = _asn1_integer_to_int(backend, asn1_int)
+ return x509.InhibitAnyPolicy(skip_certs)
+
+
+def _decode_precert_signed_certificate_timestamps(backend, asn1_scts):
+ from cryptography.hazmat.backends.openssl.x509 import (
+ _SignedCertificateTimestamp
+ )
+ asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts)
+ asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free)
+
+ scts = []
+ for i in range(backend._lib.sk_SCT_num(asn1_scts)):
+ sct = backend._lib.sk_SCT_value(asn1_scts, i)
+
+ scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct))
+ return x509.PrecertificateSignedCertificateTimestamps(scts)
+
+
+# CRLReason ::= ENUMERATED {
+# unspecified (0),
+# keyCompromise (1),
+# cACompromise (2),
+# affiliationChanged (3),
+# superseded (4),
+# cessationOfOperation (5),
+# certificateHold (6),
+# -- value 7 is not used
+# removeFromCRL (8),
+# privilegeWithdrawn (9),
+# aACompromise (10) }
+_CRL_ENTRY_REASON_CODE_TO_ENUM = {
+ 0: x509.ReasonFlags.unspecified,
+ 1: x509.ReasonFlags.key_compromise,
+ 2: x509.ReasonFlags.ca_compromise,
+ 3: x509.ReasonFlags.affiliation_changed,
+ 4: x509.ReasonFlags.superseded,
+ 5: x509.ReasonFlags.cessation_of_operation,
+ 6: x509.ReasonFlags.certificate_hold,
+ 8: x509.ReasonFlags.remove_from_crl,
+ 9: x509.ReasonFlags.privilege_withdrawn,
+ 10: x509.ReasonFlags.aa_compromise,
+}
+
+
+_CRL_ENTRY_REASON_ENUM_TO_CODE = {
+ x509.ReasonFlags.unspecified: 0,
+ x509.ReasonFlags.key_compromise: 1,
+ x509.ReasonFlags.ca_compromise: 2,
+ x509.ReasonFlags.affiliation_changed: 3,
+ x509.ReasonFlags.superseded: 4,
+ x509.ReasonFlags.cessation_of_operation: 5,
+ x509.ReasonFlags.certificate_hold: 6,
+ x509.ReasonFlags.remove_from_crl: 8,
+ x509.ReasonFlags.privilege_withdrawn: 9,
+ x509.ReasonFlags.aa_compromise: 10
+}
+
+
+def _decode_crl_reason(backend, enum):
+ enum = backend._ffi.cast("ASN1_ENUMERATED *", enum)
+ enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free)
+ code = backend._lib.ASN1_ENUMERATED_get(enum)
+
+ try:
+ return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code])
+ except KeyError:
+ raise ValueError("Unsupported reason code: {}".format(code))
+
+
+def _decode_invalidity_date(backend, inv_date):
+ generalized_time = backend._ffi.cast(
+ "ASN1_GENERALIZEDTIME *", inv_date
+ )
+ generalized_time = backend._ffi.gc(
+ generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
+ )
+ return x509.InvalidityDate(
+ _parse_asn1_generalized_time(backend, generalized_time)
+ )
+
+
+def _decode_cert_issuer(backend, gns):
+ gns = backend._ffi.cast("GENERAL_NAMES *", gns)
+ gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
+ general_names = _decode_general_names(backend, gns)
+ return x509.CertificateIssuer(general_names)
+
+
+def _asn1_to_der(backend, asn1_type):
+ buf = backend._ffi.new("unsigned char **")
+ res = backend._lib.i2d_ASN1_TYPE(asn1_type, buf)
+ backend.openssl_assert(res >= 0)
+ backend.openssl_assert(buf[0] != backend._ffi.NULL)
+ buf = backend._ffi.gc(
+ buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])
+ )
+ return backend._ffi.buffer(buf[0], res)[:]
+
+
+def _asn1_integer_to_int(backend, asn1_int):
+ bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL)
+ backend.openssl_assert(bn != backend._ffi.NULL)
+ bn = backend._ffi.gc(bn, backend._lib.BN_free)
+ return backend._bn_to_int(bn)
+
+
+def _asn1_integer_to_int_or_none(backend, asn1_int):
+ if asn1_int == backend._ffi.NULL:
+ return None
+ else:
+ return _asn1_integer_to_int(backend, asn1_int)
+
+
+def _asn1_string_to_bytes(backend, asn1_string):
+ return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
+
+
+def _asn1_string_to_ascii(backend, asn1_string):
+ return _asn1_string_to_bytes(backend, asn1_string).decode("ascii")
+
+
+def _asn1_string_to_utf8(backend, asn1_string):
+ buf = backend._ffi.new("unsigned char **")
+ res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string)
+ if res == -1:
+ raise ValueError(
+ "Unsupported ASN1 string type. Type: {}".format(asn1_string.type)
+ )
+
+ backend.openssl_assert(buf[0] != backend._ffi.NULL)
+ buf = backend._ffi.gc(
+ buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])
+ )
+ return backend._ffi.buffer(buf[0], res)[:].decode('utf8')
+
+
+def _parse_asn1_time(backend, asn1_time):
+ backend.openssl_assert(asn1_time != backend._ffi.NULL)
+ generalized_time = backend._lib.ASN1_TIME_to_generalizedtime(
+ asn1_time, backend._ffi.NULL
+ )
+ if generalized_time == backend._ffi.NULL:
+ raise ValueError(
+ "Couldn't parse ASN.1 time as generalizedtime {!r}".format(
+ _asn1_string_to_bytes(backend, asn1_time)
+ )
+ )
+
+ generalized_time = backend._ffi.gc(
+ generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free
+ )
+ return _parse_asn1_generalized_time(backend, generalized_time)
+
+
+def _parse_asn1_generalized_time(backend, generalized_time):
+ time = _asn1_string_to_ascii(
+ backend, backend._ffi.cast("ASN1_STRING *", generalized_time)
+ )
+ return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+
+
+def _decode_nonce(backend, nonce):
+ nonce = backend._ffi.cast("ASN1_OCTET_STRING *", nonce)
+ nonce = backend._ffi.gc(nonce, backend._lib.ASN1_OCTET_STRING_free)
+ return x509.OCSPNonce(_asn1_string_to_bytes(backend, nonce))
+
+
+_EXTENSION_HANDLERS_NO_SCT = {
+ ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints,
+ ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier,
+ ExtensionOID.KEY_USAGE: _decode_key_usage,
+ ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name,
+ ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage,
+ ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
+ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
+ _decode_authority_information_access
+ ),
+ ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies,
+ ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points,
+ ExtensionOID.FRESHEST_CRL: _decode_freshest_crl,
+ ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check,
+ ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy,
+ ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
+ ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints,
+ ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints,
+}
+_EXTENSION_HANDLERS = _EXTENSION_HANDLERS_NO_SCT.copy()
+_EXTENSION_HANDLERS[
+ ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
+] = _decode_precert_signed_certificate_timestamps
+
+
+_REVOKED_EXTENSION_HANDLERS = {
+ CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason,
+ CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date,
+ CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer,
+}
+
+_CRL_EXTENSION_HANDLERS = {
+ ExtensionOID.CRL_NUMBER: _decode_crl_number,
+ ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator,
+ ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier,
+ ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name,
+ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
+ _decode_authority_information_access
+ ),
+ ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point,
+ ExtensionOID.FRESHEST_CRL: _decode_freshest_crl,
+}
+
+_OCSP_REQ_EXTENSION_HANDLERS = {
+ OCSPExtensionOID.NONCE: _decode_nonce,
+}
+
+_OCSP_BASICRESP_EXTENSION_HANDLERS = {
+ OCSPExtensionOID.NONCE: _decode_nonce,
+}
+
+# All revoked extensions are valid single response extensions, see:
+# https://tools.ietf.org/html/rfc6960#section-4.4.5
+_OCSP_SINGLERESP_EXTENSION_HANDLERS = _REVOKED_EXTENSION_HANDLERS.copy()
+
+_CERTIFICATE_EXTENSION_PARSER_NO_SCT = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
+ handlers=_EXTENSION_HANDLERS_NO_SCT
+)
+
+_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.X509_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.X509_get_ext(x, i),
+ handlers=_EXTENSION_HANDLERS
+)
+
+_CSR_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.sk_X509_EXTENSION_num(x),
+ get_ext=lambda backend, x, i: backend._lib.sk_X509_EXTENSION_value(x, i),
+ handlers=_EXTENSION_HANDLERS
+)
+
+_REVOKED_CERTIFICATE_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.X509_REVOKED_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.X509_REVOKED_get_ext(x, i),
+ handlers=_REVOKED_EXTENSION_HANDLERS,
+)
+
+_CRL_EXTENSION_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.X509_CRL_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.X509_CRL_get_ext(x, i),
+ handlers=_CRL_EXTENSION_HANDLERS,
+)
+
+_OCSP_REQ_EXT_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.OCSP_REQUEST_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.OCSP_REQUEST_get_ext(x, i),
+ handlers=_OCSP_REQ_EXTENSION_HANDLERS,
+)
+
+_OCSP_BASICRESP_EXT_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.OCSP_BASICRESP_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.OCSP_BASICRESP_get_ext(x, i),
+ handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS,
+)
+
+_OCSP_SINGLERESP_EXT_PARSER = _X509ExtensionParser(
+ ext_count=lambda backend, x: backend._lib.OCSP_SINGLERESP_get_ext_count(x),
+ get_ext=lambda backend, x, i: backend._lib.OCSP_SINGLERESP_get_ext(x, i),
+ handlers=_OCSP_SINGLERESP_EXTENSION_HANDLERS,
+)
diff --git a/src/cryptography/hazmat/backends/openssl/dh.py b/src/cryptography/hazmat/backends/openssl/dh.py
new file mode 100644
index 00000000..1d5065c2
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/dh.py
@@ -0,0 +1,281 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric import dh
+
+
+def _dh_params_dup(dh_cdata, backend):
+ lib = backend._lib
+ ffi = backend._ffi
+
+ param_cdata = lib.DHparams_dup(dh_cdata)
+ backend.openssl_assert(param_cdata != ffi.NULL)
+ param_cdata = ffi.gc(param_cdata, lib.DH_free)
+ if lib.CRYPTOGRAPHY_IS_LIBRESSL:
+ # In libressl DHparams_dup don't copy q
+ q = ffi.new("BIGNUM **")
+ lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL)
+ q_dup = lib.BN_dup(q[0])
+ res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL)
+ backend.openssl_assert(res == 1)
+
+ return param_cdata
+
+
+def _dh_cdata_to_parameters(dh_cdata, backend):
+ param_cdata = _dh_params_dup(dh_cdata, backend)
+ return _DHParameters(backend, param_cdata)
+
+
+@utils.register_interface(dh.DHParametersWithSerialization)
+class _DHParameters(object):
+ def __init__(self, backend, dh_cdata):
+ self._backend = backend
+ self._dh_cdata = dh_cdata
+
+ def parameter_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
+ return dh.DHParameterNumbers(
+ p=self._backend._bn_to_int(p[0]),
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
+ )
+
+ def generate_private_key(self):
+ return self._backend.generate_dh_private_key(self)
+
+ def parameter_bytes(self, encoding, format):
+ if format is not serialization.ParameterFormat.PKCS3:
+ raise ValueError(
+ "Only PKCS3 serialization is supported"
+ )
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
+ return self._backend._parameter_bytes(
+ encoding,
+ format,
+ self._dh_cdata
+ )
+
+
+def _handle_dh_compute_key_error(errors, backend):
+ lib = backend._lib
+
+ backend.openssl_assert(
+ errors[0]._lib_reason_match(
+ lib.ERR_LIB_DH, lib.DH_R_INVALID_PUBKEY
+ )
+ )
+
+ raise ValueError("Public key value is invalid for this exchange.")
+
+
+def _get_dh_num_bits(backend, dh_cdata):
+ p = backend._ffi.new("BIGNUM **")
+ backend._lib.DH_get0_pqg(dh_cdata, p,
+ backend._ffi.NULL,
+ backend._ffi.NULL)
+ backend.openssl_assert(p[0] != backend._ffi.NULL)
+ return backend._lib.BN_num_bits(p[0])
+
+
+@utils.register_interface(dh.DHPrivateKeyWithSerialization)
+class _DHPrivateKey(object):
+ def __init__(self, backend, dh_cdata, evp_pkey):
+ self._backend = backend
+ self._dh_cdata = dh_cdata
+ self._evp_pkey = evp_pkey
+ self._key_size_bytes = self._backend._lib.DH_size(dh_cdata)
+
+ @property
+ def key_size(self):
+ return _get_dh_num_bits(self._backend, self._dh_cdata)
+
+ def private_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ priv_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key)
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL)
+ return dh.DHPrivateNumbers(
+ public_numbers=dh.DHPublicNumbers(
+ parameter_numbers=dh.DHParameterNumbers(
+ p=self._backend._bn_to_int(p[0]),
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
+ ),
+ y=self._backend._bn_to_int(pub_key[0])
+ ),
+ x=self._backend._bn_to_int(priv_key[0])
+ )
+
+ def exchange(self, peer_public_key):
+
+ buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes)
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_key(peer_public_key._dh_cdata, pub_key,
+ self._backend._ffi.NULL)
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ res = self._backend._lib.DH_compute_key(
+ buf,
+ pub_key[0],
+ self._dh_cdata
+ )
+
+ if res == -1:
+ errors = self._backend._consume_errors()
+ return _handle_dh_compute_key_error(errors, self._backend)
+ else:
+ self._backend.openssl_assert(res >= 1)
+
+ key = self._backend._ffi.buffer(buf)[:res]
+ pad = self._key_size_bytes - len(key)
+
+ if pad > 0:
+ key = (b"\x00" * pad) + key
+
+ return key
+
+ def public_key(self):
+ dh_cdata = _dh_params_dup(self._dh_cdata, self._backend)
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_key(self._dh_cdata,
+ pub_key, self._backend._ffi.NULL)
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ pub_key_dup = self._backend._lib.BN_dup(pub_key[0])
+ self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL)
+
+ res = self._backend._lib.DH_set0_key(dh_cdata,
+ pub_key_dup,
+ self._backend._ffi.NULL)
+ self._backend.openssl_assert(res == 1)
+ evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata)
+ return _DHPublicKey(self._backend, dh_cdata, evp_pkey)
+
+ def parameters(self):
+ return _dh_cdata_to_parameters(self._dh_cdata, self._backend)
+
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if format is not serialization.PrivateFormat.PKCS8:
+ raise ValueError(
+ "DH private keys support only PKCS8 serialization"
+ )
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
+ return self._backend._private_key_bytes(
+ encoding,
+ format,
+ encryption_algorithm,
+ self,
+ self._evp_pkey,
+ self._dh_cdata
+ )
+
+
+@utils.register_interface(dh.DHPublicKeyWithSerialization)
+class _DHPublicKey(object):
+ def __init__(self, backend, dh_cdata, evp_pkey):
+ self._backend = backend
+ self._dh_cdata = dh_cdata
+ self._evp_pkey = evp_pkey
+ self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata)
+
+ @property
+ def key_size(self):
+ return self._key_size_bits
+
+ def public_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ if q[0] == self._backend._ffi.NULL:
+ q_val = None
+ else:
+ q_val = self._backend._bn_to_int(q[0])
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_key(self._dh_cdata,
+ pub_key, self._backend._ffi.NULL)
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ return dh.DHPublicNumbers(
+ parameter_numbers=dh.DHParameterNumbers(
+ p=self._backend._bn_to_int(p[0]),
+ g=self._backend._bn_to_int(g[0]),
+ q=q_val
+ ),
+ y=self._backend._bn_to_int(pub_key[0])
+ )
+
+ def parameters(self):
+ return _dh_cdata_to_parameters(self._dh_cdata, self._backend)
+
+ def public_bytes(self, encoding, format):
+ if format is not serialization.PublicFormat.SubjectPublicKeyInfo:
+ raise ValueError(
+ "DH public keys support only "
+ "SubjectPublicKeyInfo serialization"
+ )
+
+ if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX:
+ q = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DH_get0_pqg(self._dh_cdata,
+ self._backend._ffi.NULL,
+ q,
+ self._backend._ffi.NULL)
+ if q[0] != self._backend._ffi.NULL:
+ raise UnsupportedAlgorithm(
+ "DH X9.42 serialization is not supported",
+ _Reasons.UNSUPPORTED_SERIALIZATION)
+
+ return self._backend._public_key_bytes(
+ encoding,
+ format,
+ self,
+ self._evp_pkey,
+ None
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py
index f84857ff..79142bf6 100644
--- a/src/cryptography/hazmat/backends/openssl/dsa.py
+++ b/src/cryptography/hazmat/backends/openssl/dsa.py
@@ -6,24 +6,42 @@ 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, serialization
+from cryptography.hazmat.backends.openssl.utils import (
+ _calculate_digest_and_algorithm, _check_not_prehashed,
+ _warn_sign_verify_deprecated
+)
+from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, dsa
)
-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.
- """
+def _dsa_sig_sign(backend, private_key, data):
+ sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata)
+ sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len)
+ buflen = backend._ffi.new("unsigned int *")
+
+ # The first parameter passed to DSA_sign is unused by OpenSSL but
+ # must be an integer.
+ res = backend._lib.DSA_sign(
+ 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata
+ )
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(buflen[0])
+
+ return backend._ffi.buffer(sig_buf)[:buflen[0]]
- order_bits = backend._lib.BN_num_bits(dsa_cdata.q)
- return _truncate_digest(digest, order_bits)
+
+def _dsa_sig_verify(backend, public_key, signature, data):
+ # The first parameter passed to DSA_verify is unused by OpenSSL but
+ # must be an integer.
+ res = backend._lib.DSA_verify(
+ 0, data, len(data), signature, len(signature), public_key._dsa_cdata
+ )
+
+ if res != 1:
+ backend._consume_errors()
+ raise InvalidSignature
@utils.register_interface(AsymmetricVerificationContext)
@@ -42,20 +60,10 @@ class _DSAVerificationContext(object):
def verify(self):
data_to_verify = self._hash_ctx.finalize()
- data_to_verify = _truncate_digest_for_dsa(
- self._public_key._dsa_cdata, data_to_verify, self._backend
+ _dsa_sig_verify(
+ self._backend, self._public_key, self._signature, data_to_verify
)
- # 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:
- self._backend._consume_errors()
- raise InvalidSignature
-
@utils.register_interface(AsymmetricSignatureContext)
class _DSASignatureContext(object):
@@ -70,22 +78,7 @@ class _DSASignatureContext(object):
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]]
+ return _dsa_sig_sign(self._backend, self._private_key, data_to_sign)
@utils.register_interface(dsa.DSAParametersWithNumbers)
@@ -95,10 +88,17 @@ class _DSAParameters(object):
self._dsa_cdata = dsa_cdata
def parameter_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
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)
+ p=self._backend._bn_to_int(p[0]),
+ q=self._backend._bn_to_int(q[0]),
+ g=self._backend._bn_to_int(g[0])
)
def generate_private_key(self):
@@ -111,48 +111,71 @@ class _DSAPrivateKey(object):
self._backend = backend
self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
- self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
+
+ p = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_pqg(
+ dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(p[0] != backend._ffi.NULL)
+ self._key_size = self._backend._lib.BN_num_bits(p[0])
key_size = utils.read_only_property("_key_size")
def signer(self, signature_algorithm):
+ _warn_sign_verify_deprecated()
+ _check_not_prehashed(signature_algorithm)
return _DSASignatureContext(self._backend, self, signature_algorithm)
def private_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ priv_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key)
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL)
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)
+ p=self._backend._bn_to_int(p[0]),
+ q=self._backend._bn_to_int(q[0]),
+ g=self._backend._bn_to_int(g[0])
),
- y=self._backend._bn_to_int(self._dsa_cdata.pub_key)
+ y=self._backend._bn_to_int(pub_key[0])
),
- x=self._backend._bn_to_int(self._dsa_cdata.priv_key)
+ x=self._backend._bn_to_int(priv_key[0])
)
def public_key(self):
- dsa_cdata = self._backend._lib.DSA_new()
- assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
+ self._backend.openssl_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)
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_key(
+ self._dsa_cdata, pub_key, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
+ pub_key_dup = self._backend._lib.BN_dup(pub_key[0])
+ res = self._backend._lib.DSA_set0_key(
+ dsa_cdata, pub_key_dup, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata)
return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey)
def parameters(self):
- dsa_cdata = self._backend._lib.DSA_new()
- assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
+ self._backend.openssl_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)
def private_bytes(self, encoding, format, encryption_algorithm):
@@ -160,10 +183,17 @@ class _DSAPrivateKey(object):
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
self._dsa_cdata
)
+ def sign(self, data, algorithm):
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, algorithm
+ )
+ return _dsa_sig_sign(self._backend, self, data)
+
@utils.register_interface(dsa.DSAPublicKeyWithSerialization)
class _DSAPublicKey(object):
@@ -171,45 +201,64 @@ class _DSAPublicKey(object):
self._backend = backend
self._dsa_cdata = dsa_cdata
self._evp_pkey = evp_pkey
- self._key_size = self._backend._lib.BN_num_bits(self._dsa_cdata.p)
+ p = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_pqg(
+ dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(p[0] != backend._ffi.NULL)
+ self._key_size = self._backend._lib.BN_num_bits(p[0])
key_size = utils.read_only_property("_key_size")
def verifier(self, signature, signature_algorithm):
+ _warn_sign_verify_deprecated()
+ utils._check_bytes("signature", signature)
+
+ _check_not_prehashed(signature_algorithm)
return _DSAVerificationContext(
self._backend, self, signature, signature_algorithm
)
def public_numbers(self):
+ p = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ g = self._backend._ffi.new("BIGNUM **")
+ pub_key = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(g[0] != self._backend._ffi.NULL)
+ self._backend._lib.DSA_get0_key(
+ self._dsa_cdata, pub_key, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL)
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)
+ p=self._backend._bn_to_int(p[0]),
+ q=self._backend._bn_to_int(q[0]),
+ g=self._backend._bn_to_int(g[0])
),
- y=self._backend._bn_to_int(self._dsa_cdata.pub_key)
+ y=self._backend._bn_to_int(pub_key[0])
)
def parameters(self):
- dsa_cdata = self._backend._lib.DSA_new()
- assert dsa_cdata != self._backend._ffi.NULL
+ dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
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)
def public_bytes(self, encoding, format):
- if format is serialization.PublicFormat.PKCS1:
- raise ValueError(
- "DSA public keys do not support PKCS1 serialization"
- )
-
return self._backend._public_key_bytes(
encoding,
format,
+ self,
self._evp_pkey,
None
)
+
+ def verify(self, signature, data, algorithm):
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, algorithm
+ )
+ return _dsa_sig_verify(self._backend, self, signature, data)
diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py
index 7d3afb94..e70a3410 100644
--- a/src/cryptography/hazmat/backends/openssl/ec.py
+++ b/src/cryptography/hazmat/backends/openssl/ec.py
@@ -8,53 +8,50 @@ from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
-from cryptography.hazmat.backends.openssl.utils import _truncate_digest
+from cryptography.hazmat.backends.openssl.utils import (
+ _calculate_digest_and_algorithm, _check_not_prehashed,
+ _warn_sign_verify_deprecated
+)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, 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 _check_signature_algorithm(signature_algorithm):
+ if not isinstance(signature_algorithm, ec.ECDSA):
+ raise UnsupportedAlgorithm(
+ "Unsupported elliptic curve signature algorithm.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def _ec_key_curve_sn(backend, ec_key):
group = backend._lib.EC_KEY_get0_group(ec_key)
- assert group != backend._ffi.NULL
+ backend.openssl_assert(group != backend._ffi.NULL)
nid = backend._lib.EC_GROUP_get_curve_name(group)
# The following check is to find EC keys with unnamed curves and raise
# an error for now.
if nid == backend._lib.NID_undef:
raise NotImplementedError(
- "ECDSA certificates with unnamed curves are unsupported "
+ "ECDSA keys with unnamed curves are unsupported "
+ "at this time"
+ )
+
+ # This is like the above check, but it also catches the case where you
+ # explicitly encoded a curve with the same parameters as a named curve.
+ # Don't do that.
+ if (
+ backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER and
+ backend._lib.EC_GROUP_get_asn1_flag(group) == 0
+ ):
+ raise NotImplementedError(
+ "ECDSA keys with unnamed curves are unsupported "
"at this time"
)
curve_name = backend._lib.OBJ_nid2sn(nid)
- assert curve_name != backend._ffi.NULL
+ backend.openssl_assert(curve_name != backend._ffi.NULL)
sn = backend._ffi.string(curve_name).decode('ascii')
return sn
@@ -77,11 +74,33 @@ def _sn_to_elliptic_curve(backend, sn):
return ec._CURVE_TYPES[sn]()
except KeyError:
raise UnsupportedAlgorithm(
- "{0} is not a supported elliptic curve".format(sn),
+ "{} is not a supported elliptic curve".format(sn),
_Reasons.UNSUPPORTED_ELLIPTIC_CURVE
)
+def _ecdsa_sig_sign(backend, private_key, data):
+ max_size = backend._lib.ECDSA_size(private_key._ec_key)
+ backend.openssl_assert(max_size > 0)
+
+ sigbuf = backend._ffi.new("unsigned char[]", max_size)
+ siglen_ptr = backend._ffi.new("unsigned int[]", 1)
+ res = backend._lib.ECDSA_sign(
+ 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key
+ )
+ backend.openssl_assert(res == 1)
+ return backend._ffi.buffer(sigbuf)[:siglen_ptr[0]]
+
+
+def _ecdsa_sig_verify(backend, public_key, signature, data):
+ res = backend._lib.ECDSA_verify(
+ 0, data, len(data), signature, len(signature), public_key._ec_key
+ )
+ if res != 1:
+ backend._consume_errors()
+ raise InvalidSignature
+
+
@utils.register_interface(AsymmetricSignatureContext)
class _ECDSASignatureContext(object):
def __init__(self, backend, private_key, algorithm):
@@ -93,27 +112,9 @@ class _ECDSASignatureContext(object):
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]]
+ return _ecdsa_sig_sign(self._backend, self._private_key, digest)
@utils.register_interface(AsymmetricVerificationContext)
@@ -128,66 +129,84 @@ class _ECDSAVerificationContext(object):
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
+ _ecdsa_sig_verify(
+ self._backend, self._public_key, self._signature, digest
)
- if res != 1:
- self._backend._consume_errors()
- raise InvalidSignature
- return True
@utils.register_interface(ec.EllipticCurvePrivateKeyWithSerialization)
class _EllipticCurvePrivateKey(object):
def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend
- _mark_asn1_named_ec_curve(backend, ec_key_cdata)
self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn)
+ _mark_asn1_named_ec_curve(backend, ec_key_cdata)
curve = utils.read_only_property("_curve")
+ @property
+ def key_size(self):
+ return self.curve.key_size
+
def signer(self, signature_algorithm):
- if isinstance(signature_algorithm, ec.ECDSA):
- return _ECDSASignatureContext(
- self._backend, self, signature_algorithm.algorithm
+ _warn_sign_verify_deprecated()
+ _check_signature_algorithm(signature_algorithm)
+ _check_not_prehashed(signature_algorithm.algorithm)
+ return _ECDSASignatureContext(
+ self._backend, self, signature_algorithm.algorithm
+ )
+
+ def exchange(self, algorithm, peer_public_key):
+ if not (
+ self._backend.elliptic_curve_exchange_algorithm_supported(
+ algorithm, self.curve
)
- else:
+ ):
raise UnsupportedAlgorithm(
- "Unsupported elliptic curve signature algorithm.",
- _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+ "This backend does not support the ECDH algorithm.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ if peer_public_key.curve.name != self.curve.name:
+ raise ValueError(
+ "peer_public_key and self are not on the same curve"
+ )
+
+ group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
+ z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8
+ self._backend.openssl_assert(z_len > 0)
+ z_buf = self._backend._ffi.new("uint8_t[]", z_len)
+ peer_key = self._backend._lib.EC_KEY_get0_public_key(
+ peer_public_key._ec_key
+ )
+
+ r = self._backend._lib.ECDH_compute_key(
+ z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(r > 0)
+ return self._backend._ffi.buffer(z_buf)[:z_len]
def public_key(self):
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
- assert group != self._backend._ffi.NULL
+ self._backend.openssl_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
+ self._backend.openssl_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
+ self._backend.openssl_assert(point != self._backend._ffi.NULL)
res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
- assert res == 1
+ self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key)
@@ -206,47 +225,59 @@ class _EllipticCurvePrivateKey(object):
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
self._ec_key
)
+ def sign(self, data, signature_algorithm):
+ _check_signature_algorithm(signature_algorithm)
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, signature_algorithm._algorithm
+ )
+ return _ecdsa_sig_sign(self._backend, self, data)
+
@utils.register_interface(ec.EllipticCurvePublicKeyWithSerialization)
class _EllipticCurvePublicKey(object):
def __init__(self, backend, ec_key_cdata, evp_pkey):
self._backend = backend
- _mark_asn1_named_ec_curve(backend, ec_key_cdata)
self._ec_key = ec_key_cdata
self._evp_pkey = evp_pkey
sn = _ec_key_curve_sn(backend, ec_key_cdata)
self._curve = _sn_to_elliptic_curve(backend, sn)
+ _mark_asn1_named_ec_curve(backend, ec_key_cdata)
curve = utils.read_only_property("_curve")
+ @property
+ def key_size(self):
+ return self.curve.key_size
+
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)
+ _warn_sign_verify_deprecated()
+ utils._check_bytes("signature", signature)
+
+ _check_signature_algorithm(signature_algorithm)
+ _check_not_prehashed(signature_algorithm.algorithm)
+ return _ECDSAVerificationContext(
+ self._backend, self, signature, signature_algorithm.algorithm
+ )
def public_numbers(self):
- set_func, get_func, group = (
- self._backend._ec_key_determine_group_get_set_funcs(self._ec_key)
+ get_func, group = (
+ self._backend._ec_key_determine_group_get_func(self._ec_key)
)
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
- assert point != self._backend._ffi.NULL
+ self._backend.openssl_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
+ self._backend.openssl_assert(res == 1)
x = self._backend._bn_to_int(bn_x)
y = self._backend._bn_to_int(bn_y)
@@ -257,15 +288,62 @@ class _EllipticCurvePublicKey(object):
curve=self._curve
)
+ def _encode_point(self, format):
+ if format is serialization.PublicFormat.CompressedPoint:
+ conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED
+ else:
+ assert format is serialization.PublicFormat.UncompressedPoint
+ conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED
+
+ group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
+ self._backend.openssl_assert(group != self._backend._ffi.NULL)
+ point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
+ self._backend.openssl_assert(point != self._backend._ffi.NULL)
+ with self._backend._tmp_bn_ctx() as bn_ctx:
+ buflen = self._backend._lib.EC_POINT_point2oct(
+ group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx
+ )
+ self._backend.openssl_assert(buflen > 0)
+ buf = self._backend._ffi.new("char[]", buflen)
+ res = self._backend._lib.EC_POINT_point2oct(
+ group, point, conversion, buf, buflen, bn_ctx
+ )
+ self._backend.openssl_assert(buflen == res)
+
+ return self._backend._ffi.buffer(buf)[:]
+
def public_bytes(self, encoding, format):
- if format is serialization.PublicFormat.PKCS1:
- raise ValueError(
- "EC public keys do not support PKCS1 serialization"
+
+ if (
+ encoding is serialization.Encoding.X962 or
+ format is serialization.PublicFormat.CompressedPoint or
+ format is serialization.PublicFormat.UncompressedPoint
+ ):
+ if (
+ encoding is not serialization.Encoding.X962 or
+ format not in (
+ serialization.PublicFormat.CompressedPoint,
+ serialization.PublicFormat.UncompressedPoint
+ )
+ ):
+ raise ValueError(
+ "X962 encoding must be used with CompressedPoint or "
+ "UncompressedPoint format"
+ )
+
+ return self._encode_point(format)
+ else:
+ return self._backend._public_key_bytes(
+ encoding,
+ format,
+ self,
+ self._evp_pkey,
+ None
)
- return self._backend._public_key_bytes(
- encoding,
- format,
- self._evp_pkey,
- None
+ def verify(self, signature, data, signature_algorithm):
+ _check_signature_algorithm(signature_algorithm)
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, signature_algorithm._algorithm
)
+ _ecdsa_sig_verify(self._backend, self, signature, data)
diff --git a/src/cryptography/hazmat/backends/openssl/ed25519.py b/src/cryptography/hazmat/backends/openssl/ed25519.py
new file mode 100644
index 00000000..1632ec37
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/ed25519.py
@@ -0,0 +1,134 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import exceptions, utils
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.ed25519 import (
+ Ed25519PrivateKey, Ed25519PublicKey, _ED25519_KEY_SIZE, _ED25519_SIG_SIZE
+)
+
+
+@utils.register_interface(Ed25519PublicKey)
+class _Ed25519PublicKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_bytes(self, encoding, format):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ encoding is not serialization.Encoding.Raw or
+ format is not serialization.PublicFormat.Raw
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw"
+ )
+
+ return self._raw_public_bytes()
+
+ return self._backend._public_key_bytes(
+ encoding, format, self, self._evp_pkey, None
+ )
+
+ def _raw_public_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:]
+
+ def verify(self, signature, data):
+ evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
+ evp_md_ctx = self._backend._ffi.gc(
+ evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ res = self._backend._lib.EVP_DigestVerifyInit(
+ evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
+ self._backend._ffi.NULL, self._evp_pkey
+ )
+ self._backend.openssl_assert(res == 1)
+ res = self._backend._lib.EVP_DigestVerify(
+ evp_md_ctx, signature, len(signature), data, len(data)
+ )
+ if res != 1:
+ self._backend._consume_errors()
+ raise exceptions.InvalidSignature
+
+
+@utils.register_interface(Ed25519PrivateKey)
+class _Ed25519PrivateKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_key(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
+ public_bytes = self._backend._ffi.buffer(buf)[:]
+ return self._backend.ed25519_load_public_bytes(public_bytes)
+
+ def sign(self, data):
+ evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
+ evp_md_ctx = self._backend._ffi.gc(
+ evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ res = self._backend._lib.EVP_DigestSignInit(
+ evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
+ self._backend._ffi.NULL, self._evp_pkey
+ )
+ self._backend.openssl_assert(res == 1)
+ buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE)
+ buflen = self._backend._ffi.new("size_t *", len(buf))
+ res = self._backend._lib.EVP_DigestSign(
+ evp_md_ctx, buf, buflen, data, len(data)
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE)
+ return self._backend._ffi.buffer(buf, buflen[0])[:]
+
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ format is not serialization.PrivateFormat.Raw or
+ encoding is not serialization.Encoding.Raw or not
+ isinstance(encryption_algorithm, serialization.NoEncryption)
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw "
+ "and encryption_algorithm must be NoEncryption()"
+ )
+
+ return self._raw_private_bytes()
+
+ return self._backend._private_key_bytes(
+ encoding, format, encryption_algorithm, self, self._evp_pkey, None
+ )
+
+ def _raw_private_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_private_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:]
diff --git a/src/cryptography/hazmat/backends/openssl/ed448.py b/src/cryptography/hazmat/backends/openssl/ed448.py
new file mode 100644
index 00000000..4845a1f2
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/ed448.py
@@ -0,0 +1,137 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import exceptions, utils
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.ed448 import (
+ Ed448PrivateKey, Ed448PublicKey
+)
+
+_ED448_KEY_SIZE = 57
+_ED448_SIG_SIZE = 114
+
+
+@utils.register_interface(Ed448PublicKey)
+class _Ed448PublicKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_bytes(self, encoding, format):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ encoding is not serialization.Encoding.Raw or
+ format is not serialization.PublicFormat.Raw
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw"
+ )
+
+ return self._raw_public_bytes()
+
+ return self._backend._public_key_bytes(
+ encoding, format, self, self._evp_pkey, None
+ )
+
+ def _raw_public_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
+
+ def verify(self, signature, data):
+ evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
+ evp_md_ctx = self._backend._ffi.gc(
+ evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ res = self._backend._lib.EVP_DigestVerifyInit(
+ evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
+ self._backend._ffi.NULL, self._evp_pkey
+ )
+ self._backend.openssl_assert(res == 1)
+ res = self._backend._lib.EVP_DigestVerify(
+ evp_md_ctx, signature, len(signature), data, len(data)
+ )
+ if res != 1:
+ self._backend._consume_errors()
+ raise exceptions.InvalidSignature
+
+
+@utils.register_interface(Ed448PrivateKey)
+class _Ed448PrivateKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_key(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
+ public_bytes = self._backend._ffi.buffer(buf)[:]
+ return self._backend.ed448_load_public_bytes(public_bytes)
+
+ def sign(self, data):
+ evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL)
+ evp_md_ctx = self._backend._ffi.gc(
+ evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ res = self._backend._lib.EVP_DigestSignInit(
+ evp_md_ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
+ self._backend._ffi.NULL, self._evp_pkey
+ )
+ self._backend.openssl_assert(res == 1)
+ buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE)
+ buflen = self._backend._ffi.new("size_t *", len(buf))
+ res = self._backend._lib.EVP_DigestSign(
+ evp_md_ctx, buf, buflen, data, len(data)
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE)
+ return self._backend._ffi.buffer(buf, buflen[0])[:]
+
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ format is not serialization.PrivateFormat.Raw or
+ encoding is not serialization.Encoding.Raw or not
+ isinstance(encryption_algorithm, serialization.NoEncryption)
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw "
+ "and encryption_algorithm must be NoEncryption()"
+ )
+
+ return self._raw_private_bytes()
+
+ return self._backend._private_key_bytes(
+ encoding, format, encryption_algorithm, self, self._evp_pkey, None
+ )
+
+ def _raw_private_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_private_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:]
diff --git a/src/cryptography/hazmat/backends/openssl/encode_asn1.py b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
new file mode 100644
index 00000000..ca35f0e7
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/encode_asn1.py
@@ -0,0 +1,660 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import calendar
+import ipaddress
+
+import six
+
+from cryptography import utils, x509
+from cryptography.hazmat.backends.openssl.decode_asn1 import (
+ _CRL_ENTRY_REASON_ENUM_TO_CODE, _DISTPOINT_TYPE_FULLNAME,
+ _DISTPOINT_TYPE_RELATIVENAME
+)
+from cryptography.x509.name import _ASN1Type
+from cryptography.x509.oid import (
+ CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID,
+)
+
+
+def _encode_asn1_int(backend, x):
+ """
+ Converts a python integer to an ASN1_INTEGER. The returned ASN1_INTEGER
+ 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.
+
+ """
+ # Convert Python integer to OpenSSL "bignum" in case value exceeds
+ # machine's native integer limits (note: `int_to_bn` doesn't automatically
+ # GC).
+ i = backend._int_to_bn(x)
+ i = backend._ffi.gc(i, backend._lib.BN_free)
+
+ # Wrap in an ASN.1 integer. Don't GC -- as documented.
+ i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL)
+ backend.openssl_assert(i != backend._ffi.NULL)
+ return i
+
+
+def _encode_asn1_int_gc(backend, x):
+ i = _encode_asn1_int(backend, x)
+ i = backend._ffi.gc(i, backend._lib.ASN1_INTEGER_free)
+ return i
+
+
+def _encode_asn1_str(backend, data):
+ """
+ Create an ASN1_OCTET_STRING from a Python byte string.
+ """
+ s = backend._lib.ASN1_OCTET_STRING_new()
+ res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data))
+ backend.openssl_assert(res == 1)
+ return s
+
+
+def _encode_asn1_utf8_str(backend, string):
+ """
+ Create an ASN1_UTF8STRING from a Python unicode string.
+ This object will be an ASN1_STRING with UTF8 type in OpenSSL and
+ can be decoded with ASN1_STRING_to_UTF8.
+ """
+ s = backend._lib.ASN1_UTF8STRING_new()
+ res = backend._lib.ASN1_STRING_set(
+ s, string.encode("utf8"), len(string.encode("utf8"))
+ )
+ backend.openssl_assert(res == 1)
+ return s
+
+
+def _encode_asn1_str_gc(backend, data):
+ s = _encode_asn1_str(backend, data)
+ s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free)
+ return s
+
+
+def _encode_inhibit_any_policy(backend, inhibit_any_policy):
+ return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs)
+
+
+def _encode_name(backend, name):
+ """
+ The X509_NAME created will not be gc'd. Use _encode_name_gc if needed.
+ """
+ subject = backend._lib.X509_NAME_new()
+ for rdn in name.rdns:
+ set_flag = 0 # indicate whether to add to last RDN or create new RDN
+ for attribute in rdn:
+ name_entry = _encode_name_entry(backend, attribute)
+ # X509_NAME_add_entry dups the object so we need to gc this copy
+ name_entry = backend._ffi.gc(
+ name_entry, backend._lib.X509_NAME_ENTRY_free
+ )
+ res = backend._lib.X509_NAME_add_entry(
+ subject, name_entry, -1, set_flag)
+ backend.openssl_assert(res == 1)
+ set_flag = -1
+ return subject
+
+
+def _encode_name_gc(backend, attributes):
+ subject = _encode_name(backend, attributes)
+ subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free)
+ return subject
+
+
+def _encode_sk_name_entry(backend, attributes):
+ """
+ The sk_X509_NAME_ENTRY created will not be gc'd.
+ """
+ stack = backend._lib.sk_X509_NAME_ENTRY_new_null()
+ for attribute in attributes:
+ name_entry = _encode_name_entry(backend, attribute)
+ res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry)
+ backend.openssl_assert(res >= 1)
+ return stack
+
+
+def _encode_name_entry(backend, attribute):
+ if attribute._type is _ASN1Type.BMPString:
+ value = attribute.value.encode('utf_16_be')
+ elif attribute._type is _ASN1Type.UniversalString:
+ value = attribute.value.encode('utf_32_be')
+ else:
+ value = attribute.value.encode('utf8')
+
+ obj = _txt2obj_gc(backend, attribute.oid.dotted_string)
+
+ name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ(
+ backend._ffi.NULL, obj, attribute._type.value, value, len(value)
+ )
+ return name_entry
+
+
+def _encode_crl_number_delta_crl_indicator(backend, ext):
+ return _encode_asn1_int_gc(backend, ext.crl_number)
+
+
+def _encode_issuing_dist_point(backend, ext):
+ idp = backend._lib.ISSUING_DIST_POINT_new()
+ backend.openssl_assert(idp != backend._ffi.NULL)
+ idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free)
+ idp.onlyuser = 255 if ext.only_contains_user_certs else 0
+ idp.onlyCA = 255 if ext.only_contains_ca_certs else 0
+ idp.indirectCRL = 255 if ext.indirect_crl else 0
+ idp.onlyattr = 255 if ext.only_contains_attribute_certs else 0
+ if ext.only_some_reasons:
+ idp.onlysomereasons = _encode_reasonflags(
+ backend, ext.only_some_reasons
+ )
+
+ if ext.full_name:
+ idp.distpoint = _encode_full_name(backend, ext.full_name)
+
+ if ext.relative_name:
+ idp.distpoint = _encode_relative_name(backend, ext.relative_name)
+
+ return idp
+
+
+def _encode_crl_reason(backend, crl_reason):
+ asn1enum = backend._lib.ASN1_ENUMERATED_new()
+ backend.openssl_assert(asn1enum != backend._ffi.NULL)
+ asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free)
+ res = backend._lib.ASN1_ENUMERATED_set(
+ asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason]
+ )
+ backend.openssl_assert(res == 1)
+
+ return asn1enum
+
+
+def _encode_invalidity_date(backend, invalidity_date):
+ time = backend._lib.ASN1_GENERALIZEDTIME_set(
+ backend._ffi.NULL, calendar.timegm(
+ invalidity_date.invalidity_date.timetuple()
+ )
+ )
+ backend.openssl_assert(time != backend._ffi.NULL)
+ time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free)
+
+ return time
+
+
+def _encode_certificate_policies(backend, certificate_policies):
+ cp = backend._lib.sk_POLICYINFO_new_null()
+ backend.openssl_assert(cp != backend._ffi.NULL)
+ cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
+ for policy_info in certificate_policies:
+ pi = backend._lib.POLICYINFO_new()
+ backend.openssl_assert(pi != backend._ffi.NULL)
+ res = backend._lib.sk_POLICYINFO_push(cp, pi)
+ backend.openssl_assert(res >= 1)
+ oid = _txt2obj(backend, policy_info.policy_identifier.dotted_string)
+ pi.policyid = oid
+ if policy_info.policy_qualifiers:
+ pqis = backend._lib.sk_POLICYQUALINFO_new_null()
+ backend.openssl_assert(pqis != backend._ffi.NULL)
+ for qualifier in policy_info.policy_qualifiers:
+ pqi = backend._lib.POLICYQUALINFO_new()
+ backend.openssl_assert(pqi != backend._ffi.NULL)
+ res = backend._lib.sk_POLICYQUALINFO_push(pqis, pqi)
+ backend.openssl_assert(res >= 1)
+ if isinstance(qualifier, six.text_type):
+ pqi.pqualid = _txt2obj(
+ backend, x509.OID_CPS_QUALIFIER.dotted_string
+ )
+ pqi.d.cpsuri = _encode_asn1_str(
+ backend,
+ qualifier.encode("ascii"),
+ )
+ else:
+ assert isinstance(qualifier, x509.UserNotice)
+ pqi.pqualid = _txt2obj(
+ backend, x509.OID_CPS_USER_NOTICE.dotted_string
+ )
+ un = backend._lib.USERNOTICE_new()
+ backend.openssl_assert(un != backend._ffi.NULL)
+ pqi.d.usernotice = un
+ if qualifier.explicit_text:
+ un.exptext = _encode_asn1_utf8_str(
+ backend, qualifier.explicit_text
+ )
+
+ un.noticeref = _encode_notice_reference(
+ backend, qualifier.notice_reference
+ )
+
+ pi.qualifiers = pqis
+
+ return cp
+
+
+def _encode_notice_reference(backend, notice):
+ if notice is None:
+ return backend._ffi.NULL
+ else:
+ nr = backend._lib.NOTICEREF_new()
+ backend.openssl_assert(nr != backend._ffi.NULL)
+ # organization is a required field
+ nr.organization = _encode_asn1_utf8_str(backend, notice.organization)
+
+ notice_stack = backend._lib.sk_ASN1_INTEGER_new_null()
+ nr.noticenos = notice_stack
+ for number in notice.notice_numbers:
+ num = _encode_asn1_int(backend, number)
+ res = backend._lib.sk_ASN1_INTEGER_push(notice_stack, num)
+ backend.openssl_assert(res >= 1)
+
+ return nr
+
+
+def _txt2obj(backend, name):
+ """
+ Converts a Python string with an ASN.1 object ID in dotted form to a
+ ASN1_OBJECT.
+ """
+ name = name.encode('ascii')
+ obj = backend._lib.OBJ_txt2obj(name, 1)
+ backend.openssl_assert(obj != backend._ffi.NULL)
+ return obj
+
+
+def _txt2obj_gc(backend, name):
+ obj = _txt2obj(backend, name)
+ obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free)
+ return obj
+
+
+def _encode_ocsp_nocheck(backend, ext):
+ # Doesn't need to be GC'd
+ return backend._lib.ASN1_NULL_new()
+
+
+def _encode_key_usage(backend, key_usage):
+ set_bit = backend._lib.ASN1_BIT_STRING_set_bit
+ ku = backend._lib.ASN1_BIT_STRING_new()
+ ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free)
+ res = set_bit(ku, 0, key_usage.digital_signature)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 1, key_usage.content_commitment)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 2, key_usage.key_encipherment)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 3, key_usage.data_encipherment)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 4, key_usage.key_agreement)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 5, key_usage.key_cert_sign)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 6, key_usage.crl_sign)
+ backend.openssl_assert(res == 1)
+ if key_usage.key_agreement:
+ res = set_bit(ku, 7, key_usage.encipher_only)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 8, key_usage.decipher_only)
+ backend.openssl_assert(res == 1)
+ else:
+ res = set_bit(ku, 7, 0)
+ backend.openssl_assert(res == 1)
+ res = set_bit(ku, 8, 0)
+ backend.openssl_assert(res == 1)
+
+ return ku
+
+
+def _encode_authority_key_identifier(backend, authority_keyid):
+ akid = backend._lib.AUTHORITY_KEYID_new()
+ backend.openssl_assert(akid != backend._ffi.NULL)
+ akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free)
+ if authority_keyid.key_identifier is not None:
+ akid.keyid = _encode_asn1_str(
+ backend,
+ authority_keyid.key_identifier,
+ )
+
+ if authority_keyid.authority_cert_issuer is not None:
+ akid.issuer = _encode_general_names(
+ backend, authority_keyid.authority_cert_issuer
+ )
+
+ if authority_keyid.authority_cert_serial_number is not None:
+ akid.serial = _encode_asn1_int(
+ backend, authority_keyid.authority_cert_serial_number
+ )
+
+ return akid
+
+
+def _encode_basic_constraints(backend, basic_constraints):
+ constraints = backend._lib.BASIC_CONSTRAINTS_new()
+ constraints = backend._ffi.gc(
+ constraints, backend._lib.BASIC_CONSTRAINTS_free
+ )
+ constraints.ca = 255 if basic_constraints.ca else 0
+ if basic_constraints.ca and basic_constraints.path_length is not None:
+ constraints.pathlen = _encode_asn1_int(
+ backend, basic_constraints.path_length
+ )
+
+ return constraints
+
+
+def _encode_authority_information_access(backend, authority_info_access):
+ aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
+ backend.openssl_assert(aia != backend._ffi.NULL)
+ aia = backend._ffi.gc(
+ aia,
+ lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free(
+ x, backend._ffi.addressof(
+ backend._lib._original_lib, "ACCESS_DESCRIPTION_free"
+ )
+ )
+ )
+ for access_description in authority_info_access:
+ ad = backend._lib.ACCESS_DESCRIPTION_new()
+ method = _txt2obj(
+ backend, access_description.access_method.dotted_string
+ )
+ _encode_general_name_preallocated(
+ backend, access_description.access_location, ad.location
+ )
+ ad.method = method
+ res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
+ backend.openssl_assert(res >= 1)
+
+ return aia
+
+
+def _encode_general_names(backend, names):
+ general_names = backend._lib.GENERAL_NAMES_new()
+ backend.openssl_assert(general_names != backend._ffi.NULL)
+ for name in names:
+ gn = _encode_general_name(backend, name)
+ res = backend._lib.sk_GENERAL_NAME_push(general_names, gn)
+ backend.openssl_assert(res != 0)
+
+ return general_names
+
+
+def _encode_alt_name(backend, san):
+ general_names = _encode_general_names(backend, san)
+ general_names = backend._ffi.gc(
+ general_names, backend._lib.GENERAL_NAMES_free
+ )
+ return general_names
+
+
+def _encode_subject_key_identifier(backend, ski):
+ return _encode_asn1_str_gc(backend, ski.digest)
+
+
+def _encode_general_name(backend, name):
+ gn = backend._lib.GENERAL_NAME_new()
+ _encode_general_name_preallocated(backend, name, gn)
+ return gn
+
+
+def _encode_general_name_preallocated(backend, name, gn):
+ if isinstance(name, x509.DNSName):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ gn.type = backend._lib.GEN_DNS
+
+ ia5 = backend._lib.ASN1_IA5STRING_new()
+ backend.openssl_assert(ia5 != backend._ffi.NULL)
+ # ia5strings are supposed to be ITU T.50 but to allow round-tripping
+ # of broken certs that encode utf8 we'll encode utf8 here too.
+ value = name.value.encode("utf8")
+
+ res = backend._lib.ASN1_STRING_set(ia5, value, len(value))
+ backend.openssl_assert(res == 1)
+ gn.d.dNSName = ia5
+ elif isinstance(name, x509.RegisteredID):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ gn.type = backend._lib.GEN_RID
+ obj = backend._lib.OBJ_txt2obj(
+ name.value.dotted_string.encode('ascii'), 1
+ )
+ backend.openssl_assert(obj != backend._ffi.NULL)
+ gn.d.registeredID = obj
+ elif isinstance(name, x509.DirectoryName):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ dir_name = _encode_name(backend, name.value)
+ gn.type = backend._lib.GEN_DIRNAME
+ gn.d.directoryName = dir_name
+ elif isinstance(name, x509.IPAddress):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ if isinstance(name.value, ipaddress.IPv4Network):
+ packed = (
+ name.value.network_address.packed +
+ utils.int_to_bytes(((1 << 32) - name.value.num_addresses), 4)
+ )
+ elif isinstance(name.value, ipaddress.IPv6Network):
+ packed = (
+ name.value.network_address.packed +
+ utils.int_to_bytes((1 << 128) - name.value.num_addresses, 16)
+ )
+ else:
+ packed = name.value.packed
+ ipaddr = _encode_asn1_str(backend, packed)
+ gn.type = backend._lib.GEN_IPADD
+ gn.d.iPAddress = ipaddr
+ elif isinstance(name, x509.OtherName):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ other_name = backend._lib.OTHERNAME_new()
+ backend.openssl_assert(other_name != backend._ffi.NULL)
+
+ type_id = backend._lib.OBJ_txt2obj(
+ name.type_id.dotted_string.encode('ascii'), 1
+ )
+ backend.openssl_assert(type_id != backend._ffi.NULL)
+ data = backend._ffi.new("unsigned char[]", name.value)
+ data_ptr_ptr = backend._ffi.new("unsigned char **")
+ data_ptr_ptr[0] = data
+ value = backend._lib.d2i_ASN1_TYPE(
+ backend._ffi.NULL, data_ptr_ptr, len(name.value)
+ )
+ if value == backend._ffi.NULL:
+ backend._consume_errors()
+ raise ValueError("Invalid ASN.1 data")
+ other_name.type_id = type_id
+ other_name.value = value
+ gn.type = backend._lib.GEN_OTHERNAME
+ gn.d.otherName = other_name
+ elif isinstance(name, x509.RFC822Name):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ # ia5strings are supposed to be ITU T.50 but to allow round-tripping
+ # of broken certs that encode utf8 we'll encode utf8 here too.
+ data = name.value.encode("utf8")
+ asn1_str = _encode_asn1_str(backend, data)
+ gn.type = backend._lib.GEN_EMAIL
+ gn.d.rfc822Name = asn1_str
+ elif isinstance(name, x509.UniformResourceIdentifier):
+ backend.openssl_assert(gn != backend._ffi.NULL)
+ # ia5strings are supposed to be ITU T.50 but to allow round-tripping
+ # of broken certs that encode utf8 we'll encode utf8 here too.
+ data = name.value.encode("utf8")
+ asn1_str = _encode_asn1_str(backend, data)
+ gn.type = backend._lib.GEN_URI
+ gn.d.uniformResourceIdentifier = asn1_str
+ else:
+ raise ValueError(
+ "{} is an unknown GeneralName type".format(name)
+ )
+
+
+def _encode_extended_key_usage(backend, extended_key_usage):
+ eku = backend._lib.sk_ASN1_OBJECT_new_null()
+ eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free)
+ for oid in extended_key_usage:
+ obj = _txt2obj(backend, oid.dotted_string)
+ res = backend._lib.sk_ASN1_OBJECT_push(eku, obj)
+ backend.openssl_assert(res >= 1)
+
+ return eku
+
+
+_CRLREASONFLAGS = {
+ x509.ReasonFlags.key_compromise: 1,
+ x509.ReasonFlags.ca_compromise: 2,
+ x509.ReasonFlags.affiliation_changed: 3,
+ x509.ReasonFlags.superseded: 4,
+ x509.ReasonFlags.cessation_of_operation: 5,
+ x509.ReasonFlags.certificate_hold: 6,
+ x509.ReasonFlags.privilege_withdrawn: 7,
+ x509.ReasonFlags.aa_compromise: 8,
+}
+
+
+def _encode_reasonflags(backend, reasons):
+ bitmask = backend._lib.ASN1_BIT_STRING_new()
+ backend.openssl_assert(bitmask != backend._ffi.NULL)
+ for reason in reasons:
+ res = backend._lib.ASN1_BIT_STRING_set_bit(
+ bitmask, _CRLREASONFLAGS[reason], 1
+ )
+ backend.openssl_assert(res == 1)
+
+ return bitmask
+
+
+def _encode_full_name(backend, full_name):
+ dpn = backend._lib.DIST_POINT_NAME_new()
+ backend.openssl_assert(dpn != backend._ffi.NULL)
+ dpn.type = _DISTPOINT_TYPE_FULLNAME
+ dpn.name.fullname = _encode_general_names(backend, full_name)
+ return dpn
+
+
+def _encode_relative_name(backend, relative_name):
+ dpn = backend._lib.DIST_POINT_NAME_new()
+ backend.openssl_assert(dpn != backend._ffi.NULL)
+ dpn.type = _DISTPOINT_TYPE_RELATIVENAME
+ dpn.name.relativename = _encode_sk_name_entry(backend, relative_name)
+ return dpn
+
+
+def _encode_cdps_freshest_crl(backend, cdps):
+ cdp = backend._lib.sk_DIST_POINT_new_null()
+ cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free)
+ for point in cdps:
+ dp = backend._lib.DIST_POINT_new()
+ backend.openssl_assert(dp != backend._ffi.NULL)
+
+ if point.reasons:
+ dp.reasons = _encode_reasonflags(backend, point.reasons)
+
+ if point.full_name:
+ dp.distpoint = _encode_full_name(backend, point.full_name)
+
+ if point.relative_name:
+ dp.distpoint = _encode_relative_name(backend, point.relative_name)
+
+ if point.crl_issuer:
+ dp.CRLissuer = _encode_general_names(backend, point.crl_issuer)
+
+ res = backend._lib.sk_DIST_POINT_push(cdp, dp)
+ backend.openssl_assert(res >= 1)
+
+ return cdp
+
+
+def _encode_name_constraints(backend, name_constraints):
+ nc = backend._lib.NAME_CONSTRAINTS_new()
+ backend.openssl_assert(nc != backend._ffi.NULL)
+ nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free)
+ permitted = _encode_general_subtree(
+ backend, name_constraints.permitted_subtrees
+ )
+ nc.permittedSubtrees = permitted
+ excluded = _encode_general_subtree(
+ backend, name_constraints.excluded_subtrees
+ )
+ nc.excludedSubtrees = excluded
+
+ return nc
+
+
+def _encode_policy_constraints(backend, policy_constraints):
+ pc = backend._lib.POLICY_CONSTRAINTS_new()
+ backend.openssl_assert(pc != backend._ffi.NULL)
+ pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free)
+ if policy_constraints.require_explicit_policy is not None:
+ pc.requireExplicitPolicy = _encode_asn1_int(
+ backend, policy_constraints.require_explicit_policy
+ )
+
+ if policy_constraints.inhibit_policy_mapping is not None:
+ pc.inhibitPolicyMapping = _encode_asn1_int(
+ backend, policy_constraints.inhibit_policy_mapping
+ )
+
+ return pc
+
+
+def _encode_general_subtree(backend, subtrees):
+ if subtrees is None:
+ return backend._ffi.NULL
+ else:
+ general_subtrees = backend._lib.sk_GENERAL_SUBTREE_new_null()
+ for name in subtrees:
+ gs = backend._lib.GENERAL_SUBTREE_new()
+ gs.base = _encode_general_name(backend, name)
+ res = backend._lib.sk_GENERAL_SUBTREE_push(general_subtrees, gs)
+ assert res >= 1
+
+ return general_subtrees
+
+
+def _encode_nonce(backend, nonce):
+ return _encode_asn1_str_gc(backend, nonce.nonce)
+
+
+_EXTENSION_ENCODE_HANDLERS = {
+ ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints,
+ ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier,
+ ExtensionOID.KEY_USAGE: _encode_key_usage,
+ ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _encode_alt_name,
+ ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
+ ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage,
+ ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
+ ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies,
+ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
+ _encode_authority_information_access
+ ),
+ ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl,
+ ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
+ ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy,
+ ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck,
+ ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints,
+ ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints,
+}
+
+_CRL_EXTENSION_ENCODE_HANDLERS = {
+ ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name,
+ ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier,
+ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: (
+ _encode_authority_information_access
+ ),
+ ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator,
+ ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator,
+ ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point,
+ ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl,
+}
+
+_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = {
+ CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name,
+ CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason,
+ CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date,
+}
+
+_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS = {
+ OCSPExtensionOID.NONCE: _encode_nonce,
+}
+
+_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS = {
+ OCSPExtensionOID.NONCE: _encode_nonce,
+}
diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py
index 2c1702f8..7f9d840b 100644
--- a/src/cryptography/hazmat/backends/openssl/hashes.py
+++ b/src/cryptography/hazmat/backends/openssl/hashes.py
@@ -18,45 +18,61 @@ class _HashContext(object):
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"))
+ ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ ctx = self._backend._ffi.gc(
+ ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ evp_md = self._backend._evp_md_from_algorithm(algorithm)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend.".format(
+ "{} 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._backend.openssl_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._lib.Cryptography_EVP_MD_CTX_new()
copied_ctx = self._backend._ffi.gc(
- copied_ctx, self._backend._lib.EVP_MD_CTX_destroy
+ copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx)
- assert res != 0
+ self._backend.openssl_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
+ data_ptr = self._backend._ffi.from_buffer(data)
+ res = self._backend._lib.EVP_DigestUpdate(
+ self._ctx, data_ptr, len(data)
+ )
+ self._backend.openssl_assert(res != 0)
def finalize(self):
+ if isinstance(self.algorithm, hashes.ExtendableOutputFunction):
+ # extendable output functions use a different finalize
+ return self._finalize_xof()
+ else:
+ 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)
+ self._backend.openssl_assert(res != 0)
+ self._backend.openssl_assert(
+ outlen[0] == self.algorithm.digest_size
+ )
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def _finalize_xof(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]]
+ self.algorithm.digest_size)
+ res = self._backend._lib.EVP_DigestFinalXOF(
+ self._ctx, buf, self.algorithm.digest_size
+ )
+ self._backend.openssl_assert(res != 0)
+ return self._backend._ffi.buffer(buf)[:self.algorithm.digest_size]
diff --git a/src/cryptography/hazmat/backends/openssl/hmac.py b/src/cryptography/hazmat/backends/openssl/hmac.py
index dfe9d93b..2e09cbc8 100644
--- a/src/cryptography/hazmat/backends/openssl/hmac.py
+++ b/src/cryptography/hazmat/backends/openssl/hmac.py
@@ -9,10 +9,9 @@ from cryptography import utils
from cryptography.exceptions import (
InvalidSignature, UnsupportedAlgorithm, _Reasons
)
-from cryptography.hazmat.primitives import constant_time, hashes, interfaces
+from cryptography.hazmat.primitives import constant_time, hashes
-@utils.register_interface(interfaces.MACContext)
@utils.register_interface(hashes.HashContext)
class _HMACContext(object):
def __init__(self, backend, key, algorithm, ctx=None):
@@ -20,23 +19,23 @@ class _HMACContext(object):
self._backend = backend
if ctx is None:
- ctx = self._backend._ffi.new("HMAC_CTX *")
- self._backend._lib.HMAC_CTX_init(ctx)
+ ctx = self._backend._lib.Cryptography_HMAC_CTX_new()
+ self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(
- ctx, self._backend._lib.HMAC_CTX_cleanup
+ ctx, self._backend._lib.Cryptography_HMAC_CTX_free
)
- evp_md = self._backend._lib.EVP_get_digestbyname(
- algorithm.name.encode('ascii'))
+ evp_md = self._backend._evp_md_from_algorithm(algorithm)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend.".format(
+ "{} 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
+ key_ptr = self._backend._ffi.from_buffer(key)
+ res = self._backend._lib.HMAC_Init_ex(
+ ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL
)
- assert res != 0
+ self._backend.openssl_assert(res != 0)
self._ctx = ctx
self._key = key
@@ -44,35 +43,29 @@ class _HMACContext(object):
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._lib.Cryptography_HMAC_CTX_new()
+ self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL)
copied_ctx = self._backend._ffi.gc(
- copied_ctx, self._backend._lib.HMAC_CTX_cleanup
+ copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free
)
- res = self._backend._lib.Cryptography_HMAC_CTX_copy(
- copied_ctx, self._ctx
- )
- assert res != 0
+ res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx)
+ self._backend.openssl_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
+ data_ptr = self._backend._ffi.from_buffer(data)
+ res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data))
+ self._backend.openssl_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)
+ res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen)
+ self._backend.openssl_assert(res != 0)
+ self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size)
return self._backend._ffi.buffer(buf)[:outlen[0]]
def verify(self, signature):
diff --git a/src/cryptography/hazmat/backends/openssl/ocsp.py b/src/cryptography/hazmat/backends/openssl/ocsp.py
new file mode 100644
index 00000000..e42565ef
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/ocsp.py
@@ -0,0 +1,389 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import functools
+
+from cryptography import utils, x509
+from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.backends.openssl.decode_asn1 import (
+ _CRL_ENTRY_REASON_CODE_TO_ENUM, _OCSP_BASICRESP_EXT_PARSER,
+ _OCSP_REQ_EXT_PARSER, _OCSP_SINGLERESP_EXT_PARSER,
+ _asn1_integer_to_int,
+ _asn1_string_to_bytes, _decode_x509_name, _obj2txt,
+ _parse_asn1_generalized_time,
+)
+from cryptography.hazmat.backends.openssl.x509 import _Certificate
+from cryptography.hazmat.primitives import serialization
+from cryptography.x509.ocsp import (
+ OCSPCertStatus, OCSPRequest, OCSPResponse, OCSPResponseStatus,
+ _CERT_STATUS_TO_ENUM, _OIDS_TO_HASH, _RESPONSE_STATUS_TO_ENUM,
+)
+
+
+def _requires_successful_response(func):
+ @functools.wraps(func)
+ def wrapper(self, *args):
+ if self.response_status != OCSPResponseStatus.SUCCESSFUL:
+ raise ValueError(
+ "OCSP response status is not successful so the property "
+ "has no value"
+ )
+ else:
+ return func(self, *args)
+
+ return wrapper
+
+
+def _issuer_key_hash(backend, cert_id):
+ key_hash = backend._ffi.new("ASN1_OCTET_STRING **")
+ res = backend._lib.OCSP_id_get0_info(
+ backend._ffi.NULL, backend._ffi.NULL,
+ key_hash, backend._ffi.NULL, cert_id
+ )
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(key_hash[0] != backend._ffi.NULL)
+ return _asn1_string_to_bytes(backend, key_hash[0])
+
+
+def _issuer_name_hash(backend, cert_id):
+ name_hash = backend._ffi.new("ASN1_OCTET_STRING **")
+ res = backend._lib.OCSP_id_get0_info(
+ name_hash, backend._ffi.NULL,
+ backend._ffi.NULL, backend._ffi.NULL, cert_id
+ )
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(name_hash[0] != backend._ffi.NULL)
+ return _asn1_string_to_bytes(backend, name_hash[0])
+
+
+def _serial_number(backend, cert_id):
+ num = backend._ffi.new("ASN1_INTEGER **")
+ res = backend._lib.OCSP_id_get0_info(
+ backend._ffi.NULL, backend._ffi.NULL,
+ backend._ffi.NULL, num, cert_id
+ )
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(num[0] != backend._ffi.NULL)
+ return _asn1_integer_to_int(backend, num[0])
+
+
+def _hash_algorithm(backend, cert_id):
+ asn1obj = backend._ffi.new("ASN1_OBJECT **")
+ res = backend._lib.OCSP_id_get0_info(
+ backend._ffi.NULL, asn1obj,
+ backend._ffi.NULL, backend._ffi.NULL, cert_id
+ )
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(asn1obj[0] != backend._ffi.NULL)
+ oid = _obj2txt(backend, asn1obj[0])
+ try:
+ return _OIDS_TO_HASH[oid]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "Signature algorithm OID: {} not recognized".format(oid)
+ )
+
+
+@utils.register_interface(OCSPResponse)
+class _OCSPResponse(object):
+ def __init__(self, backend, ocsp_response):
+ self._backend = backend
+ self._ocsp_response = ocsp_response
+ status = self._backend._lib.OCSP_response_status(self._ocsp_response)
+ self._backend.openssl_assert(status in _RESPONSE_STATUS_TO_ENUM)
+ self._status = _RESPONSE_STATUS_TO_ENUM[status]
+ if self._status is OCSPResponseStatus.SUCCESSFUL:
+ basic = self._backend._lib.OCSP_response_get1_basic(
+ self._ocsp_response
+ )
+ self._backend.openssl_assert(basic != self._backend._ffi.NULL)
+ self._basic = self._backend._ffi.gc(
+ basic, self._backend._lib.OCSP_BASICRESP_free
+ )
+ self._backend.openssl_assert(
+ self._backend._lib.OCSP_resp_count(self._basic) == 1
+ )
+ self._single = self._backend._lib.OCSP_resp_get0(self._basic, 0)
+ self._backend.openssl_assert(
+ self._single != self._backend._ffi.NULL
+ )
+ self._cert_id = self._backend._lib.OCSP_SINGLERESP_get0_id(
+ self._single
+ )
+ self._backend.openssl_assert(
+ self._cert_id != self._backend._ffi.NULL
+ )
+
+ response_status = utils.read_only_property("_status")
+
+ @property
+ @_requires_successful_response
+ def signature_algorithm_oid(self):
+ alg = self._backend._lib.OCSP_resp_get0_tbs_sigalg(self._basic)
+ self._backend.openssl_assert(alg != self._backend._ffi.NULL)
+ oid = _obj2txt(self._backend, alg.algorithm)
+ return x509.ObjectIdentifier(oid)
+
+ @property
+ @_requires_successful_response
+ def signature_hash_algorithm(self):
+ oid = self.signature_algorithm_oid
+ try:
+ return x509._SIG_OIDS_TO_HASH[oid]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "Signature algorithm OID:{} not recognized".format(oid)
+ )
+
+ @property
+ @_requires_successful_response
+ def signature(self):
+ sig = self._backend._lib.OCSP_resp_get0_signature(self._basic)
+ self._backend.openssl_assert(sig != self._backend._ffi.NULL)
+ return _asn1_string_to_bytes(self._backend, sig)
+
+ @property
+ @_requires_successful_response
+ def tbs_response_bytes(self):
+ respdata = self._backend._lib.OCSP_resp_get0_respdata(self._basic)
+ self._backend.openssl_assert(respdata != self._backend._ffi.NULL)
+ pp = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.i2d_OCSP_RESPDATA(respdata, pp)
+ self._backend.openssl_assert(pp[0] != self._backend._ffi.NULL)
+ pp = self._backend._ffi.gc(
+ pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
+ )
+ self._backend.openssl_assert(res > 0)
+ return self._backend._ffi.buffer(pp[0], res)[:]
+
+ @property
+ @_requires_successful_response
+ def certificates(self):
+ sk_x509 = self._backend._lib.OCSP_resp_get0_certs(self._basic)
+ num = self._backend._lib.sk_X509_num(sk_x509)
+ certs = []
+ for i in range(num):
+ x509 = self._backend._lib.sk_X509_value(sk_x509, i)
+ self._backend.openssl_assert(x509 != self._backend._ffi.NULL)
+ cert = _Certificate(self._backend, x509)
+ # We need to keep the OCSP response that the certificate came from
+ # alive until the Certificate object itself goes out of scope, so
+ # we give it a private reference.
+ cert._ocsp_resp = self
+ certs.append(cert)
+
+ return certs
+
+ @property
+ @_requires_successful_response
+ def responder_key_hash(self):
+ _, asn1_string = self._responder_key_name()
+ if asn1_string == self._backend._ffi.NULL:
+ return None
+ else:
+ return _asn1_string_to_bytes(self._backend, asn1_string)
+
+ @property
+ @_requires_successful_response
+ def responder_name(self):
+ x509_name, _ = self._responder_key_name()
+ if x509_name == self._backend._ffi.NULL:
+ return None
+ else:
+ return _decode_x509_name(self._backend, x509_name)
+
+ def _responder_key_name(self):
+ asn1_string = self._backend._ffi.new("ASN1_OCTET_STRING **")
+ x509_name = self._backend._ffi.new("X509_NAME **")
+ res = self._backend._lib.OCSP_resp_get0_id(
+ self._basic, asn1_string, x509_name
+ )
+ self._backend.openssl_assert(res == 1)
+ return x509_name[0], asn1_string[0]
+
+ @property
+ @_requires_successful_response
+ def produced_at(self):
+ produced_at = self._backend._lib.OCSP_resp_get0_produced_at(
+ self._basic
+ )
+ return _parse_asn1_generalized_time(self._backend, produced_at)
+
+ @property
+ @_requires_successful_response
+ def certificate_status(self):
+ status = self._backend._lib.OCSP_single_get0_status(
+ self._single,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ )
+ self._backend.openssl_assert(status in _CERT_STATUS_TO_ENUM)
+ return _CERT_STATUS_TO_ENUM[status]
+
+ @property
+ @_requires_successful_response
+ def revocation_time(self):
+ if self.certificate_status is not OCSPCertStatus.REVOKED:
+ return None
+
+ asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
+ self._backend._lib.OCSP_single_get0_status(
+ self._single,
+ self._backend._ffi.NULL,
+ asn1_time,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ )
+ self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL)
+ return _parse_asn1_generalized_time(self._backend, asn1_time[0])
+
+ @property
+ @_requires_successful_response
+ def revocation_reason(self):
+ if self.certificate_status is not OCSPCertStatus.REVOKED:
+ return None
+
+ reason_ptr = self._backend._ffi.new("int *")
+ self._backend._lib.OCSP_single_get0_status(
+ self._single,
+ reason_ptr,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ )
+ # If no reason is encoded OpenSSL returns -1
+ if reason_ptr[0] == -1:
+ return None
+ else:
+ self._backend.openssl_assert(
+ reason_ptr[0] in _CRL_ENTRY_REASON_CODE_TO_ENUM
+ )
+ return _CRL_ENTRY_REASON_CODE_TO_ENUM[reason_ptr[0]]
+
+ @property
+ @_requires_successful_response
+ def this_update(self):
+ asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
+ self._backend._lib.OCSP_single_get0_status(
+ self._single,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ asn1_time,
+ self._backend._ffi.NULL,
+ )
+ self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL)
+ return _parse_asn1_generalized_time(self._backend, asn1_time[0])
+
+ @property
+ @_requires_successful_response
+ def next_update(self):
+ asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **")
+ self._backend._lib.OCSP_single_get0_status(
+ self._single,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ asn1_time,
+ )
+ if asn1_time[0] != self._backend._ffi.NULL:
+ return _parse_asn1_generalized_time(self._backend, asn1_time[0])
+ else:
+ return None
+
+ @property
+ @_requires_successful_response
+ def issuer_key_hash(self):
+ return _issuer_key_hash(self._backend, self._cert_id)
+
+ @property
+ @_requires_successful_response
+ def issuer_name_hash(self):
+ return _issuer_name_hash(self._backend, self._cert_id)
+
+ @property
+ @_requires_successful_response
+ def hash_algorithm(self):
+ return _hash_algorithm(self._backend, self._cert_id)
+
+ @property
+ @_requires_successful_response
+ def serial_number(self):
+ return _serial_number(self._backend, self._cert_id)
+
+ @utils.cached_property
+ @_requires_successful_response
+ def extensions(self):
+ return _OCSP_BASICRESP_EXT_PARSER.parse(self._backend, self._basic)
+
+ @utils.cached_property
+ @_requires_successful_response
+ def single_extensions(self):
+ return _OCSP_SINGLERESP_EXT_PARSER.parse(
+ self._backend, self._single
+ )
+
+ def public_bytes(self, encoding):
+ if encoding is not serialization.Encoding.DER:
+ raise ValueError(
+ "The only allowed encoding value is Encoding.DER"
+ )
+
+ bio = self._backend._create_mem_bio_gc()
+ res = self._backend._lib.i2d_OCSP_RESPONSE_bio(
+ bio, self._ocsp_response
+ )
+ self._backend.openssl_assert(res > 0)
+ return self._backend._read_mem_bio(bio)
+
+
+@utils.register_interface(OCSPRequest)
+class _OCSPRequest(object):
+ def __init__(self, backend, ocsp_request):
+ if backend._lib.OCSP_request_onereq_count(ocsp_request) > 1:
+ raise NotImplementedError(
+ 'OCSP request contains more than one request'
+ )
+ self._backend = backend
+ self._ocsp_request = ocsp_request
+ self._request = self._backend._lib.OCSP_request_onereq_get0(
+ self._ocsp_request, 0
+ )
+ self._backend.openssl_assert(self._request != self._backend._ffi.NULL)
+ self._cert_id = self._backend._lib.OCSP_onereq_get0_id(self._request)
+ self._backend.openssl_assert(self._cert_id != self._backend._ffi.NULL)
+
+ @property
+ def issuer_key_hash(self):
+ return _issuer_key_hash(self._backend, self._cert_id)
+
+ @property
+ def issuer_name_hash(self):
+ return _issuer_name_hash(self._backend, self._cert_id)
+
+ @property
+ def serial_number(self):
+ return _serial_number(self._backend, self._cert_id)
+
+ @property
+ def hash_algorithm(self):
+ return _hash_algorithm(self._backend, self._cert_id)
+
+ @utils.cached_property
+ def extensions(self):
+ return _OCSP_REQ_EXT_PARSER.parse(self._backend, self._ocsp_request)
+
+ def public_bytes(self, encoding):
+ if encoding is not serialization.Encoding.DER:
+ raise ValueError(
+ "The only allowed encoding value is Encoding.DER"
+ )
+
+ bio = self._backend._create_mem_bio_gc()
+ res = self._backend._lib.i2d_OCSP_REQUEST_bio(bio, self._ocsp_request)
+ self._backend.openssl_assert(res > 0)
+ return self._backend._read_mem_bio(bio)
diff --git a/src/cryptography/hazmat/backends/openssl/poly1305.py b/src/cryptography/hazmat/backends/openssl/poly1305.py
new file mode 100644
index 00000000..25448dd0
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/poly1305.py
@@ -0,0 +1,60 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+
+from cryptography.exceptions import InvalidSignature
+from cryptography.hazmat.primitives import constant_time
+
+
+_POLY1305_TAG_SIZE = 16
+_POLY1305_KEY_SIZE = 32
+
+
+class _Poly1305Context(object):
+ def __init__(self, backend, key):
+ self._backend = backend
+
+ key_ptr = self._backend._ffi.from_buffer(key)
+ # This function copies the key into OpenSSL-owned memory so we don't
+ # need to retain it ourselves
+ evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key(
+ self._backend._lib.NID_poly1305,
+ self._backend._ffi.NULL, key_ptr, len(key)
+ )
+ self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL)
+ self._evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new()
+ self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
+ self._ctx = self._backend._ffi.gc(
+ ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
+ )
+ res = self._backend._lib.EVP_DigestSignInit(
+ self._ctx, self._backend._ffi.NULL, self._backend._ffi.NULL,
+ self._backend._ffi.NULL, self._evp_pkey
+ )
+ self._backend.openssl_assert(res == 1)
+
+ def update(self, data):
+ data_ptr = self._backend._ffi.from_buffer(data)
+ res = self._backend._lib.EVP_DigestSignUpdate(
+ self._ctx, data_ptr, len(data)
+ )
+ self._backend.openssl_assert(res != 0)
+
+ def finalize(self):
+ buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE)
+ outlen = self._backend._ffi.new("size_t *")
+ res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen)
+ self._backend.openssl_assert(res != 0)
+ self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE)
+ return self._backend._ffi.buffer(buf)[:outlen[0]]
+
+ def verify(self, tag):
+ mac = self.finalize()
+ if not constant_time.bytes_eq(mac, tag):
+ raise InvalidSignature("Value did not match computed tag.")
diff --git a/src/cryptography/hazmat/backends/openssl/rsa.py b/src/cryptography/hazmat/backends/openssl/rsa.py
index 21414c05..a9e07b52 100644
--- a/src/cryptography/hazmat/backends/openssl/rsa.py
+++ b/src/cryptography/hazmat/backends/openssl/rsa.py
@@ -4,33 +4,31 @@
from __future__ import absolute_import, division, print_function
-import math
-
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
+ InvalidSignature, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.openssl.utils import (
+ _calculate_digest_and_algorithm, _check_not_prehashed,
+ _warn_sign_verify_deprecated
)
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import (
AsymmetricSignatureContext, AsymmetricVerificationContext, rsa
)
from cryptography.hazmat.primitives.asymmetric.padding import (
- AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS
+ AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS, calculate_max_pss_salt_length
)
from cryptography.hazmat.primitives.asymmetric.rsa import (
RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization
)
-def _get_rsa_pss_salt_length(pss, key_size, digest_size):
+def _get_rsa_pss_salt_length(pss, key, hash_algorithm):
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
+ return calculate_max_pss_salt_length(key, hash_algorithm)
else:
return salt
@@ -43,63 +41,80 @@ def _enc_dec_rsa(backend, key, data, padding):
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):
+ if not backend.rsa_padding_supported(padding):
raise UnsupportedAlgorithm(
- "This backend supports only SHA1 inside MGF1 when "
- "using OAEP.",
- _Reasons.UNSUPPORTED_HASH
+ "This combination of padding and hash algorithm is not "
+ "supported by this backend.",
+ _Reasons.UNSUPPORTED_PADDING
)
- 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(
+ "{} 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)
+ return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
-def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
+def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding):
if isinstance(key, _RSAPublicKey):
init = backend._lib.EVP_PKEY_encrypt_init
- crypt = backend._lib.Cryptography_EVP_PKEY_encrypt
+ crypt = backend._lib.EVP_PKEY_encrypt
else:
init = backend._lib.EVP_PKEY_decrypt_init
- crypt = backend._lib.Cryptography_EVP_PKEY_decrypt
+ crypt = backend._lib.EVP_PKEY_decrypt
pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
key._evp_pkey, backend._ffi.NULL
)
- assert pkey_ctx != backend._ffi.NULL
+ backend.openssl_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
+ backend.openssl_assert(res == 1)
res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
pkey_ctx, padding_enum)
- assert res > 0
+ backend.openssl_assert(res > 0)
buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
- assert buf_size > 0
+ backend.openssl_assert(buf_size > 0)
+ if (
+ isinstance(padding, OAEP) and
+ backend._lib.Cryptography_HAS_RSA_OAEP_MD
+ ):
+ mgf1_md = backend._evp_md_non_null_from_algorithm(
+ padding._mgf._algorithm)
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md)
+ backend.openssl_assert(res > 0)
+ oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm)
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md)
+ backend.openssl_assert(res > 0)
+
+ if (
+ isinstance(padding, OAEP) and
+ padding._label is not None and
+ len(padding._label) > 0
+ ):
+ # set0_rsa_oaep_label takes ownership of the char * so we need to
+ # copy it into some new memory
+ labelptr = backend._lib.OPENSSL_malloc(len(padding._label))
+ backend.openssl_assert(labelptr != backend._ffi.NULL)
+ backend._ffi.memmove(labelptr, padding._label, len(padding._label))
+ res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label(
+ pkey_ctx, labelptr, len(padding._label)
+ )
+ backend.openssl_assert(res == 1)
+
outlen = backend._ffi.new("size_t *", buf_size)
- buf = backend._ffi.new("char[]", buf_size)
+ buf = backend._ffi.new("unsigned char[]", buf_size)
res = crypt(pkey_ctx, buf, outlen, data, len(data))
if res <= 0:
_handle_rsa_enc_dec_error(backend, key)
@@ -107,96 +122,165 @@ def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum):
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
+ backend.openssl_assert(errors)
+ backend.openssl_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)
+ backend.openssl_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_BAD_PAD_BYTE_COUNT,
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_01,
backend._lib.RSA_R_BLOCK_TYPE_IS_NOT_02,
+ backend._lib.RSA_R_OAEP_DECODING_ERROR,
+ # Though this error looks similar to the
+ # RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE, this occurs on decrypts,
+ # rather than on encrypts
+ backend._lib.RSA_R_DATA_TOO_LARGE_FOR_MODULUS,
]
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
+ backend.openssl_assert(errors[0].reason in decoding_errors)
raise ValueError("Decryption failed.")
-@utils.register_interface(AsymmetricSignatureContext)
-class _RSASignatureContext(object):
- def __init__(self, backend, private_key, padding, algorithm):
- self._backend = backend
- self._private_key = private_key
+def _rsa_sig_determine_padding(backend, key, padding, algorithm):
+ if not isinstance(padding, AsymmetricPadding):
+ raise TypeError("Expected provider of AsymmetricPadding.")
+
+ pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
+ backend.openssl_assert(pkey_size > 0)
+
+ if isinstance(padding, PKCS1v15):
+ padding_enum = backend._lib.RSA_PKCS1_PADDING
+ 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)
+ if pkey_size - algorithm.digest_size - 2 < 0:
+ raise ValueError("Digest too large for key size. Use a larger "
+ "key or different digest.")
+
+ padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING
+ else:
+ raise UnsupportedAlgorithm(
+ "{} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING
+ )
+
+ return padding_enum
- if not isinstance(padding, AsymmetricPadding):
- raise TypeError("Expected provider of AsymmetricPadding.")
- self._pkey_size = self._backend._lib.EVP_PKEY_size(
- self._private_key._evp_pkey
+def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func):
+ padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm)
+ evp_md = backend._evp_md_non_null_from_algorithm(algorithm)
+ pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL)
+ backend.openssl_assert(pkey_ctx != backend._ffi.NULL)
+ pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free)
+ res = init_func(pkey_ctx)
+ backend.openssl_assert(res == 1)
+ res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md)
+ if res == 0:
+ backend._consume_errors()
+ raise UnsupportedAlgorithm(
+ "{} is not supported by this backend for RSA signing.".format(
+ algorithm.name
+ ),
+ _Reasons.UNSUPPORTED_HASH
+ )
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum)
+ backend.openssl_assert(res > 0)
+ if isinstance(padding, PSS):
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen(
+ pkey_ctx, _get_rsa_pss_salt_length(padding, key, algorithm)
)
+ backend.openssl_assert(res > 0)
+
+ mgf1_md = backend._evp_md_non_null_from_algorithm(
+ padding._mgf._algorithm)
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md)
+ backend.openssl_assert(res > 0)
- 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
+ return pkey_ctx
+
+
+def _rsa_sig_sign(backend, padding, algorithm, private_key, data):
+ pkey_ctx = _rsa_sig_setup(
+ backend, padding, algorithm, private_key, data,
+ backend._lib.EVP_PKEY_sign_init
+ )
+ buflen = backend._ffi.new("size_t *")
+ res = backend._lib.EVP_PKEY_sign(
+ pkey_ctx,
+ backend._ffi.NULL,
+ buflen,
+ data,
+ len(data)
+ )
+ backend.openssl_assert(res == 1)
+ buf = backend._ffi.new("unsigned char[]", buflen[0])
+ res = backend._lib.EVP_PKEY_sign(
+ pkey_ctx, buf, buflen, data, len(data))
+ if res != 1:
+ errors = backend._consume_errors()
+ backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA)
+ if (
+ errors[0].reason ==
+ backend._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE
+ ):
+ reason = ("Salt length too long for key size. Try using "
+ "MAX_LENGTH instead.")
else:
- raise UnsupportedAlgorithm(
- "{0} is not supported by this backend.".format(padding.name),
- _Reasons.UNSUPPORTED_PADDING
+ backend.openssl_assert(
+ errors[0].reason ==
+ backend._lib.RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY
)
+ reason = "Digest too large for key size. Use a larger key."
+ raise ValueError(reason)
+ return backend._ffi.buffer(buf)[:]
+
+
+def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data):
+ pkey_ctx = _rsa_sig_setup(
+ backend, padding, algorithm, public_key, data,
+ backend._lib.EVP_PKEY_verify_init
+ )
+ res = backend._lib.EVP_PKEY_verify(
+ pkey_ctx, signature, len(signature), data, len(data)
+ )
+ # 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.
+ backend.openssl_assert(res >= 0)
+ if res == 0:
+ backend._consume_errors()
+ raise InvalidSignature
+
+
+@utils.register_interface(AsymmetricSignatureContext)
+class _RSASignatureContext(object):
+ def __init__(self, backend, private_key, padding, algorithm):
+ self._backend = backend
+ self._private_key = private_key
+
+ # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However
+ # we need to make a pointless call to it here so we maintain the
+ # API of erroring on init with this context if the values are invalid.
+ _rsa_sig_determine_padding(backend, private_key, padding, algorithm)
self._padding = padding
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
@@ -205,132 +289,13 @@ class _RSASignatureContext(object):
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)
- )
+ return _rsa_sig_sign(
+ self._backend,
+ self._padding,
+ self._algorithm,
+ self._private_key,
+ self._hash_ctx.finalize()
)
- 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(AsymmetricVerificationContext)
@@ -339,55 +304,13 @@ class _RSAVerificationContext(object):
self._backend = backend
self._public_key = public_key
self._signature = signature
-
- if not isinstance(padding, AsymmetricPadding):
- raise TypeError("Expected provider of 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
+ # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However
+ # we need to make a pointless call to it here so we maintain the
+ # API of erroring on init with this context if the values are invalid.
+ _rsa_sig_determine_padding(backend, public_key, padding, algorithm)
+
+ padding = padding
self._algorithm = algorithm
self._hash_ctx = hashes.Hash(self._algorithm, self._backend)
@@ -395,115 +318,14 @@ class _RSAVerificationContext(object):
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),
+ return _rsa_sig_verify(
+ self._backend,
+ self._padding,
+ self._algorithm,
+ self._public_key,
self._signature,
- buf,
- self._public_key._rsa_cdata,
- self._backend._lib.RSA_NO_PADDING
+ self._hash_ctx.finalize()
)
- 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(RSAPrivateKeyWithSerialization)
@@ -513,42 +335,69 @@ class _RSAPrivateKey(object):
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
- self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+ n = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.RSA_get0_key(
+ self._rsa_cdata, n, self._backend._ffi.NULL,
+ self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
+ self._key_size = self._backend._lib.BN_num_bits(n[0])
key_size = utils.read_only_property("_key_size")
def signer(self, padding, algorithm):
+ _warn_sign_verify_deprecated()
+ _check_not_prehashed(algorithm)
return _RSASignatureContext(self._backend, self, padding, algorithm)
def decrypt(self, ciphertext, padding):
- key_size_bytes = int(math.ceil(self.key_size / 8.0))
+ key_size_bytes = (self.key_size + 7) // 8
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._lib.RSAPublicKey_dup(self._rsa_cdata)
+ self._backend.openssl_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
+ self._backend.openssl_assert(res == 1)
evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx)
return _RSAPublicKey(self._backend, ctx, evp_pkey)
def private_numbers(self):
+ n = self._backend._ffi.new("BIGNUM **")
+ e = self._backend._ffi.new("BIGNUM **")
+ d = self._backend._ffi.new("BIGNUM **")
+ p = self._backend._ffi.new("BIGNUM **")
+ q = self._backend._ffi.new("BIGNUM **")
+ dmp1 = self._backend._ffi.new("BIGNUM **")
+ dmq1 = self._backend._ffi.new("BIGNUM **")
+ iqmp = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d)
+ self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(e[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(d[0] != self._backend._ffi.NULL)
+ self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q)
+ self._backend.openssl_assert(p[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(q[0] != self._backend._ffi.NULL)
+ self._backend._lib.RSA_get0_crt_params(
+ self._rsa_cdata, dmp1, dmq1, iqmp
+ )
+ self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL)
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),
+ p=self._backend._bn_to_int(p[0]),
+ q=self._backend._bn_to_int(q[0]),
+ d=self._backend._bn_to_int(d[0]),
+ dmp1=self._backend._bn_to_int(dmp1[0]),
+ dmq1=self._backend._bn_to_int(dmq1[0]),
+ iqmp=self._backend._bn_to_int(iqmp[0]),
public_numbers=rsa.RSAPublicNumbers(
- e=self._backend._bn_to_int(self._rsa_cdata.e),
- n=self._backend._bn_to_int(self._rsa_cdata.n),
+ e=self._backend._bn_to_int(e[0]),
+ n=self._backend._bn_to_int(n[0]),
)
)
@@ -557,10 +406,17 @@ class _RSAPrivateKey(object):
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
self._rsa_cdata
)
+ def sign(self, data, padding, algorithm):
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, algorithm
+ )
+ return _rsa_sig_sign(self._backend, padding, algorithm, self, data)
+
@utils.register_interface(RSAPublicKeyWithSerialization)
class _RSAPublicKey(object):
@@ -569,11 +425,21 @@ class _RSAPublicKey(object):
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
- self._key_size = self._backend._lib.BN_num_bits(self._rsa_cdata.n)
+ n = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.RSA_get0_key(
+ self._rsa_cdata, n, self._backend._ffi.NULL,
+ self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
+ self._key_size = self._backend._lib.BN_num_bits(n[0])
key_size = utils.read_only_property("_key_size")
def verifier(self, signature, padding, algorithm):
+ _warn_sign_verify_deprecated()
+ utils._check_bytes("signature", signature)
+
+ _check_not_prehashed(algorithm)
return _RSAVerificationContext(
self._backend, self, signature, padding, algorithm
)
@@ -582,15 +448,31 @@ class _RSAPublicKey(object):
return _enc_dec_rsa(self._backend, self, plaintext, padding)
def public_numbers(self):
+ n = self._backend._ffi.new("BIGNUM **")
+ e = self._backend._ffi.new("BIGNUM **")
+ self._backend._lib.RSA_get0_key(
+ self._rsa_cdata, n, e, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(n[0] != self._backend._ffi.NULL)
+ self._backend.openssl_assert(e[0] != self._backend._ffi.NULL)
return rsa.RSAPublicNumbers(
- e=self._backend._bn_to_int(self._rsa_cdata.e),
- n=self._backend._bn_to_int(self._rsa_cdata.n),
+ e=self._backend._bn_to_int(e[0]),
+ n=self._backend._bn_to_int(n[0]),
)
def public_bytes(self, encoding, format):
return self._backend._public_key_bytes(
encoding,
format,
+ self,
self._evp_pkey,
self._rsa_cdata
)
+
+ def verify(self, signature, data, padding, algorithm):
+ data, algorithm = _calculate_digest_and_algorithm(
+ self._backend, data, algorithm
+ )
+ return _rsa_sig_verify(
+ self._backend, padding, algorithm, self, signature, data
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/utils.py b/src/cryptography/hazmat/backends/openssl/utils.py
index 001121f9..ee472c0e 100644
--- a/src/cryptography/hazmat/backends/openssl/utils.py
+++ b/src/cryptography/hazmat/backends/openssl/utils.py
@@ -4,23 +4,66 @@
from __future__ import absolute_import, division, print_function
-import six
+import warnings
+from cryptography import utils
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
-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]
+def _evp_pkey_derive(backend, evp_pkey, peer_public_key):
+ ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL)
+ backend.openssl_assert(ctx != backend._ffi.NULL)
+ ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free)
+ res = backend._lib.EVP_PKEY_derive_init(ctx)
+ backend.openssl_assert(res == 1)
+ res = backend._lib.EVP_PKEY_derive_set_peer(
+ ctx, peer_public_key._evp_pkey
+ )
+ backend.openssl_assert(res == 1)
+ keylen = backend._ffi.new("size_t *")
+ res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen)
+ backend.openssl_assert(res == 1)
+ backend.openssl_assert(keylen[0] > 0)
+ buf = backend._ffi.new("unsigned char[]", keylen[0])
+ res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen)
+ if res != 1:
+ raise ValueError(
+ "Null shared key derived from public/private pair."
+ )
- if 8 * digest_len > order_bits:
- rshift = 8 - (order_bits & 0x7)
- assert 0 < rshift < 8
+ return backend._ffi.buffer(buf, keylen[0])[:]
- mask = 0xFF >> rshift << rshift
- # Set the bottom rshift bits to 0
- digest = digest[:-1] + six.int2byte(six.indexbytes(digest, -1) & mask)
+def _calculate_digest_and_algorithm(backend, data, algorithm):
+ if not isinstance(algorithm, Prehashed):
+ hash_ctx = hashes.Hash(algorithm, backend)
+ hash_ctx.update(data)
+ data = hash_ctx.finalize()
+ else:
+ algorithm = algorithm._algorithm
- return digest
+ if len(data) != algorithm.digest_size:
+ raise ValueError(
+ "The provided data must be the same length as the hash "
+ "algorithm's digest size."
+ )
+
+ return (data, algorithm)
+
+
+def _check_not_prehashed(signature_algorithm):
+ if isinstance(signature_algorithm, Prehashed):
+ raise TypeError(
+ "Prehashed is only supported in the sign and verify methods. "
+ "It cannot be used with signer or verifier."
+ )
+
+
+def _warn_sign_verify_deprecated():
+ warnings.warn(
+ "signer and verifier have been deprecated. Please use sign "
+ "and verify instead.",
+ utils.PersistentlyDeprecated2017,
+ stacklevel=3
+ )
diff --git a/src/cryptography/hazmat/backends/openssl/x25519.py b/src/cryptography/hazmat/backends/openssl/x25519.py
new file mode 100644
index 00000000..665acf2f
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/x25519.py
@@ -0,0 +1,118 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import utils
+from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.x25519 import (
+ X25519PrivateKey, X25519PublicKey
+)
+
+
+_X25519_KEY_SIZE = 32
+
+
+@utils.register_interface(X25519PublicKey)
+class _X25519PublicKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_bytes(self, encoding, format):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ encoding is not serialization.Encoding.Raw or
+ format is not serialization.PublicFormat.Raw
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw"
+ )
+
+ return self._raw_public_bytes()
+
+ return self._backend._public_key_bytes(
+ encoding, format, self, self._evp_pkey, None
+ )
+
+ def _raw_public_bytes(self):
+ ucharpp = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint(
+ self._evp_pkey, ucharpp
+ )
+ self._backend.openssl_assert(res == 32)
+ self._backend.openssl_assert(ucharpp[0] != self._backend._ffi.NULL)
+ data = self._backend._ffi.gc(
+ ucharpp[0], self._backend._lib.OPENSSL_free
+ )
+ return self._backend._ffi.buffer(data, res)[:]
+
+
+@utils.register_interface(X25519PrivateKey)
+class _X25519PrivateKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_key(self):
+ bio = self._backend._create_mem_bio_gc()
+ res = self._backend._lib.i2d_PUBKEY_bio(bio, self._evp_pkey)
+ self._backend.openssl_assert(res == 1)
+ evp_pkey = self._backend._lib.d2i_PUBKEY_bio(
+ bio, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL)
+ evp_pkey = self._backend._ffi.gc(
+ evp_pkey, self._backend._lib.EVP_PKEY_free
+ )
+ return _X25519PublicKey(self._backend, evp_pkey)
+
+ def exchange(self, peer_public_key):
+ if not isinstance(peer_public_key, X25519PublicKey):
+ raise TypeError("peer_public_key must be X25519PublicKey.")
+
+ return _evp_pkey_derive(
+ self._backend, self._evp_pkey, peer_public_key
+ )
+
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ format is not serialization.PrivateFormat.Raw or
+ encoding is not serialization.Encoding.Raw or not
+ isinstance(encryption_algorithm, serialization.NoEncryption)
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw "
+ "and encryption_algorithm must be NoEncryption()"
+ )
+
+ return self._raw_private_bytes()
+
+ return self._backend._private_key_bytes(
+ encoding, format, encryption_algorithm, self, self._evp_pkey, None
+ )
+
+ def _raw_private_bytes(self):
+ # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can
+ # switch this to EVP_PKEY_new_raw_private_key
+ # The trick we use here is serializing to a PKCS8 key and just
+ # using the last 32 bytes, which is the key itself.
+ bio = self._backend._create_mem_bio_gc()
+ res = self._backend._lib.i2d_PKCS8PrivateKey_bio(
+ bio, self._evp_pkey,
+ self._backend._ffi.NULL, self._backend._ffi.NULL,
+ 0, self._backend._ffi.NULL, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(res == 1)
+ pkcs8 = self._backend._read_mem_bio(bio)
+ self._backend.openssl_assert(len(pkcs8) == 48)
+ return pkcs8[-_X25519_KEY_SIZE:]
diff --git a/src/cryptography/hazmat/backends/openssl/x448.py b/src/cryptography/hazmat/backends/openssl/x448.py
new file mode 100644
index 00000000..3de35b43
--- /dev/null
+++ b/src/cryptography/hazmat/backends/openssl/x448.py
@@ -0,0 +1,106 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography import utils
+from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric.x448 import (
+ X448PrivateKey, X448PublicKey
+)
+
+_X448_KEY_SIZE = 56
+
+
+@utils.register_interface(X448PublicKey)
+class _X448PublicKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_bytes(self, encoding, format):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ encoding is not serialization.Encoding.Raw or
+ format is not serialization.PublicFormat.Raw
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw"
+ )
+
+ return self._raw_public_bytes()
+
+ return self._backend._public_key_bytes(
+ encoding, format, self, self._evp_pkey, None
+ )
+
+ def _raw_public_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:]
+
+
+@utils.register_interface(X448PrivateKey)
+class _X448PrivateKey(object):
+ def __init__(self, backend, evp_pkey):
+ self._backend = backend
+ self._evp_pkey = evp_pkey
+
+ def public_key(self):
+ buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_public_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
+ return self._backend.x448_load_public_bytes(buf)
+
+ def exchange(self, peer_public_key):
+ if not isinstance(peer_public_key, X448PublicKey):
+ raise TypeError("peer_public_key must be X448PublicKey.")
+
+ return _evp_pkey_derive(
+ self._backend, self._evp_pkey, peer_public_key
+ )
+
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ if (
+ encoding is serialization.Encoding.Raw or
+ format is serialization.PublicFormat.Raw
+ ):
+ if (
+ format is not serialization.PrivateFormat.Raw or
+ encoding is not serialization.Encoding.Raw or not
+ isinstance(encryption_algorithm, serialization.NoEncryption)
+ ):
+ raise ValueError(
+ "When using Raw both encoding and format must be Raw "
+ "and encryption_algorithm must be NoEncryption()"
+ )
+
+ return self._raw_private_bytes()
+
+ return self._backend._private_key_bytes(
+ encoding, format, encryption_algorithm, self, self._evp_pkey, None
+ )
+
+ def _raw_private_bytes(self):
+ buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE)
+ buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE)
+ res = self._backend._lib.EVP_PKEY_get_raw_private_key(
+ self._evp_pkey, buf, buflen
+ )
+ self._backend.openssl_assert(res == 1)
+ self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE)
+ return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:]
diff --git a/src/cryptography/hazmat/backends/openssl/x509.py b/src/cryptography/hazmat/backends/openssl/x509.py
index a03414c8..efbb1793 100644
--- a/src/cryptography/hazmat/backends/openssl/x509.py
+++ b/src/cryptography/hazmat/backends/openssl/x509.py
@@ -5,152 +5,21 @@
from __future__ import absolute_import, division, print_function
import datetime
-import ipaddress
-from email.utils import parseaddr
-
-import idna
-
-import six
-
-from six.moves import urllib_parse
+import operator
from cryptography import utils, x509
from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.backends.openssl.decode_asn1 import (
+ _CERTIFICATE_EXTENSION_PARSER, _CERTIFICATE_EXTENSION_PARSER_NO_SCT,
+ _CRL_EXTENSION_PARSER, _CSR_EXTENSION_PARSER,
+ _REVOKED_CERTIFICATE_EXTENSION_PARSER, _asn1_integer_to_int,
+ _asn1_string_to_bytes, _decode_x509_name, _obj2txt, _parse_asn1_time
+)
+from cryptography.hazmat.backends.openssl.encode_asn1 import (
+ _encode_asn1_int_gc
+)
from cryptography.hazmat.primitives import hashes, serialization
-
-
-def _obj2txt(backend, obj):
- # Set to 80 on the recommendation of
- # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values
- buf_len = 80
- buf = backend._ffi.new("char[]", buf_len)
- res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1)
- assert res > 0
- return backend._ffi.buffer(buf, res)[:].decode()
-
-
-def _asn1_integer_to_int(backend, asn1_int):
- bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL)
- assert bn != backend._ffi.NULL
- bn = backend._ffi.gc(bn, backend._lib.BN_free)
- return backend._bn_to_int(bn)
-
-
-def _asn1_string_to_utf8(backend, asn1_string):
- buf = backend._ffi.new("unsigned char **")
- res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string)
- assert res >= 0
- assert buf[0] != backend._ffi.NULL
- buf = backend._ffi.gc(
- buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0])
- )
- return backend._ffi.buffer(buf[0], res)[:].decode('utf8')
-
-
-def _decode_x509_name_entry(backend, x509_name_entry):
- obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry)
- assert obj != backend._ffi.NULL
- data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry)
- assert data != backend._ffi.NULL
- value = _asn1_string_to_utf8(backend, data)
- oid = _obj2txt(backend, obj)
-
- return x509.NameAttribute(x509.ObjectIdentifier(oid), value)
-
-
-def _decode_x509_name(backend, x509_name):
- count = backend._lib.X509_NAME_entry_count(x509_name)
- attributes = []
- for x in range(count):
- entry = backend._lib.X509_NAME_get_entry(x509_name, x)
- attributes.append(_decode_x509_name_entry(backend, entry))
-
- return x509.Name(attributes)
-
-
-def _decode_general_names(backend, gns):
- num = backend._lib.sk_GENERAL_NAME_num(gns)
- names = []
- for i in range(num):
- gn = backend._lib.sk_GENERAL_NAME_value(gns, i)
- assert gn != backend._ffi.NULL
- names.append(_decode_general_name(backend, gn))
-
- return names
-
-
-def _decode_general_name(backend, gn):
- if gn.type == backend._lib.GEN_DNS:
- data = backend._ffi.buffer(gn.d.dNSName.data, gn.d.dNSName.length)[:]
- return x509.DNSName(idna.decode(data))
- elif gn.type == backend._lib.GEN_URI:
- data = backend._ffi.buffer(
- gn.d.uniformResourceIdentifier.data,
- gn.d.uniformResourceIdentifier.length
- )[:].decode("ascii")
- parsed = urllib_parse.urlparse(data)
- hostname = idna.decode(parsed.hostname)
- if parsed.port:
- netloc = hostname + u":" + six.text_type(parsed.port)
- else:
- netloc = hostname
-
- # Note that building a URL in this fashion means it should be
- # semantically indistinguishable from the original but is not
- # guaranteed to be exactly the same.
- uri = urllib_parse.urlunparse((
- parsed.scheme,
- netloc,
- parsed.path,
- parsed.params,
- parsed.query,
- parsed.fragment
- ))
- return x509.UniformResourceIdentifier(uri)
- elif gn.type == backend._lib.GEN_RID:
- oid = _obj2txt(backend, gn.d.registeredID)
- return x509.RegisteredID(x509.ObjectIdentifier(oid))
- elif gn.type == backend._lib.GEN_IPADD:
- return x509.IPAddress(
- ipaddress.ip_address(
- backend._ffi.buffer(
- gn.d.iPAddress.data, gn.d.iPAddress.length
- )[:]
- )
- )
- elif gn.type == backend._lib.GEN_DIRNAME:
- return x509.DirectoryName(
- _decode_x509_name(backend, gn.d.directoryName)
- )
- elif gn.type == backend._lib.GEN_EMAIL:
- data = backend._ffi.buffer(
- gn.d.rfc822Name.data, gn.d.rfc822Name.length
- )[:].decode("ascii")
- name, address = parseaddr(data)
- parts = address.split(u"@")
- if name or len(parts) > 2 or not address:
- # parseaddr has found a name (e.g. Name <email>) or the split
- # has found more than 2 parts (which means more than one @ sign)
- # or the entire value is an empty string.
- raise ValueError("Invalid rfc822name value")
- elif len(parts) == 1:
- # Single label email name. This is valid for local delivery. No
- # IDNA decoding can be done since there is no domain component.
- return x509.RFC822Name(address)
- else:
- # A normal email of the form user@domain.com. Let's attempt to
- # decode the domain component and return the entire address.
- return x509.RFC822Name(
- parts[0] + u"@" + idna.decode(parts[1])
- )
- else:
- # otherName, x400Address or ediPartyName
- raise x509.UnsupportedGeneralNameType(
- "{0} is not a supported type".format(
- x509._GENERAL_NAMES.get(gn.type, gn.type)
- ),
- gn.type
- )
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
@utils.register_interface(x509.Certificate)
@@ -160,7 +29,7 @@ class _Certificate(object):
self._x509 = x509
def __repr__(self):
- return "<Certificate(subject={0}, ...)>".format(self.subject)
+ return "<Certificate(subject={}, ...)>".format(self.subject)
def __eq__(self, other):
if not isinstance(other, x509.Certificate):
@@ -172,15 +41,12 @@ class _Certificate(object):
def __ne__(self, other):
return not self == other
+ def __hash__(self):
+ return hash(self.public_bytes(serialization.Encoding.DER))
+
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
- bio = self._backend._create_mem_bio()
- res = self._backend._lib.i2d_X509_bio(
- bio, self._x509
- )
- assert res == 1
- der = self._backend._read_mem_bio(bio)
- h.update(der)
+ h.update(self.public_bytes(serialization.Encoding.DER))
return h.finalize()
@property
@@ -192,476 +58,320 @@ class _Certificate(object):
return x509.Version.v3
else:
raise x509.InvalidVersion(
- "{0} is not a valid X509 version".format(version), version
+ "{} is not a valid X509 version".format(version), version
)
@property
- def serial(self):
+ def serial_number(self):
asn1_int = self._backend._lib.X509_get_serialNumber(self._x509)
- assert asn1_int != self._backend._ffi.NULL
+ self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return _asn1_integer_to_int(self._backend, asn1_int)
def public_key(self):
pkey = self._backend._lib.X509_get_pubkey(self._x509)
- assert pkey != self._backend._ffi.NULL
+ if pkey == self._backend._ffi.NULL:
+ # Remove errors from the stack.
+ self._backend._consume_errors()
+ raise ValueError("Certificate public key is of an unknown type")
+
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def not_valid_before(self):
- asn1_time = self._backend._lib.X509_get_notBefore(self._x509)
- return self._parse_asn1_time(asn1_time)
+ asn1_time = self._backend._lib.X509_getm_notBefore(self._x509)
+ return _parse_asn1_time(self._backend, asn1_time)
@property
def not_valid_after(self):
- asn1_time = self._backend._lib.X509_get_notAfter(self._x509)
- return self._parse_asn1_time(asn1_time)
-
- def _parse_asn1_time(self, asn1_time):
- assert asn1_time != self._backend._ffi.NULL
- generalized_time = self._backend._lib.ASN1_TIME_to_generalizedtime(
- asn1_time, self._backend._ffi.NULL
- )
- assert generalized_time != self._backend._ffi.NULL
- generalized_time = self._backend._ffi.gc(
- generalized_time, self._backend._lib.ASN1_GENERALIZEDTIME_free
- )
- time = self._backend._ffi.string(
- self._backend._lib.ASN1_STRING_data(
- self._backend._ffi.cast("ASN1_STRING *", generalized_time)
- )
- ).decode("ascii")
- return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ")
+ asn1_time = self._backend._lib.X509_getm_notAfter(self._x509)
+ return _parse_asn1_time(self._backend, asn1_time)
@property
def issuer(self):
issuer = self._backend._lib.X509_get_issuer_name(self._x509)
- assert issuer != self._backend._ffi.NULL
+ self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@property
def subject(self):
subject = self._backend._lib.X509_get_subject_name(self._x509)
- assert subject != self._backend._ffi.NULL
+ self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
- oid = _obj2txt(self._backend, self._x509.sig_alg.algorithm)
+ oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
- "Signature algorithm OID:{0} not recognized".format(oid)
+ "Signature algorithm OID:{} not recognized".format(oid)
)
@property
+ def signature_algorithm_oid(self):
+ alg = self._backend._ffi.new("X509_ALGOR **")
+ self._backend._lib.X509_get0_signature(
+ self._backend._ffi.NULL, alg, self._x509
+ )
+ self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
+ oid = _obj2txt(self._backend, alg[0].algorithm)
+ return x509.ObjectIdentifier(oid)
+
+ @utils.cached_property
def extensions(self):
- extensions = []
- seen_oids = set()
- extcount = self._backend._lib.X509_get_ext_count(self._x509)
- for i in range(0, extcount):
- ext = self._backend._lib.X509_get_ext(self._x509, i)
- assert ext != self._backend._ffi.NULL
- crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
- critical = crit == 1
- oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
- if oid in seen_oids:
- raise x509.DuplicateExtension(
- "Duplicate {0} extension found".format(oid), oid
- )
- elif oid == x509.OID_BASIC_CONSTRAINTS:
- value = _decode_basic_constraints(self._backend, ext)
- elif oid == x509.OID_SUBJECT_KEY_IDENTIFIER:
- value = _decode_subject_key_identifier(self._backend, ext)
- elif oid == x509.OID_KEY_USAGE:
- value = _decode_key_usage(self._backend, ext)
- elif oid == x509.OID_SUBJECT_ALTERNATIVE_NAME:
- value = _decode_subject_alt_name(self._backend, ext)
- elif oid == x509.OID_EXTENDED_KEY_USAGE:
- value = _decode_extended_key_usage(self._backend, ext)
- elif oid == x509.OID_AUTHORITY_KEY_IDENTIFIER:
- value = _decode_authority_key_identifier(self._backend, ext)
- elif oid == x509.OID_AUTHORITY_INFORMATION_ACCESS:
- value = _decode_authority_information_access(
- self._backend, ext
- )
- elif oid == x509.OID_CERTIFICATE_POLICIES:
- value = _decode_certificate_policies(self._backend, ext)
- elif oid == x509.OID_CRL_DISTRIBUTION_POINTS:
- value = _decode_crl_distribution_points(self._backend, ext)
- elif oid == x509.OID_OCSP_NO_CHECK:
- value = x509.OCSPNoCheck()
- elif oid == x509.OID_INHIBIT_ANY_POLICY:
- value = _decode_inhibit_any_policy(self._backend, ext)
- elif oid == x509.OID_ISSUER_ALTERNATIVE_NAME:
- value = _decode_issuer_alt_name(self._backend, ext)
- elif critical:
- raise x509.UnsupportedExtension(
- "{0} is not currently supported".format(oid), oid
- )
- else:
- # Unsupported non-critical extension, silently skipping for now
- seen_oids.add(oid)
- continue
+ if self._backend._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER:
+ return _CERTIFICATE_EXTENSION_PARSER.parse(
+ self._backend, self._x509
+ )
+ else:
+ return _CERTIFICATE_EXTENSION_PARSER_NO_SCT.parse(
+ self._backend, self._x509
+ )
- seen_oids.add(oid)
- extensions.append(x509.Extension(oid, critical, value))
+ @property
+ def signature(self):
+ sig = self._backend._ffi.new("ASN1_BIT_STRING **")
+ self._backend._lib.X509_get0_signature(
+ sig, self._backend._ffi.NULL, self._x509
+ )
+ self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
+ return _asn1_string_to_bytes(self._backend, sig[0])
- return x509.Extensions(extensions)
+ @property
+ def tbs_certificate_bytes(self):
+ pp = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp)
+ self._backend.openssl_assert(res > 0)
+ pp = self._backend._ffi.gc(
+ pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
+ )
+ return self._backend._ffi.buffer(pp[0], res)[:]
def public_bytes(self, encoding):
- if not isinstance(encoding, serialization.Encoding):
- raise TypeError("encoding must be an item from the Encoding enum")
-
- bio = self._backend._create_mem_bio()
+ bio = self._backend._create_mem_bio_gc()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509(bio, self._x509)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_bio(bio, self._x509)
- assert res == 1
+ else:
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
-def _decode_certificate_policies(backend, ext):
- cp = backend._ffi.cast(
- "Cryptography_STACK_OF_POLICYINFO *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert cp != backend._ffi.NULL
- cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free)
- num = backend._lib.sk_POLICYINFO_num(cp)
- certificate_policies = []
- for i in range(num):
- qualifiers = None
- pi = backend._lib.sk_POLICYINFO_value(cp, i)
- oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid))
- if pi.qualifiers != backend._ffi.NULL:
- qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers)
- qualifiers = []
- for j in range(qnum):
- pqi = backend._lib.sk_POLICYQUALINFO_value(
- pi.qualifiers, j
- )
- pqualid = x509.ObjectIdentifier(
- _obj2txt(backend, pqi.pqualid)
- )
- if pqualid == x509.OID_CPS_QUALIFIER:
- cpsuri = backend._ffi.buffer(
- pqi.d.cpsuri.data, pqi.d.cpsuri.length
- )[:].decode('ascii')
- qualifiers.append(cpsuri)
- elif pqualid == x509.OID_CPS_USER_NOTICE:
- user_notice = _decode_user_notice(
- backend, pqi.d.usernotice
- )
- qualifiers.append(user_notice)
-
- certificate_policies.append(
- x509.PolicyInformation(oid, qualifiers)
+@utils.register_interface(x509.RevokedCertificate)
+class _RevokedCertificate(object):
+ def __init__(self, backend, crl, x509_revoked):
+ self._backend = backend
+ # The X509_REVOKED_value is a X509_REVOKED * that has
+ # no reference counting. This means when X509_CRL_free is
+ # called then the CRL and all X509_REVOKED * are freed. Since
+ # you can retain a reference to a single revoked certificate
+ # and let the CRL fall out of scope we need to retain a
+ # private reference to the CRL inside the RevokedCertificate
+ # object to prevent the gc from being called inappropriately.
+ self._crl = crl
+ self._x509_revoked = x509_revoked
+
+ @property
+ def serial_number(self):
+ asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber(
+ self._x509_revoked
)
+ self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
+ return _asn1_integer_to_int(self._backend, asn1_int)
- return x509.CertificatePolicies(certificate_policies)
+ @property
+ def revocation_date(self):
+ return _parse_asn1_time(
+ self._backend,
+ self._backend._lib.X509_REVOKED_get0_revocationDate(
+ self._x509_revoked
+ )
+ )
+ @utils.cached_property
+ def extensions(self):
+ return _REVOKED_CERTIFICATE_EXTENSION_PARSER.parse(
+ self._backend, self._x509_revoked
+ )
-def _decode_user_notice(backend, un):
- explicit_text = None
- notice_reference = None
- if un.exptext != backend._ffi.NULL:
- explicit_text = _asn1_string_to_utf8(backend, un.exptext)
+@utils.register_interface(x509.CertificateRevocationList)
+class _CertificateRevocationList(object):
+ def __init__(self, backend, x509_crl):
+ self._backend = backend
+ self._x509_crl = x509_crl
+
+ def __eq__(self, other):
+ if not isinstance(other, x509.CertificateRevocationList):
+ return NotImplemented
+
+ res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl)
+ return res == 0
+
+ def __ne__(self, other):
+ return not self == other
- if un.noticeref != backend._ffi.NULL:
- organization = _asn1_string_to_utf8(
- backend, un.noticeref.organization
+ def fingerprint(self, algorithm):
+ h = hashes.Hash(algorithm, self._backend)
+ bio = self._backend._create_mem_bio_gc()
+ res = self._backend._lib.i2d_X509_CRL_bio(
+ bio, self._x509_crl
)
+ self._backend.openssl_assert(res == 1)
+ der = self._backend._read_mem_bio(bio)
+ h.update(der)
+ return h.finalize()
- num = backend._lib.sk_ASN1_INTEGER_num(
- un.noticeref.noticenos
+ @utils.cached_property
+ def _sorted_crl(self):
+ # X509_CRL_get0_by_serial sorts in place, which breaks a variety of
+ # things we don't want to break (like iteration and the signature).
+ # Let's dupe it and sort that instead.
+ dup = self._backend._lib.X509_CRL_dup(self._x509_crl)
+ self._backend.openssl_assert(dup != self._backend._ffi.NULL)
+ dup = self._backend._ffi.gc(dup, self._backend._lib.X509_CRL_free)
+ return dup
+
+ def get_revoked_certificate_by_serial_number(self, serial_number):
+ revoked = self._backend._ffi.new("X509_REVOKED **")
+ asn1_int = _encode_asn1_int_gc(self._backend, serial_number)
+ res = self._backend._lib.X509_CRL_get0_by_serial(
+ self._sorted_crl, revoked, asn1_int
)
- notice_numbers = []
- for i in range(num):
- asn1_int = backend._lib.sk_ASN1_INTEGER_value(
- un.noticeref.noticenos, i
+ if res == 0:
+ return None
+ else:
+ self._backend.openssl_assert(
+ revoked[0] != self._backend._ffi.NULL
)
- notice_num = _asn1_integer_to_int(
- backend, asn1_int
+ return _RevokedCertificate(
+ self._backend, self._sorted_crl, revoked[0]
)
- notice_numbers.append(notice_num)
- notice_reference = x509.NoticeReference(
- organization, notice_numbers
- )
+ @property
+ def signature_hash_algorithm(self):
+ oid = self.signature_algorithm_oid
+ try:
+ return x509._SIG_OIDS_TO_HASH[oid]
+ except KeyError:
+ raise UnsupportedAlgorithm(
+ "Signature algorithm OID:{} not recognized".format(oid)
+ )
- return x509.UserNotice(notice_reference, explicit_text)
-
-
-def _decode_basic_constraints(backend, ext):
- bc_st = backend._lib.X509V3_EXT_d2i(ext)
- assert bc_st != backend._ffi.NULL
- basic_constraints = backend._ffi.cast(
- "BASIC_CONSTRAINTS *", bc_st
- )
- basic_constraints = backend._ffi.gc(
- basic_constraints, backend._lib.BASIC_CONSTRAINTS_free
- )
- # The byte representation of an ASN.1 boolean true is \xff. OpenSSL
- # chooses to just map this to its ordinal value, so true is 255 and
- # false is 0.
- ca = basic_constraints.ca == 255
- if basic_constraints.pathlen == backend._ffi.NULL:
- path_length = None
- else:
- path_length = _asn1_integer_to_int(
- backend, basic_constraints.pathlen
+ @property
+ def signature_algorithm_oid(self):
+ alg = self._backend._ffi.new("X509_ALGOR **")
+ self._backend._lib.X509_CRL_get0_signature(
+ self._x509_crl, self._backend._ffi.NULL, alg
)
+ self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
+ oid = _obj2txt(self._backend, alg[0].algorithm)
+ return x509.ObjectIdentifier(oid)
+
+ @property
+ def issuer(self):
+ issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl)
+ self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
+ return _decode_x509_name(self._backend, issuer)
- return x509.BasicConstraints(ca, path_length)
-
-
-def _decode_subject_key_identifier(backend, ext):
- asn1_string = backend._lib.X509V3_EXT_d2i(ext)
- assert asn1_string != backend._ffi.NULL
- asn1_string = backend._ffi.cast(
- "ASN1_OCTET_STRING *", asn1_string
- )
- asn1_string = backend._ffi.gc(
- asn1_string, backend._lib.ASN1_OCTET_STRING_free
- )
- return x509.SubjectKeyIdentifier(
- backend._ffi.buffer(asn1_string.data, asn1_string.length)[:]
- )
-
-
-def _decode_authority_key_identifier(backend, ext):
- akid = backend._lib.X509V3_EXT_d2i(ext)
- assert akid != backend._ffi.NULL
- akid = backend._ffi.cast("AUTHORITY_KEYID *", akid)
- akid = backend._ffi.gc(
- akid, backend._lib.AUTHORITY_KEYID_free
- )
- key_identifier = None
- authority_cert_issuer = None
- authority_cert_serial_number = None
-
- if akid.keyid != backend._ffi.NULL:
- key_identifier = backend._ffi.buffer(
- akid.keyid.data, akid.keyid.length
- )[:]
-
- if akid.issuer != backend._ffi.NULL:
- authority_cert_issuer = _decode_general_names(
- backend, akid.issuer
+ @property
+ def next_update(self):
+ nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl)
+ self._backend.openssl_assert(nu != self._backend._ffi.NULL)
+ return _parse_asn1_time(self._backend, nu)
+
+ @property
+ def last_update(self):
+ lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl)
+ self._backend.openssl_assert(lu != self._backend._ffi.NULL)
+ return _parse_asn1_time(self._backend, lu)
+
+ @property
+ def signature(self):
+ sig = self._backend._ffi.new("ASN1_BIT_STRING **")
+ self._backend._lib.X509_CRL_get0_signature(
+ self._x509_crl, sig, self._backend._ffi.NULL
)
+ self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
+ return _asn1_string_to_bytes(self._backend, sig[0])
- if akid.serial != backend._ffi.NULL:
- authority_cert_serial_number = _asn1_integer_to_int(
- backend, akid.serial
+ @property
+ def tbs_certlist_bytes(self):
+ pp = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp)
+ self._backend.openssl_assert(res > 0)
+ pp = self._backend._ffi.gc(
+ pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
)
+ return self._backend._ffi.buffer(pp[0], res)[:]
- return x509.AuthorityKeyIdentifier(
- key_identifier, authority_cert_issuer, authority_cert_serial_number
- )
-
-
-def _decode_authority_information_access(backend, ext):
- aia = backend._lib.X509V3_EXT_d2i(ext)
- assert aia != backend._ffi.NULL
- aia = backend._ffi.cast(
- "Cryptography_STACK_OF_ACCESS_DESCRIPTION *", aia
- )
- aia = backend._ffi.gc(
- aia, backend._lib.sk_ACCESS_DESCRIPTION_free
- )
- num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
- access_descriptions = []
- for i in range(num):
- ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
- assert ad.method != backend._ffi.NULL
- oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method))
- assert ad.location != backend._ffi.NULL
- gn = _decode_general_name(backend, ad.location)
- access_descriptions.append(x509.AccessDescription(oid, gn))
-
- return x509.AuthorityInformationAccess(access_descriptions)
-
-
-def _decode_key_usage(backend, ext):
- bit_string = backend._lib.X509V3_EXT_d2i(ext)
- assert bit_string != backend._ffi.NULL
- bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string)
- bit_string = backend._ffi.gc(
- bit_string, backend._lib.ASN1_BIT_STRING_free
- )
- get_bit = backend._lib.ASN1_BIT_STRING_get_bit
- digital_signature = get_bit(bit_string, 0) == 1
- content_commitment = get_bit(bit_string, 1) == 1
- key_encipherment = get_bit(bit_string, 2) == 1
- data_encipherment = get_bit(bit_string, 3) == 1
- key_agreement = get_bit(bit_string, 4) == 1
- key_cert_sign = get_bit(bit_string, 5) == 1
- crl_sign = get_bit(bit_string, 6) == 1
- encipher_only = get_bit(bit_string, 7) == 1
- decipher_only = get_bit(bit_string, 8) == 1
- return x509.KeyUsage(
- digital_signature,
- content_commitment,
- key_encipherment,
- data_encipherment,
- key_agreement,
- key_cert_sign,
- crl_sign,
- encipher_only,
- decipher_only
- )
-
-
-def _decode_general_names_extension(backend, ext):
- gns = backend._ffi.cast(
- "GENERAL_NAMES *", backend._lib.X509V3_EXT_d2i(ext)
- )
- assert gns != backend._ffi.NULL
- gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free)
- general_names = _decode_general_names(backend, gns)
- return general_names
-
-
-def _decode_subject_alt_name(backend, ext):
- return x509.SubjectAlternativeName(
- _decode_general_names_extension(backend, ext)
- )
-
-
-def _decode_issuer_alt_name(backend, ext):
- return x509.IssuerAlternativeName(
- _decode_general_names_extension(backend, ext)
- )
-
-
-def _decode_extended_key_usage(backend, ext):
- sk = backend._ffi.cast(
- "Cryptography_STACK_OF_ASN1_OBJECT *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert sk != backend._ffi.NULL
- sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free)
- num = backend._lib.sk_ASN1_OBJECT_num(sk)
- ekus = []
-
- for i in range(num):
- obj = backend._lib.sk_ASN1_OBJECT_value(sk, i)
- assert obj != backend._ffi.NULL
- oid = x509.ObjectIdentifier(_obj2txt(backend, obj))
- ekus.append(oid)
-
- return x509.ExtendedKeyUsage(ekus)
-
-
-def _decode_crl_distribution_points(backend, ext):
- cdps = backend._ffi.cast(
- "Cryptography_STACK_OF_DIST_POINT *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert cdps != backend._ffi.NULL
- cdps = backend._ffi.gc(
- cdps, backend._lib.sk_DIST_POINT_free)
- num = backend._lib.sk_DIST_POINT_num(cdps)
-
- dist_points = []
- for i in range(num):
- full_name = None
- relative_name = None
- crl_issuer = None
- reasons = None
- cdp = backend._lib.sk_DIST_POINT_value(cdps, i)
- if cdp.reasons != backend._ffi.NULL:
- # We will check each bit from RFC 5280
- # ReasonFlags ::= BIT STRING {
- # unused (0),
- # keyCompromise (1),
- # cACompromise (2),
- # affiliationChanged (3),
- # superseded (4),
- # cessationOfOperation (5),
- # certificateHold (6),
- # privilegeWithdrawn (7),
- # aACompromise (8) }
- reasons = []
- get_bit = backend._lib.ASN1_BIT_STRING_get_bit
- if get_bit(cdp.reasons, 1):
- reasons.append(x509.ReasonFlags.key_compromise)
-
- if get_bit(cdp.reasons, 2):
- reasons.append(x509.ReasonFlags.ca_compromise)
-
- if get_bit(cdp.reasons, 3):
- reasons.append(x509.ReasonFlags.affiliation_changed)
-
- if get_bit(cdp.reasons, 4):
- reasons.append(x509.ReasonFlags.superseded)
-
- if get_bit(cdp.reasons, 5):
- reasons.append(x509.ReasonFlags.cessation_of_operation)
-
- if get_bit(cdp.reasons, 6):
- reasons.append(x509.ReasonFlags.certificate_hold)
-
- if get_bit(cdp.reasons, 7):
- reasons.append(x509.ReasonFlags.privilege_withdrawn)
-
- if get_bit(cdp.reasons, 8):
- reasons.append(x509.ReasonFlags.aa_compromise)
-
- reasons = frozenset(reasons)
-
- if cdp.CRLissuer != backend._ffi.NULL:
- crl_issuer = _decode_general_names(backend, cdp.CRLissuer)
-
- # Certificates may have a crl_issuer/reasons and no distribution
- # point so make sure it's not null.
- if cdp.distpoint != backend._ffi.NULL:
- # Type 0 is fullName, there is no #define for it in the code.
- if cdp.distpoint.type == 0:
- full_name = _decode_general_names(
- backend, cdp.distpoint.name.fullname
- )
- # OpenSSL code doesn't test for a specific type for
- # relativename, everything that isn't fullname is considered
- # relativename.
- else:
- rns = cdp.distpoint.name.relativename
- rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns)
- attributes = []
- for i in range(rnum):
- rn = backend._lib.sk_X509_NAME_ENTRY_value(
- rns, i
- )
- assert rn != backend._ffi.NULL
- attributes.append(
- _decode_x509_name_entry(backend, rn)
- )
-
- relative_name = x509.Name(attributes)
-
- dist_points.append(
- x509.DistributionPoint(
- full_name, relative_name, reasons, crl_issuer
+ def public_bytes(self, encoding):
+ bio = self._backend._create_mem_bio_gc()
+ if encoding is serialization.Encoding.PEM:
+ res = self._backend._lib.PEM_write_bio_X509_CRL(
+ bio, self._x509_crl
)
- )
+ elif encoding is serialization.Encoding.DER:
+ res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl)
+ else:
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ self._backend.openssl_assert(res == 1)
+ return self._backend._read_mem_bio(bio)
+
+ def _revoked_cert(self, idx):
+ revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
+ r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx)
+ self._backend.openssl_assert(r != self._backend._ffi.NULL)
+ return _RevokedCertificate(self._backend, self, r)
+
+ def __iter__(self):
+ for i in range(len(self)):
+ yield self._revoked_cert(i)
+
+ def __getitem__(self, idx):
+ if isinstance(idx, slice):
+ start, stop, step = idx.indices(len(self))
+ return [self._revoked_cert(i) for i in range(start, stop, step)]
+ else:
+ idx = operator.index(idx)
+ if idx < 0:
+ idx += len(self)
+ if not 0 <= idx < len(self):
+ raise IndexError
+ return self._revoked_cert(idx)
+
+ def __len__(self):
+ revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl)
+ if revoked == self._backend._ffi.NULL:
+ return 0
+ else:
+ return self._backend._lib.sk_X509_REVOKED_num(revoked)
- return x509.CRLDistributionPoints(dist_points)
+ @utils.cached_property
+ def extensions(self):
+ return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl)
+
+ def is_signature_valid(self, public_key):
+ if not isinstance(public_key, (dsa.DSAPublicKey, rsa.RSAPublicKey,
+ ec.EllipticCurvePublicKey)):
+ raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,'
+ ' or EllipticCurvePublicKey.')
+ res = self._backend._lib.X509_CRL_verify(
+ self._x509_crl, public_key._evp_pkey
+ )
+ if res != 1:
+ self._backend._consume_errors()
+ return False
-def _decode_inhibit_any_policy(backend, ext):
- asn1_int = backend._ffi.cast(
- "ASN1_INTEGER *",
- backend._lib.X509V3_EXT_d2i(ext)
- )
- assert asn1_int != backend._ffi.NULL
- asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free)
- skip_certs = _asn1_integer_to_int(backend, asn1_int)
- return x509.InhibitAnyPolicy(skip_certs)
+ return True
@utils.register_interface(x509.CertificateSigningRequest)
@@ -670,70 +380,167 @@ class _CertificateSigningRequest(object):
self._backend = backend
self._x509_req = x509_req
+ def __eq__(self, other):
+ if not isinstance(other, _CertificateSigningRequest):
+ return NotImplemented
+
+ self_bytes = self.public_bytes(serialization.Encoding.DER)
+ other_bytes = other.public_bytes(serialization.Encoding.DER)
+ return self_bytes == other_bytes
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.public_bytes(serialization.Encoding.DER))
+
def public_key(self):
pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
- assert pkey != self._backend._ffi.NULL
+ self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
return self._backend._evp_pkey_to_public_key(pkey)
@property
def subject(self):
subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req)
- assert subject != self._backend._ffi.NULL
+ self._backend.openssl_assert(subject != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, subject)
@property
def signature_hash_algorithm(self):
- oid = _obj2txt(self._backend, self._x509_req.sig_alg.algorithm)
+ oid = self.signature_algorithm_oid
try:
return x509._SIG_OIDS_TO_HASH[oid]
except KeyError:
raise UnsupportedAlgorithm(
- "Signature algorithm OID:{0} not recognized".format(oid)
+ "Signature algorithm OID:{} not recognized".format(oid)
)
@property
+ def signature_algorithm_oid(self):
+ alg = self._backend._ffi.new("X509_ALGOR **")
+ self._backend._lib.X509_REQ_get0_signature(
+ self._x509_req, self._backend._ffi.NULL, alg
+ )
+ self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL)
+ oid = _obj2txt(self._backend, alg[0].algorithm)
+ return x509.ObjectIdentifier(oid)
+
+ @utils.cached_property
def extensions(self):
- extensions = []
- seen_oids = set()
x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req)
- extcount = self._backend._lib.sk_X509_EXTENSION_num(x509_exts)
- for i in range(0, extcount):
- ext = self._backend._lib.sk_X509_EXTENSION_value(x509_exts, i)
- assert ext != self._backend._ffi.NULL
- crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
- critical = crit == 1
- oid = x509.ObjectIdentifier(_obj2txt(self._backend, ext.object))
- if oid in seen_oids:
- raise x509.DuplicateExtension(
- "Duplicate {0} extension found".format(oid), oid
+ x509_exts = self._backend._ffi.gc(
+ x509_exts,
+ lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free(
+ x, self._backend._ffi.addressof(
+ self._backend._lib._original_lib, "X509_EXTENSION_free"
)
- elif oid == x509.OID_BASIC_CONSTRAINTS:
- value = _decode_basic_constraints(self._backend, ext)
- elif critical:
- raise x509.UnsupportedExtension(
- "{0} is not currently supported".format(oid), oid
- )
- else:
- # Unsupported non-critical extension, silently skipping for now
- seen_oids.add(oid)
- continue
-
- seen_oids.add(oid)
- extensions.append(x509.Extension(oid, critical, value))
-
- return x509.Extensions(extensions)
+ )
+ )
+ return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts)
def public_bytes(self, encoding):
- if not isinstance(encoding, serialization.Encoding):
- raise TypeError("encoding must be an item from the Encoding enum")
-
- bio = self._backend._create_mem_bio()
+ bio = self._backend._create_mem_bio_gc()
if encoding is serialization.Encoding.PEM:
res = self._backend._lib.PEM_write_bio_X509_REQ(
bio, self._x509_req
)
elif encoding is serialization.Encoding.DER:
res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req)
- assert res == 1
+ else:
+ raise TypeError("encoding must be an item from the Encoding enum")
+
+ self._backend.openssl_assert(res == 1)
return self._backend._read_mem_bio(bio)
+
+ @property
+ def tbs_certrequest_bytes(self):
+ pp = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.i2d_re_X509_REQ_tbs(self._x509_req, pp)
+ self._backend.openssl_assert(res > 0)
+ pp = self._backend._ffi.gc(
+ pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0])
+ )
+ return self._backend._ffi.buffer(pp[0], res)[:]
+
+ @property
+ def signature(self):
+ sig = self._backend._ffi.new("ASN1_BIT_STRING **")
+ self._backend._lib.X509_REQ_get0_signature(
+ self._x509_req, sig, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL)
+ return _asn1_string_to_bytes(self._backend, sig[0])
+
+ @property
+ def is_signature_valid(self):
+ pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req)
+ self._backend.openssl_assert(pkey != self._backend._ffi.NULL)
+ pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free)
+ res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey)
+
+ if res != 1:
+ self._backend._consume_errors()
+ return False
+
+ return True
+
+
+@utils.register_interface(
+ x509.certificate_transparency.SignedCertificateTimestamp
+)
+class _SignedCertificateTimestamp(object):
+ def __init__(self, backend, sct_list, sct):
+ self._backend = backend
+ # Keep the SCT_LIST that this SCT came from alive.
+ self._sct_list = sct_list
+ self._sct = sct
+
+ @property
+ def version(self):
+ version = self._backend._lib.SCT_get_version(self._sct)
+ assert version == self._backend._lib.SCT_VERSION_V1
+ return x509.certificate_transparency.Version.v1
+
+ @property
+ def log_id(self):
+ out = self._backend._ffi.new("unsigned char **")
+ log_id_length = self._backend._lib.SCT_get0_log_id(self._sct, out)
+ assert log_id_length >= 0
+ return self._backend._ffi.buffer(out[0], log_id_length)[:]
+
+ @property
+ def timestamp(self):
+ timestamp = self._backend._lib.SCT_get_timestamp(self._sct)
+ milliseconds = timestamp % 1000
+ return datetime.datetime.utcfromtimestamp(
+ timestamp // 1000
+ ).replace(microsecond=milliseconds * 1000)
+
+ @property
+ def entry_type(self):
+ entry_type = self._backend._lib.SCT_get_log_entry_type(self._sct)
+ # We currently only support loading SCTs from the X.509 extension, so
+ # we only have precerts.
+ assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT
+ return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE
+
+ @property
+ def _signature(self):
+ ptrptr = self._backend._ffi.new("unsigned char **")
+ res = self._backend._lib.SCT_get0_signature(self._sct, ptrptr)
+ self._backend.openssl_assert(res > 0)
+ self._backend.openssl_assert(ptrptr[0] != self._backend._ffi.NULL)
+ return self._backend._ffi.buffer(ptrptr[0], res)[:]
+
+ def __hash__(self):
+ return hash(self._signature)
+
+ def __eq__(self, other):
+ if not isinstance(other, _SignedCertificateTimestamp):
+ return NotImplemented
+
+ return self._signature == other._signature
+
+ def __ne__(self, other):
+ return not self == other
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/__init__.py b/src/cryptography/hazmat/bindings/commoncrypto/__init__.py
deleted file mode 100644
index 4b540884..00000000
--- a/src/cryptography/hazmat/bindings/commoncrypto/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
diff --git a/src/cryptography/hazmat/bindings/commoncrypto/binding.py b/src/cryptography/hazmat/bindings/commoncrypto/binding.py
deleted file mode 100644
index 1695c041..00000000
--- a/src/cryptography/hazmat/bindings/commoncrypto/binding.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-from cryptography.hazmat.bindings._commoncrypto import ffi, lib
-
-
-class Binding(object):
- """
- CommonCrypto API wrapper.
- """
- lib = lib
- ffi = ffi
-
- def __init__(self):
- pass
diff --git a/src/cryptography/hazmat/bindings/openssl/_conditional.py b/src/cryptography/hazmat/bindings/openssl/_conditional.py
new file mode 100644
index 00000000..3bc879c4
--- /dev/null
+++ b/src/cryptography/hazmat/bindings/openssl/_conditional.py
@@ -0,0 +1,361 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+
+def cryptography_has_ec2m():
+ return [
+ "EC_POINT_set_affine_coordinates_GF2m",
+ "EC_POINT_get_affine_coordinates_GF2m",
+ "EC_POINT_set_compressed_coordinates_GF2m",
+ ]
+
+
+def cryptography_has_rsa_r_pkcs_decoding_error():
+ return [
+ "RSA_R_PKCS_DECODING_ERROR"
+ ]
+
+
+def cryptography_has_rsa_oaep_md():
+ return [
+ "EVP_PKEY_CTX_set_rsa_oaep_md",
+ ]
+
+
+def cryptography_has_rsa_oaep_label():
+ return [
+ "EVP_PKEY_CTX_set0_rsa_oaep_label",
+ ]
+
+
+def cryptography_has_ssl3_method():
+ return [
+ "SSLv3_method",
+ "SSLv3_client_method",
+ "SSLv3_server_method",
+ ]
+
+
+def cryptography_has_compression():
+ return [
+ "SSL_get_current_compression",
+ "SSL_get_current_expansion",
+ "SSL_COMP_get_name",
+ ]
+
+
+def cryptography_has_102_verification():
+ return [
+ '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_FLAG_SUITEB_128_LOS_ONLY",
+ "X509_V_FLAG_SUITEB_192_LOS",
+ "X509_V_FLAG_SUITEB_128_LOS",
+ ]
+
+
+def cryptography_has_110_verification_params():
+ return [
+ "X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"
+ ]
+
+
+def cryptography_has_set_cert_cb():
+ return [
+ "SSL_CTX_set_cert_cb",
+ "SSL_set_cert_cb",
+ ]
+
+
+def cryptography_has_ssl_st():
+ return [
+ "SSL_ST_BEFORE",
+ "SSL_ST_OK",
+ "SSL_ST_INIT",
+ "SSL_ST_RENEGOTIATE",
+ ]
+
+
+def cryptography_has_tls_st():
+ return [
+ "TLS_ST_BEFORE",
+ "TLS_ST_OK",
+ ]
+
+
+def cryptography_has_locking_callbacks():
+ return [
+ "Cryptography_setup_ssl_threads",
+ ]
+
+
+def cryptography_has_scrypt():
+ return [
+ "EVP_PBE_scrypt",
+ ]
+
+
+def cryptography_has_evp_pkey_dhx():
+ return [
+ "EVP_PKEY_DHX",
+ ]
+
+
+def cryptography_has_mem_functions():
+ return [
+ "Cryptography_CRYPTO_set_mem_functions",
+ ]
+
+
+def cryptography_has_sct():
+ return [
+ "SCT_get_version",
+ "SCT_get_log_entry_type",
+ "SCT_get0_log_id",
+ "SCT_get0_signature",
+ "SCT_get_timestamp",
+ "SCT_set_source",
+ "sk_SCT_num",
+ "sk_SCT_value",
+ "SCT_LIST_free",
+ "sk_SCT_push",
+ "sk_SCT_new_null",
+ "SCT_new",
+ "SCT_set1_log_id",
+ "SCT_set_timestamp",
+ "SCT_set_version",
+ "SCT_set_log_entry_type",
+ ]
+
+
+def cryptography_has_x509_store_ctx_get_issuer():
+ return [
+ "X509_STORE_get_get_issuer",
+ "X509_STORE_set_get_issuer",
+ ]
+
+
+def cryptography_has_x25519():
+ return [
+ "EVP_PKEY_X25519",
+ "NID_X25519",
+ ]
+
+
+def cryptography_has_x448():
+ return [
+ "EVP_PKEY_X448",
+ "NID_X448",
+ ]
+
+
+def cryptography_has_ed448():
+ return [
+ "EVP_PKEY_ED448",
+ "NID_ED448",
+ ]
+
+
+def cryptography_has_ed25519():
+ return [
+ "NID_ED25519",
+ "EVP_PKEY_ED25519",
+ ]
+
+
+def cryptography_has_poly1305():
+ return [
+ "NID_poly1305",
+ "EVP_PKEY_POLY1305",
+ ]
+
+
+def cryptography_has_oneshot_evp_digest_sign_verify():
+ return [
+ "EVP_DigestSign",
+ "EVP_DigestVerify",
+ ]
+
+
+def cryptography_has_evp_digestfinal_xof():
+ return [
+ "EVP_DigestFinalXOF",
+ ]
+
+
+def cryptography_has_evp_pkey_get_set_tls_encodedpoint():
+ return [
+ "EVP_PKEY_get1_tls_encodedpoint",
+ "EVP_PKEY_set1_tls_encodedpoint",
+ ]
+
+
+def cryptography_has_fips():
+ return [
+ "FIPS_mode_set",
+ "FIPS_mode",
+ ]
+
+
+def cryptography_has_ssl_sigalgs():
+ return [
+ "SSL_CTX_set1_sigalgs_list",
+ "SSL_get_sigalgs",
+ ]
+
+
+def cryptography_has_psk():
+ return [
+ "SSL_CTX_use_psk_identity_hint",
+ "SSL_CTX_set_psk_server_callback",
+ "SSL_CTX_set_psk_client_callback",
+ ]
+
+
+def cryptography_has_custom_ext():
+ return [
+ "SSL_CTX_add_client_custom_ext",
+ "SSL_CTX_add_server_custom_ext",
+ "SSL_extension_supported",
+ ]
+
+
+def cryptography_has_openssl_cleanup():
+ return [
+ "OPENSSL_cleanup",
+ ]
+
+
+def cryptography_has_cipher_details():
+ return [
+ "SSL_CIPHER_is_aead",
+ "SSL_CIPHER_get_cipher_nid",
+ "SSL_CIPHER_get_digest_nid",
+ "SSL_CIPHER_get_kx_nid",
+ "SSL_CIPHER_get_auth_nid",
+ ]
+
+
+def cryptography_has_tlsv13():
+ return [
+ "SSL_OP_NO_TLSv1_3",
+ "SSL_VERIFY_POST_HANDSHAKE",
+ "SSL_CTX_set_ciphersuites",
+ "SSL_verify_client_post_handshake",
+ "SSL_CTX_set_post_handshake_auth",
+ "SSL_set_post_handshake_auth",
+ "SSL_SESSION_get_max_early_data",
+ "SSL_write_early_data",
+ "SSL_read_early_data",
+ "SSL_CTX_set_max_early_data",
+ ]
+
+
+def cryptography_has_keylog():
+ return [
+ "SSL_CTX_set_keylog_callback",
+ "SSL_CTX_get_keylog_callback",
+ ]
+
+
+def cryptography_has_raw_key():
+ return [
+ "EVP_PKEY_new_raw_private_key",
+ "EVP_PKEY_new_raw_public_key",
+ "EVP_PKEY_get_raw_private_key",
+ "EVP_PKEY_get_raw_public_key",
+ ]
+
+
+def cryptography_has_evp_r_memory_limit_exceeded():
+ return [
+ "EVP_R_MEMORY_LIMIT_EXCEEDED",
+ ]
+
+
+def cryptography_has_engine():
+ return [
+ "ENGINE_by_id",
+ "ENGINE_init",
+ "ENGINE_finish",
+ "ENGINE_get_default_RAND",
+ "ENGINE_set_default_RAND",
+ "ENGINE_unregister_RAND",
+ "ENGINE_ctrl_cmd",
+ "ENGINE_free",
+ "ENGINE_get_name",
+ "Cryptography_add_osrandom_engine",
+ ]
+
+
+def cryptography_has_verified_chain():
+ return [
+ "SSL_get0_verified_chain",
+ ]
+
+
+# This is a mapping of
+# {condition: function-returning-names-dependent-on-that-condition} so we can
+# loop over them and delete unsupported names at runtime. It will be removed
+# when cffi supports #if in cdef. We use functions instead of just a dict of
+# lists so we can use coverage to measure which are used.
+CONDITIONAL_NAMES = {
+ "Cryptography_HAS_EC2M": cryptography_has_ec2m,
+ "Cryptography_HAS_RSA_R_PKCS_DECODING_ERROR": (
+ cryptography_has_rsa_r_pkcs_decoding_error
+ ),
+ "Cryptography_HAS_RSA_OAEP_MD": cryptography_has_rsa_oaep_md,
+ "Cryptography_HAS_RSA_OAEP_LABEL": cryptography_has_rsa_oaep_label,
+ "Cryptography_HAS_SSL3_METHOD": cryptography_has_ssl3_method,
+ "Cryptography_HAS_COMPRESSION": cryptography_has_compression,
+ "Cryptography_HAS_102_VERIFICATION": cryptography_has_102_verification,
+ "Cryptography_HAS_110_VERIFICATION_PARAMS": (
+ cryptography_has_110_verification_params
+ ),
+ "Cryptography_HAS_SET_CERT_CB": cryptography_has_set_cert_cb,
+ "Cryptography_HAS_SSL_ST": cryptography_has_ssl_st,
+ "Cryptography_HAS_TLS_ST": cryptography_has_tls_st,
+ "Cryptography_HAS_LOCKING_CALLBACKS": cryptography_has_locking_callbacks,
+ "Cryptography_HAS_SCRYPT": cryptography_has_scrypt,
+ "Cryptography_HAS_EVP_PKEY_DHX": cryptography_has_evp_pkey_dhx,
+ "Cryptography_HAS_MEM_FUNCTIONS": cryptography_has_mem_functions,
+ "Cryptography_HAS_SCT": cryptography_has_sct,
+ "Cryptography_HAS_X509_STORE_CTX_GET_ISSUER": (
+ cryptography_has_x509_store_ctx_get_issuer
+ ),
+ "Cryptography_HAS_X25519": cryptography_has_x25519,
+ "Cryptography_HAS_X448": cryptography_has_x448,
+ "Cryptography_HAS_ED448": cryptography_has_ed448,
+ "Cryptography_HAS_ED25519": cryptography_has_ed25519,
+ "Cryptography_HAS_POLY1305": cryptography_has_poly1305,
+ "Cryptography_HAS_ONESHOT_EVP_DIGEST_SIGN_VERIFY": (
+ cryptography_has_oneshot_evp_digest_sign_verify
+ ),
+ "Cryptography_HAS_EVP_PKEY_get_set_tls_encodedpoint": (
+ cryptography_has_evp_pkey_get_set_tls_encodedpoint
+ ),
+ "Cryptography_HAS_FIPS": cryptography_has_fips,
+ "Cryptography_HAS_SIGALGS": cryptography_has_ssl_sigalgs,
+ "Cryptography_HAS_PSK": cryptography_has_psk,
+ "Cryptography_HAS_CUSTOM_EXT": cryptography_has_custom_ext,
+ "Cryptography_HAS_OPENSSL_CLEANUP": cryptography_has_openssl_cleanup,
+ "Cryptography_HAS_CIPHER_DETAILS": cryptography_has_cipher_details,
+ "Cryptography_HAS_TLSv1_3": cryptography_has_tlsv13,
+ "Cryptography_HAS_KEYLOG": cryptography_has_keylog,
+ "Cryptography_HAS_RAW_KEY": cryptography_has_raw_key,
+ "Cryptography_HAS_EVP_DIGESTFINAL_XOF": (
+ cryptography_has_evp_digestfinal_xof
+ ),
+ "Cryptography_HAS_EVP_R_MEMORY_LIMIT_EXCEEDED": (
+ cryptography_has_evp_r_memory_limit_exceeded
+ ),
+ "Cryptography_HAS_ENGINE": cryptography_has_engine,
+ "Cryptography_HAS_VERIFIED_CHAIN": cryptography_has_verified_chain,
+}
diff --git a/src/cryptography/hazmat/bindings/openssl/binding.py b/src/cryptography/hazmat/bindings/openssl/binding.py
index 35ea4979..4e23cd53 100644
--- a/src/cryptography/hazmat/bindings/openssl/binding.py
+++ b/src/cryptography/hazmat/bindings/openssl/binding.py
@@ -4,140 +4,178 @@
from __future__ import absolute_import, division, print_function
-import os
+import collections
import threading
+import types
+import cryptography
+from cryptography import utils
+from cryptography.exceptions import InternalError
from cryptography.hazmat.bindings._openssl import ffi, lib
+from cryptography.hazmat.bindings.openssl._conditional import CONDITIONAL_NAMES
+
+_OpenSSLErrorWithText = collections.namedtuple(
+ "_OpenSSLErrorWithText", ["code", "lib", "func", "reason", "reason_text"]
+)
+
+
+class _OpenSSLError(object):
+ def __init__(self, code, lib, func, reason):
+ self._code = code
+ self._lib = lib
+ self._func = func
+ self._reason = reason
+
+ def _lib_reason_match(self, lib, reason):
+ return lib == self.lib and reason == self.reason
+
+ code = utils.read_only_property("_code")
+ lib = utils.read_only_property("_lib")
+ func = utils.read_only_property("_func")
+ reason = utils.read_only_property("_reason")
+
+
+def _consume_errors(lib):
+ errors = []
+ while True:
+ code = lib.ERR_get_error()
+ if code == 0:
+ break
+
+ err_lib = lib.ERR_GET_LIB(code)
+ err_func = lib.ERR_GET_FUNC(code)
+ err_reason = lib.ERR_GET_REASON(code)
+
+ errors.append(_OpenSSLError(code, err_lib, err_func, err_reason))
+
+ return errors
+
+
+def _openssl_assert(lib, ok):
+ if not ok:
+ errors = _consume_errors(lib)
+ errors_with_text = []
+ for err in errors:
+ buf = ffi.new("char[]", 256)
+ lib.ERR_error_string_n(err.code, buf, len(buf))
+ err_text_reason = ffi.string(buf)
+
+ errors_with_text.append(
+ _OpenSSLErrorWithText(
+ err.code, err.lib, err.func, err.reason, err_text_reason
+ )
+ )
+
+ raise InternalError(
+ "Unknown OpenSSL error. This error is commonly encountered when "
+ "another library is not cleaning up the OpenSSL error stack. If "
+ "you are using cryptography with another library that uses "
+ "OpenSSL try disabling it before reporting a bug. Otherwise "
+ "please file an issue at https://github.com/pyca/cryptography/"
+ "issues with information on how to reproduce "
+ "this. ({0!r})".format(errors_with_text),
+ errors_with_text
+ )
+
+
+def build_conditional_library(lib, conditional_names):
+ conditional_lib = types.ModuleType("lib")
+ conditional_lib._original_lib = lib
+ excluded_names = set()
+ for condition, names_cb in conditional_names.items():
+ if not getattr(lib, condition):
+ excluded_names.update(names_cb())
+
+ for attr in dir(lib):
+ if attr not in excluded_names:
+ setattr(conditional_lib, attr, getattr(lib, attr))
+
+ return conditional_lib
class Binding(object):
"""
OpenSSL API wrapper.
"""
- lib = lib
+ lib = None
ffi = ffi
_lib_loaded = False
- _locks = None
- _lock_cb_handle = None
- _rand_method = None
_init_lock = threading.Lock()
_lock_init_lock = threading.Lock()
- _osrandom_engine_id = ffi.new("const char[]", b"osrandom")
- _osrandom_engine_name = ffi.new("const char[]", b"osrandom_engine")
- _retained = []
def __init__(self):
self._ensure_ffi_initialized()
@classmethod
- def _ensure_ffi_initialized(cls):
- if cls._lib_loaded:
- return
+ def _register_osrandom_engine(cls):
+ # Clear any errors extant in the queue before we start. In many
+ # scenarios other things may be interacting with OpenSSL in the same
+ # process space and it has proven untenable to assume that they will
+ # reliably clear the error queue. Once we clear it here we will
+ # error on any subsequent unexpected item in the stack.
+ cls.lib.ERR_clear_error()
+ if cls.lib.Cryptography_HAS_ENGINE:
+ result = cls.lib.Cryptography_add_osrandom_engine()
+ _openssl_assert(cls.lib, result in (1, 2))
+ @classmethod
+ def _ensure_ffi_initialized(cls):
with cls._init_lock:
if not cls._lib_loaded:
+ cls.lib = build_conditional_library(lib, CONDITIONAL_NAMES)
cls._lib_loaded = True
- res = cls._register_osrandom_engine()
- assert res != 0
-
- @classmethod
- def _register_osrandom_engine(cls):
- if cls._retained:
- return 2
-
- def retain(it):
- cls._retained.append(it)
- return it
- method = cls.ffi.new("RAND_METHOD*")
- retain(method)
- method.seed = cls.ffi.NULL
-
- @retain
- @cls.ffi.callback("int (*)(unsigned char *buf, int num)", error=0)
- def osrandom_rand_bytes(buf, size):
- signed = cls.ffi.cast("char*", buf)
- result = os.urandom(size)
- signed[0:size] = result
- return 1
-
- @retain
- @cls.ffi.callback("int (*)(unsigned char *buf, int num)", error=0)
- def osrandom_pseudo_rand_bytes(buf, size):
- result = osrandom_rand_bytes(buf, size)
- if result == 0:
- return -1
- else:
- return result
-
- @retain
- @cls.ffi.callback("int (*)(void)", error=0)
- def osrandom_rand_status():
- return 1
-
- @retain
- @cls.ffi.callback("ENGINE_GEN_INT_FUNC_PTR", error=0)
- def osrandom_init(engine):
- return 1
-
- @retain
- @cls.ffi.callback("ENGINE_GEN_INT_FUNC_PTR", error=0)
- def osrandom_finish(engine):
- return 1
-
- method.bytes = osrandom_rand_bytes
- method.cleanup = cls.ffi.NULL
- method.add = cls.ffi.NULL
- method.pseudorand = osrandom_pseudo_rand_bytes
- method.status = osrandom_rand_status
-
- e = cls.lib.ENGINE_new()
- result = (cls.lib.ENGINE_set_id(e, cls._osrandom_engine_id)
- and cls.lib.ENGINE_set_name(e, cls._osrandom_engine_name)
- and cls.lib.ENGINE_set_RAND(e, method)
- and cls.lib.ENGINE_set_init_function(e, osrandom_init)
- and cls.lib.ENGINE_set_finish_function(e, osrandom_finish)
- and cls.lib.ENGINE_add(e))
- if not cls.lib.ENGINE_free(e):
- return 0
- assert cls.lib.ENGINE_by_id(cls._osrandom_engine_id) != cls.ffi.NULL
- return result
+ # initialize the SSL library
+ cls.lib.SSL_library_init()
+ # adds all ciphers/digests for EVP
+ cls.lib.OpenSSL_add_all_algorithms()
+ # loads error strings for libcrypto and libssl functions
+ cls.lib.SSL_load_error_strings()
+ cls._register_osrandom_engine()
@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:
+ if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or
+ 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)]
+ res = lib.Cryptography_setup_ssl_threads()
+ _openssl_assert(cls.lib, res == 1)
+
+
+def _verify_package_version(version):
+ # Occasionally we run into situations where the version of the Python
+ # package does not match the version of the shared object that is loaded.
+ # This may occur in environments where multiple versions of cryptography
+ # are installed and available in the python path. To avoid errors cropping
+ # up later this code checks that the currently imported package and the
+ # shared object that were loaded have the same version and raise an
+ # ImportError if they do not
+ so_package_version = ffi.string(lib.CRYPTOGRAPHY_PACKAGE_VERSION)
+ if version.encode("ascii") != so_package_version:
+ raise ImportError(
+ "The version of cryptography does not match the loaded "
+ "shared object. This can happen if you have multiple copies of "
+ "cryptography installed in your Python path. Please try creating "
+ "a new virtual environment to resolve this issue. "
+ "Loaded python version: {}, shared object version: {}".format(
+ version, so_package_version
+ )
+ )
- 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
- )
- )
+_verify_package_version(cryptography.__version__)
+
+# OpenSSL is not thread safe until the locks are initialized. We call this
+# method in module scope so that it executes with the import lock. On
+# Pythons < 3.4 this import lock is a global lock, which can prevent a race
+# condition registering the OpenSSL locks. On Python 3.4+ the import lock
+# is per module so this approach will not work.
+Binding.init_static_locks()
diff --git a/src/cryptography/hazmat/primitives/asymmetric/dh.py b/src/cryptography/hazmat/primitives/asymmetric/dh.py
index 12d53eed..4fc99524 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/dh.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/dh.py
@@ -11,6 +11,10 @@ import six
from cryptography import utils
+def generate_parameters(generator, key_size, backend):
+ return backend.generate_dh_parameters(generator, key_size)
+
+
class DHPrivateNumbers(object):
def __init__(self, x, public_numbers):
if not isinstance(x, six.integer_types):
@@ -35,6 +39,9 @@ class DHPrivateNumbers(object):
def __ne__(self, other):
return not self == other
+ def private_key(self, backend):
+ return backend.load_dh_private_numbers(self)
+
public_numbers = utils.read_only_property("_public_numbers")
x = utils.read_only_property("_x")
@@ -63,20 +70,29 @@ class DHPublicNumbers(object):
def __ne__(self, other):
return not self == other
+ def public_key(self, backend):
+ return backend.load_dh_public_numbers(self)
+
y = utils.read_only_property("_y")
parameter_numbers = utils.read_only_property("_parameter_numbers")
class DHParameterNumbers(object):
- def __init__(self, p, g):
+ def __init__(self, p, g, q=None):
if (
not isinstance(p, six.integer_types) or
not isinstance(g, six.integer_types)
):
raise TypeError("p and g must be integers")
+ if q is not None and not isinstance(q, six.integer_types):
+ raise TypeError("q must be integer or None")
+
+ if g < 2:
+ raise ValueError("DH generator must be 2 or greater")
self._p = p
self._g = g
+ self._q = q
def __eq__(self, other):
if not isinstance(other, DHParameterNumbers):
@@ -84,14 +100,19 @@ class DHParameterNumbers(object):
return (
self._p == other._p and
- self._g == other._g
+ self._g == other._g and
+ self._q == other._q
)
def __ne__(self, other):
return not self == other
+ def parameters(self, backend):
+ return backend.load_dh_parameter_numbers(self)
+
p = utils.read_only_property("_p")
g = utils.read_only_property("_g")
+ q = utils.read_only_property("_q")
@six.add_metaclass(abc.ABCMeta)
@@ -102,9 +123,12 @@ class DHParameters(object):
Generates and returns a DHPrivateKey.
"""
+ @abc.abstractmethod
+ def parameter_bytes(self, encoding, format):
+ """
+ Returns the parameters serialized as bytes.
+ """
-@six.add_metaclass(abc.ABCMeta)
-class DHParametersWithSerialization(DHParameters):
@abc.abstractmethod
def parameter_numbers(self):
"""
@@ -112,6 +136,9 @@ class DHParametersWithSerialization(DHParameters):
"""
+DHParametersWithSerialization = DHParameters
+
+
@six.add_metaclass(abc.ABCMeta)
class DHPrivateKey(object):
@abc.abstractproperty
@@ -132,6 +159,13 @@ class DHPrivateKey(object):
The DHParameters object associated with this private key.
"""
+ @abc.abstractmethod
+ def exchange(self, peer_public_key):
+ """
+ Given peer's DHPublicKey, carry out the key exchange and
+ return shared key as bytes.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DHPrivateKeyWithSerialization(DHPrivateKey):
@@ -141,6 +175,12 @@ class DHPrivateKeyWithSerialization(DHPrivateKey):
Returns a DHPrivateNumbers.
"""
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ Returns the key serialized as bytes.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DHPublicKey(object):
@@ -156,11 +196,17 @@ class DHPublicKey(object):
The DHParameters object associated with this public key.
"""
-
-@six.add_metaclass(abc.ABCMeta)
-class DHPublicKeyWithSerialization(DHPublicKey):
@abc.abstractmethod
def public_numbers(self):
"""
Returns a DHPublicNumbers.
"""
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding, format):
+ """
+ Returns the key serialized as bytes.
+ """
+
+
+DHPublicKeyWithSerialization = DHPublicKey
diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py
index 733a967c..e380a441 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -55,6 +55,12 @@ class DSAPrivateKey(object):
Returns an AsymmetricSignatureContext used for signing data.
"""
+ @abc.abstractmethod
+ def sign(self, data, algorithm):
+ """
+ Signs the data
+ """
+
@six.add_metaclass(abc.ABCMeta)
class DSAPrivateKeyWithSerialization(DSAPrivateKey):
@@ -91,9 +97,6 @@ class DSAPublicKey(object):
Returns an AsymmetricVerificationContext used for signing data.
"""
-
-@six.add_metaclass(abc.ABCMeta)
-class DSAPublicKeyWithSerialization(DSAPublicKey):
@abc.abstractmethod
def public_numbers(self):
"""
@@ -106,6 +109,15 @@ class DSAPublicKeyWithSerialization(DSAPublicKey):
Returns the key serialized as bytes.
"""
+ @abc.abstractmethod
+ def verify(self, signature, data, algorithm):
+ """
+ Verifies the signature of the data.
+ """
+
+
+DSAPublicKeyWithSerialization = DSAPublicKey
+
def generate_parameters(key_size, backend):
return backend.generate_dsa_parameters(key_size)
@@ -116,10 +128,10 @@ def generate_private_key(key_size, backend):
def _check_dsa_parameters(parameters):
- if utils.bit_length(parameters.p) not in [1024, 2048, 3072]:
+ if parameters.p.bit_length() 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 parameters.q.bit_length() not in [160, 224, 256]:
+ raise ValueError("q must be exactly 160, 224, or 256 bits long")
if not (1 < parameters.g < parameters.p):
raise ValueError("g, p don't satisfy 1 < g < p.")
@@ -166,6 +178,13 @@ class DSAParameterNumbers(object):
def __ne__(self, other):
return not self == other
+ def __repr__(self):
+ return (
+ "<DSAParameterNumbers(p={self.p}, q={self.q}, g={self.g})>".format(
+ self=self
+ )
+ )
+
class DSAPublicNumbers(object):
def __init__(self, y, parameter_numbers):
@@ -198,6 +217,12 @@ class DSAPublicNumbers(object):
def __ne__(self, other):
return not self == other
+ def __repr__(self):
+ return (
+ "<DSAPublicNumbers(y={self.y}, "
+ "parameter_numbers={self.parameter_numbers})>".format(self=self)
+ )
+
class DSAPrivateNumbers(object):
def __init__(self, x, public_numbers):
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py
index 631fcbf7..eef922dc 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/ec.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py
@@ -5,10 +5,34 @@
from __future__ import absolute_import, division, print_function
import abc
+import warnings
import six
from cryptography import utils
+from cryptography.hazmat._oid import ObjectIdentifier
+
+
+class EllipticCurveOID(object):
+ SECP192R1 = ObjectIdentifier("1.2.840.10045.3.1.1")
+ SECP224R1 = ObjectIdentifier("1.3.132.0.33")
+ SECP256K1 = ObjectIdentifier("1.3.132.0.10")
+ SECP256R1 = ObjectIdentifier("1.2.840.10045.3.1.7")
+ SECP384R1 = ObjectIdentifier("1.3.132.0.34")
+ SECP521R1 = ObjectIdentifier("1.3.132.0.35")
+ BRAINPOOLP256R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.7")
+ BRAINPOOLP384R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.11")
+ BRAINPOOLP512R1 = ObjectIdentifier("1.3.36.3.3.2.8.1.1.13")
+ SECT163K1 = ObjectIdentifier("1.3.132.0.1")
+ SECT163R2 = ObjectIdentifier("1.3.132.0.15")
+ SECT233K1 = ObjectIdentifier("1.3.132.0.26")
+ SECT233R1 = ObjectIdentifier("1.3.132.0.27")
+ SECT283K1 = ObjectIdentifier("1.3.132.0.16")
+ SECT283R1 = ObjectIdentifier("1.3.132.0.17")
+ SECT409K1 = ObjectIdentifier("1.3.132.0.36")
+ SECT409R1 = ObjectIdentifier("1.3.132.0.37")
+ SECT571K1 = ObjectIdentifier("1.3.132.0.38")
+ SECT571R1 = ObjectIdentifier("1.3.132.0.39")
@six.add_metaclass(abc.ABCMeta)
@@ -22,7 +46,7 @@ class EllipticCurve(object):
@abc.abstractproperty
def key_size(self):
"""
- The bit length of the base point of the curve.
+ Bit size of a secret scalar for the curve.
"""
@@ -44,6 +68,13 @@ class EllipticCurvePrivateKey(object):
"""
@abc.abstractmethod
+ def exchange(self, algorithm, peer_public_key):
+ """
+ Performs a key exchange operation using the provided algorithm with the
+ provided peer's public key.
+ """
+
+ @abc.abstractmethod
def public_key(self):
"""
The EllipticCurvePublicKey for this private key.
@@ -55,6 +86,18 @@ class EllipticCurvePrivateKey(object):
The EllipticCurve that this key is on.
"""
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ Bit size of a secret scalar for the curve.
+ """
+
+ @abc.abstractmethod
+ def sign(self, data, signature_algorithm):
+ """
+ Signs the data
+ """
+
@six.add_metaclass(abc.ABCMeta)
class EllipticCurvePrivateKeyWithSerialization(EllipticCurvePrivateKey):
@@ -85,9 +128,12 @@ class EllipticCurvePublicKey(object):
The EllipticCurve that this key is on.
"""
+ @abc.abstractproperty
+ def key_size(self):
+ """
+ Bit size of a secret scalar for the curve.
+ """
-@six.add_metaclass(abc.ABCMeta)
-class EllipticCurvePublicKeyWithSerialization(EllipticCurvePublicKey):
@abc.abstractmethod
def public_numbers(self):
"""
@@ -100,11 +146,36 @@ class EllipticCurvePublicKeyWithSerialization(EllipticCurvePublicKey):
Returns the key serialized as bytes.
"""
+ @abc.abstractmethod
+ def verify(self, signature, data, signature_algorithm):
+ """
+ Verifies the signature of the data.
+ """
+
+ @classmethod
+ def from_encoded_point(cls, curve, data):
+ utils._check_bytes("data", data)
+
+ if not isinstance(curve, EllipticCurve):
+ raise TypeError("curve must be an EllipticCurve instance")
+
+ if len(data) == 0:
+ raise ValueError("data must not be an empty byte string")
+
+ if six.indexbytes(data, 0) not in [0x02, 0x03, 0x04]:
+ raise ValueError("Unsupported elliptic curve point type")
+
+ from cryptography.hazmat.backends.openssl.backend import backend
+ return backend.load_elliptic_curve_public_bytes(curve, data)
+
+
+EllipticCurvePublicKeyWithSerialization = EllipticCurvePublicKey
+
@utils.register_interface(EllipticCurve)
class SECT571R1(object):
name = "sect571r1"
- key_size = 571
+ key_size = 570
@utils.register_interface(EllipticCurve)
@@ -197,6 +268,24 @@ class SECP192R1(object):
key_size = 192
+@utils.register_interface(EllipticCurve)
+class BrainpoolP256R1(object):
+ name = "brainpoolP256r1"
+ key_size = 256
+
+
+@utils.register_interface(EllipticCurve)
+class BrainpoolP384R1(object):
+ name = "brainpoolP384r1"
+ key_size = 384
+
+
+@utils.register_interface(EllipticCurve)
+class BrainpoolP512R1(object):
+ name = "brainpoolP512r1"
+ key_size = 512
+
+
_CURVE_TYPES = {
"prime192v1": SECP192R1,
"prime256v1": SECP256R1,
@@ -219,6 +308,10 @@ _CURVE_TYPES = {
"sect283r1": SECT283R1,
"sect409r1": SECT409R1,
"sect571r1": SECT571R1,
+
+ "brainpoolP256r1": BrainpoolP256R1,
+ "brainpoolP384r1": BrainpoolP384R1,
+ "brainpoolP512r1": BrainpoolP512R1,
}
@@ -234,6 +327,19 @@ def generate_private_key(curve, backend):
return backend.generate_elliptic_curve_private_key(curve)
+def derive_private_key(private_value, curve, backend):
+ if not isinstance(private_value, six.integer_types):
+ raise TypeError("private_value must be an integer type.")
+
+ if private_value <= 0:
+ raise ValueError("private_value must be a positive integer.")
+
+ if not isinstance(curve, EllipticCurve):
+ raise TypeError("curve must provide the EllipticCurve interface.")
+
+ return backend.derive_elliptic_curve_private_key(private_value, curve)
+
+
class EllipticCurvePublicNumbers(object):
def __init__(self, x, y, curve):
if (
@@ -252,6 +358,47 @@ class EllipticCurvePublicNumbers(object):
def public_key(self, backend):
return backend.load_elliptic_curve_public_numbers(self)
+ def encode_point(self):
+ warnings.warn(
+ "encode_point has been deprecated on EllipticCurvePublicNumbers"
+ " and will be removed in a future version. Please use "
+ "EllipticCurvePublicKey.public_bytes to obtain both "
+ "compressed and uncompressed point encoding.",
+ utils.PersistentlyDeprecated2019,
+ stacklevel=2,
+ )
+ # key_size is in bits. Convert to bytes and round up
+ byte_length = (self.curve.key_size + 7) // 8
+ return (
+ b'\x04' + utils.int_to_bytes(self.x, byte_length) +
+ utils.int_to_bytes(self.y, byte_length)
+ )
+
+ @classmethod
+ def from_encoded_point(cls, curve, data):
+ if not isinstance(curve, EllipticCurve):
+ raise TypeError("curve must be an EllipticCurve instance")
+
+ warnings.warn(
+ "Support for unsafe construction of public numbers from "
+ "encoded data will be removed in a future version. "
+ "Please use EllipticCurvePublicKey.from_encoded_point",
+ utils.PersistentlyDeprecated2019,
+ stacklevel=2,
+ )
+
+ if data.startswith(b'\x04'):
+ # key_size is in bits. Convert to bytes and round up
+ byte_length = (curve.key_size + 7) // 8
+ if len(data) == 2 * byte_length + 1:
+ x = utils.int_from_bytes(data[1:byte_length + 1], 'big')
+ y = utils.int_from_bytes(data[byte_length + 1:], 'big')
+ return cls(x, y, curve)
+ else:
+ raise ValueError('Invalid elliptic curve point data length')
+ else:
+ raise ValueError('Unsupported elliptic curve point type')
+
curve = utils.read_only_property("_curve")
x = utils.read_only_property("_x")
y = utils.read_only_property("_y")
@@ -270,6 +417,15 @@ class EllipticCurvePublicNumbers(object):
def __ne__(self, other):
return not self == other
+ def __hash__(self):
+ return hash((self.x, self.y, self.curve.name, self.curve.key_size))
+
+ def __repr__(self):
+ return (
+ "<EllipticCurvePublicNumbers(curve={0.curve.name}, x={0.x}, "
+ "y={0.y}>".format(self)
+ )
+
class EllipticCurvePrivateNumbers(object):
def __init__(self, private_value, public_numbers):
@@ -302,3 +458,43 @@ class EllipticCurvePrivateNumbers(object):
def __ne__(self, other):
return not self == other
+
+ def __hash__(self):
+ return hash((self.private_value, self.public_numbers))
+
+
+class ECDH(object):
+ pass
+
+
+_OID_TO_CURVE = {
+ EllipticCurveOID.SECP192R1: SECP192R1,
+ EllipticCurveOID.SECP224R1: SECP224R1,
+ EllipticCurveOID.SECP256K1: SECP256K1,
+ EllipticCurveOID.SECP256R1: SECP256R1,
+ EllipticCurveOID.SECP384R1: SECP384R1,
+ EllipticCurveOID.SECP521R1: SECP521R1,
+ EllipticCurveOID.BRAINPOOLP256R1: BrainpoolP256R1,
+ EllipticCurveOID.BRAINPOOLP384R1: BrainpoolP384R1,
+ EllipticCurveOID.BRAINPOOLP512R1: BrainpoolP512R1,
+ EllipticCurveOID.SECT163K1: SECT163K1,
+ EllipticCurveOID.SECT163R2: SECT163R2,
+ EllipticCurveOID.SECT233K1: SECT233K1,
+ EllipticCurveOID.SECT233R1: SECT233R1,
+ EllipticCurveOID.SECT283K1: SECT283K1,
+ EllipticCurveOID.SECT283R1: SECT283R1,
+ EllipticCurveOID.SECT409K1: SECT409K1,
+ EllipticCurveOID.SECT409R1: SECT409R1,
+ EllipticCurveOID.SECT571K1: SECT571K1,
+ EllipticCurveOID.SECT571R1: SECT571R1,
+}
+
+
+def get_curve_for_oid(oid):
+ try:
+ return _OID_TO_CURVE[oid]
+ except KeyError:
+ raise LookupError(
+ "The provided object identifier has no matching elliptic "
+ "curve class"
+ )
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed25519.py b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py
new file mode 100644
index 00000000..d89445fa
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/ed25519.py
@@ -0,0 +1,84 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+
+import six
+
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+
+
+_ED25519_KEY_SIZE = 32
+_ED25519_SIG_SIZE = 64
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Ed25519PublicKey(object):
+ @classmethod
+ def from_public_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed25519_supported():
+ raise UnsupportedAlgorithm(
+ "ed25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ return backend.ed25519_load_public_bytes(data)
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding, format):
+ """
+ The serialized bytes of the public key.
+ """
+
+ @abc.abstractmethod
+ def verify(self, signature, data):
+ """
+ Verify the signature.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Ed25519PrivateKey(object):
+ @classmethod
+ def generate(cls):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed25519_supported():
+ raise UnsupportedAlgorithm(
+ "ed25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ return backend.ed25519_generate_key()
+
+ @classmethod
+ def from_private_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed25519_supported():
+ raise UnsupportedAlgorithm(
+ "ed25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ return backend.ed25519_load_private_bytes(data)
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The Ed25519PublicKey derived from the private key.
+ """
+
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ The serialized bytes of the private key.
+ """
+
+ @abc.abstractmethod
+ def sign(self, data):
+ """
+ Signs the data.
+ """
diff --git a/src/cryptography/hazmat/primitives/asymmetric/ed448.py b/src/cryptography/hazmat/primitives/asymmetric/ed448.py
new file mode 100644
index 00000000..939157ab
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/ed448.py
@@ -0,0 +1,79 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+
+import six
+
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Ed448PublicKey(object):
+ @classmethod
+ def from_public_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed448_supported():
+ raise UnsupportedAlgorithm(
+ "ed448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ return backend.ed448_load_public_bytes(data)
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding, format):
+ """
+ The serialized bytes of the public key.
+ """
+
+ @abc.abstractmethod
+ def verify(self, signature, data):
+ """
+ Verify the signature.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Ed448PrivateKey(object):
+ @classmethod
+ def generate(cls):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed448_supported():
+ raise UnsupportedAlgorithm(
+ "ed448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+ return backend.ed448_generate_key()
+
+ @classmethod
+ def from_private_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.ed448_supported():
+ raise UnsupportedAlgorithm(
+ "ed448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ )
+
+ return backend.ed448_load_private_bytes(data)
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The Ed448PublicKey derived from the private key.
+ """
+
+ @abc.abstractmethod
+ def sign(self, data):
+ """
+ Signs the data.
+ """
+
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ The serialized bytes of the private key.
+ """
diff --git a/src/cryptography/hazmat/primitives/asymmetric/padding.py b/src/cryptography/hazmat/primitives/asymmetric/padding.py
index c796d8e4..828e03bc 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/padding.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -10,6 +10,7 @@ import six
from cryptography import utils
from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.asymmetric import rsa
@six.add_metaclass(abc.ABCMeta)
@@ -65,3 +66,13 @@ class MGF1(object):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
+
+
+def calculate_max_pss_salt_length(key, hash_algorithm):
+ if not isinstance(key, (rsa.RSAPrivateKey, rsa.RSAPublicKey)):
+ raise TypeError("key must be an RSA public or private key")
+ # bit length - 1 per RFC 3447
+ emlen = (key.key_size + 6) // 8
+ salt_length = emlen - hash_algorithm.digest_size - 2
+ assert salt_length >= 0
+ return salt_length
diff --git a/src/cryptography/hazmat/primitives/asymmetric/rsa.py b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
index 772473fd..f20cdf9c 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -5,7 +5,11 @@
from __future__ import absolute_import, division, print_function
import abc
-from fractions import gcd
+try:
+ # Only available in math in 3.5+
+ from math import gcd
+except ImportError:
+ from fractions import gcd
import six
@@ -40,6 +44,12 @@ class RSAPrivateKey(object):
The RSAPublicKey associated with this private key.
"""
+ @abc.abstractmethod
+ def sign(self, data, padding, algorithm):
+ """
+ Signs the data.
+ """
+
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKeyWithSerialization(RSAPrivateKey):
@@ -76,9 +86,6 @@ class RSAPublicKey(object):
The bit length of the public modulus.
"""
-
-@six.add_metaclass(abc.ABCMeta)
-class RSAPublicKeyWithSerialization(RSAPublicKey):
@abc.abstractmethod
def public_numbers(self):
"""
@@ -91,6 +98,15 @@ class RSAPublicKeyWithSerialization(RSAPublicKey):
Returns the key serialized as bytes.
"""
+ @abc.abstractmethod
+ def verify(self, signature, data, padding, algorithm):
+ """
+ Verifies the signature of the data.
+ """
+
+
+RSAPublicKeyWithSerialization = RSAPublicKey
+
def generate_private_key(public_exponent, key_size, backend):
if not isinstance(backend, RSABackend):
@@ -168,12 +184,12 @@ def _modinv(e, m):
"""
Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
"""
- x1, y1, x2, y2 = 1, 0, 0, 1
+ x1, x2 = 1, 0
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
+ xn = x1 - q * x2
+ a, b, x1, x2 = b, r, x2, xn
return x1 % m
@@ -187,7 +203,7 @@ def rsa_crt_iqmp(p, q):
def rsa_crt_dmp1(private_exponent, p):
"""
Compute the CRT private_exponent % (p - 1) value from the RSA
- private_exponent and p.
+ private_exponent (d) and p.
"""
return private_exponent % (p - 1)
@@ -195,7 +211,7 @@ def rsa_crt_dmp1(private_exponent, p):
def rsa_crt_dmq1(private_exponent, q):
"""
Compute the CRT private_exponent % (q - 1) value from the RSA
- private_exponent and q.
+ private_exponent (d) and q.
"""
return private_exponent % (q - 1)
@@ -245,7 +261,7 @@ def rsa_recover_prime_factors(n, e, d):
# Found !
q, r = divmod(n, p)
assert r == 0
-
+ p, q = sorted((p, q), reverse=True)
return (p, q)
@@ -307,6 +323,17 @@ class RSAPrivateNumbers(object):
def __ne__(self, other):
return not self == other
+ def __hash__(self):
+ return hash((
+ self.p,
+ self.q,
+ self.d,
+ self.dmp1,
+ self.dmq1,
+ self.iqmp,
+ self.public_numbers,
+ ))
+
class RSAPublicNumbers(object):
def __init__(self, e, n):
@@ -336,3 +363,6 @@ class RSAPublicNumbers(object):
def __ne__(self, other):
return not self == other
+
+ def __hash__(self):
+ return hash((self.e, self.n))
diff --git a/src/cryptography/hazmat/primitives/asymmetric/utils.py b/src/cryptography/hazmat/primitives/asymmetric/utils.py
index a03025bb..14d2abee 100644
--- a/src/cryptography/hazmat/primitives/asymmetric/utils.py
+++ b/src/cryptography/hazmat/primitives/asymmetric/utils.py
@@ -4,44 +4,34 @@
from __future__ import absolute_import, division, print_function
-from pyasn1.codec.der import decoder, encoder
-from pyasn1.error import PyAsn1Error
-from pyasn1.type import namedtype, univ
+from cryptography import utils
+from cryptography.hazmat._der import (
+ DERReader, INTEGER, SEQUENCE, encode_der, encode_der_integer
+)
+from cryptography.hazmat.primitives import hashes
-import six
-
-class _DSSSigValue(univ.Sequence):
- componentType = namedtype.NamedTypes(
- namedtype.NamedType('r', univ.Integer()),
- namedtype.NamedType('s', univ.Integer())
- )
+def decode_dss_signature(signature):
+ with DERReader(signature).read_single_element(SEQUENCE) as seq:
+ r = seq.read_element(INTEGER).as_integer()
+ s = seq.read_element(INTEGER).as_integer()
+ return r, s
-def decode_rfc6979_signature(signature):
- try:
- data, remaining = decoder.decode(signature, asn1Spec=_DSSSigValue())
- except PyAsn1Error:
- raise ValueError("Invalid signature data. Unable to decode ASN.1")
-
- if remaining:
- raise ValueError(
- "The signature contains bytes after the end of the ASN.1 sequence."
- )
+def encode_dss_signature(r, s):
+ return encode_der(
+ SEQUENCE,
+ encode_der(INTEGER, encode_der_integer(r)),
+ encode_der(INTEGER, encode_der_integer(s)),
+ )
- r = int(data.getComponentByName('r'))
- s = int(data.getComponentByName('s'))
- return (r, s)
+class Prehashed(object):
+ def __init__(self, algorithm):
+ if not isinstance(algorithm, hashes.HashAlgorithm):
+ raise TypeError("Expected instance of HashAlgorithm.")
-def encode_rfc6979_signature(r, s):
- if (
- not isinstance(r, six.integer_types) or
- not isinstance(s, six.integer_types)
- ):
- raise ValueError("Both r and s must be integers")
+ self._algorithm = algorithm
+ self._digest_size = algorithm.digest_size
- sig = _DSSSigValue()
- sig.setComponentByName('r', r)
- sig.setComponentByName('s', s)
- return encoder.encode(sig)
+ digest_size = utils.read_only_property("_digest_size")
diff --git a/src/cryptography/hazmat/primitives/asymmetric/x25519.py b/src/cryptography/hazmat/primitives/asymmetric/x25519.py
new file mode 100644
index 00000000..61a95ffa
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/x25519.py
@@ -0,0 +1,73 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+
+import six
+
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+
+
+@six.add_metaclass(abc.ABCMeta)
+class X25519PublicKey(object):
+ @classmethod
+ def from_public_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x25519_supported():
+ raise UnsupportedAlgorithm(
+ "X25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ return backend.x25519_load_public_bytes(data)
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding, format):
+ """
+ The serialized bytes of the public key.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class X25519PrivateKey(object):
+ @classmethod
+ def generate(cls):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x25519_supported():
+ raise UnsupportedAlgorithm(
+ "X25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+ return backend.x25519_generate_key()
+
+ @classmethod
+ def from_private_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x25519_supported():
+ raise UnsupportedAlgorithm(
+ "X25519 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ return backend.x25519_load_private_bytes(data)
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The serialized bytes of the public key.
+ """
+
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ The serialized bytes of the private key.
+ """
+
+ @abc.abstractmethod
+ def exchange(self, peer_public_key):
+ """
+ Performs a key exchange operation using the provided peer's public key.
+ """
diff --git a/src/cryptography/hazmat/primitives/asymmetric/x448.py b/src/cryptography/hazmat/primitives/asymmetric/x448.py
new file mode 100644
index 00000000..475e678f
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/asymmetric/x448.py
@@ -0,0 +1,73 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+
+import six
+
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+
+
+@six.add_metaclass(abc.ABCMeta)
+class X448PublicKey(object):
+ @classmethod
+ def from_public_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x448_supported():
+ raise UnsupportedAlgorithm(
+ "X448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ return backend.x448_load_public_bytes(data)
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding, format):
+ """
+ The serialized bytes of the public key.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class X448PrivateKey(object):
+ @classmethod
+ def generate(cls):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x448_supported():
+ raise UnsupportedAlgorithm(
+ "X448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+ return backend.x448_generate_key()
+
+ @classmethod
+ def from_private_bytes(cls, data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.x448_supported():
+ raise UnsupportedAlgorithm(
+ "X448 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM
+ )
+
+ return backend.x448_load_private_bytes(data)
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ The serialized bytes of the public key.
+ """
+
+ @abc.abstractmethod
+ def private_bytes(self, encoding, format, encryption_algorithm):
+ """
+ The serialized bytes of the private key.
+ """
+
+ @abc.abstractmethod
+ def exchange(self, peer_public_key):
+ """
+ Performs a key exchange operation using the provided peer's public key.
+ """
diff --git a/src/cryptography/hazmat/primitives/ciphers/__init__.py b/src/cryptography/hazmat/primitives/ciphers/__init__.py
index b5dd0ed7..171b1c69 100644
--- a/src/cryptography/hazmat/primitives/ciphers/__init__.py
+++ b/src/cryptography/hazmat/primitives/ciphers/__init__.py
@@ -5,8 +5,8 @@
from __future__ import absolute_import, division, print_function
from cryptography.hazmat.primitives.ciphers.base import (
- AEADCipherContext, AEADEncryptionContext, BlockCipherAlgorithm, Cipher,
- CipherAlgorithm, CipherContext
+ AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext,
+ BlockCipherAlgorithm, Cipher, CipherAlgorithm, CipherContext
)
@@ -16,5 +16,6 @@ __all__ = [
"BlockCipherAlgorithm",
"CipherContext",
"AEADCipherContext",
+ "AEADDecryptionContext",
"AEADEncryptionContext",
]
diff --git a/src/cryptography/hazmat/primitives/ciphers/aead.py b/src/cryptography/hazmat/primitives/ciphers/aead.py
new file mode 100644
index 00000000..72cb30c3
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/ciphers/aead.py
@@ -0,0 +1,182 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import os
+
+from cryptography import exceptions, utils
+from cryptography.hazmat.backends.openssl import aead
+from cryptography.hazmat.backends.openssl.backend import backend
+
+
+class ChaCha20Poly1305(object):
+ _MAX_SIZE = 2 ** 32
+
+ def __init__(self, key):
+ if not backend.aead_cipher_supported(self):
+ raise exceptions.UnsupportedAlgorithm(
+ "ChaCha20Poly1305 is not supported by this version of OpenSSL",
+ exceptions._Reasons.UNSUPPORTED_CIPHER
+ )
+ utils._check_byteslike("key", key)
+
+ if len(key) != 32:
+ raise ValueError("ChaCha20Poly1305 key must be 32 bytes.")
+
+ self._key = key
+
+ @classmethod
+ def generate_key(cls):
+ return os.urandom(32)
+
+ def encrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
+ # This is OverflowError to match what cffi would raise
+ raise OverflowError(
+ "Data or associated data too long. Max 2**32 bytes"
+ )
+
+ self._check_params(nonce, data, associated_data)
+ return aead._encrypt(
+ backend, self, nonce, data, associated_data, 16
+ )
+
+ def decrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ self._check_params(nonce, data, associated_data)
+ return aead._decrypt(
+ backend, self, nonce, data, associated_data, 16
+ )
+
+ def _check_params(self, nonce, data, associated_data):
+ utils._check_byteslike("nonce", nonce)
+ utils._check_bytes("data", data)
+ utils._check_bytes("associated_data", associated_data)
+ if len(nonce) != 12:
+ raise ValueError("Nonce must be 12 bytes")
+
+
+class AESCCM(object):
+ _MAX_SIZE = 2 ** 32
+
+ def __init__(self, key, tag_length=16):
+ utils._check_byteslike("key", key)
+ if len(key) not in (16, 24, 32):
+ raise ValueError("AESCCM key must be 128, 192, or 256 bits.")
+
+ self._key = key
+ if not isinstance(tag_length, int):
+ raise TypeError("tag_length must be an integer")
+
+ if tag_length not in (4, 6, 8, 10, 12, 14, 16):
+ raise ValueError("Invalid tag_length")
+
+ self._tag_length = tag_length
+
+ @classmethod
+ def generate_key(cls, bit_length):
+ if not isinstance(bit_length, int):
+ raise TypeError("bit_length must be an integer")
+
+ if bit_length not in (128, 192, 256):
+ raise ValueError("bit_length must be 128, 192, or 256")
+
+ return os.urandom(bit_length // 8)
+
+ def encrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
+ # This is OverflowError to match what cffi would raise
+ raise OverflowError(
+ "Data or associated data too long. Max 2**32 bytes"
+ )
+
+ self._check_params(nonce, data, associated_data)
+ self._validate_lengths(nonce, len(data))
+ return aead._encrypt(
+ backend, self, nonce, data, associated_data, self._tag_length
+ )
+
+ def decrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ self._check_params(nonce, data, associated_data)
+ return aead._decrypt(
+ backend, self, nonce, data, associated_data, self._tag_length
+ )
+
+ def _validate_lengths(self, nonce, data_len):
+ # For information about computing this, see
+ # https://tools.ietf.org/html/rfc3610#section-2.1
+ l_val = 15 - len(nonce)
+ if 2 ** (8 * l_val) < data_len:
+ raise ValueError("Data too long for nonce")
+
+ def _check_params(self, nonce, data, associated_data):
+ utils._check_byteslike("nonce", nonce)
+ utils._check_bytes("data", data)
+ utils._check_bytes("associated_data", associated_data)
+ if not 7 <= len(nonce) <= 13:
+ raise ValueError("Nonce must be between 7 and 13 bytes")
+
+
+class AESGCM(object):
+ _MAX_SIZE = 2 ** 32
+
+ def __init__(self, key):
+ utils._check_byteslike("key", key)
+ if len(key) not in (16, 24, 32):
+ raise ValueError("AESGCM key must be 128, 192, or 256 bits.")
+
+ self._key = key
+
+ @classmethod
+ def generate_key(cls, bit_length):
+ if not isinstance(bit_length, int):
+ raise TypeError("bit_length must be an integer")
+
+ if bit_length not in (128, 192, 256):
+ raise ValueError("bit_length must be 128, 192, or 256")
+
+ return os.urandom(bit_length // 8)
+
+ def encrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE:
+ # This is OverflowError to match what cffi would raise
+ raise OverflowError(
+ "Data or associated data too long. Max 2**32 bytes"
+ )
+
+ self._check_params(nonce, data, associated_data)
+ return aead._encrypt(
+ backend, self, nonce, data, associated_data, 16
+ )
+
+ def decrypt(self, nonce, data, associated_data):
+ if associated_data is None:
+ associated_data = b""
+
+ self._check_params(nonce, data, associated_data)
+ return aead._decrypt(
+ backend, self, nonce, data, associated_data, 16
+ )
+
+ def _check_params(self, nonce, data, associated_data):
+ utils._check_byteslike("nonce", nonce)
+ utils._check_bytes("data", data)
+ utils._check_bytes("associated_data", associated_data)
+ if len(nonce) == 0:
+ raise ValueError("Nonce must be at least 1 byte")
diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
index b71dddbb..f4d5160b 100644
--- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -8,12 +8,16 @@ from cryptography import utils
from cryptography.hazmat.primitives.ciphers import (
BlockCipherAlgorithm, CipherAlgorithm
)
+from cryptography.hazmat.primitives.ciphers.modes import ModeWithNonce
def _verify_key_size(algorithm, key):
+ # Verify that the key is instance of bytes
+ utils._check_byteslike("key", 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(
+ raise ValueError("Invalid key size ({}) for {}.".format(
len(key) * 8, algorithm.name
))
return key
@@ -24,7 +28,8 @@ def _verify_key_size(algorithm, key):
class AES(object):
name = "AES"
block_size = 128
- key_sizes = frozenset([128, 192, 256])
+ # 512 added to support AES-256-XTS, which uses 512-bit keys
+ key_sizes = frozenset([128, 192, 256, 512])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@@ -101,7 +106,7 @@ class CAST5(object):
@utils.register_interface(CipherAlgorithm)
class ARC4(object):
name = "RC4"
- key_sizes = frozenset([40, 56, 64, 80, 128, 192, 256])
+ key_sizes = frozenset([40, 56, 64, 80, 128, 160, 192, 256])
def __init__(self, key):
self.key = _verify_key_size(self, key)
@@ -138,3 +143,25 @@ class SEED(object):
@property
def key_size(self):
return len(self.key) * 8
+
+
+@utils.register_interface(CipherAlgorithm)
+@utils.register_interface(ModeWithNonce)
+class ChaCha20(object):
+ name = "ChaCha20"
+ key_sizes = frozenset([256])
+
+ def __init__(self, key, nonce):
+ self.key = _verify_key_size(self, key)
+ utils._check_byteslike("nonce", nonce)
+
+ if len(nonce) != 16:
+ raise ValueError("nonce must be 128-bits (16 bytes)")
+
+ self._nonce = nonce
+
+ nonce = utils.read_only_property("_nonce")
+
+ @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
index 8f3028fc..4d5f8d60 100644
--- a/src/cryptography/hazmat/primitives/ciphers/base.py
+++ b/src/cryptography/hazmat/primitives/ciphers/base.py
@@ -51,6 +51,13 @@ class CipherContext(object):
"""
@abc.abstractmethod
+ def update_into(self, data, buf):
+ """
+ Processes the provided bytes and writes the resulting data into the
+ provided buffer. Returns the number of bytes written.
+ """
+
+ @abc.abstractmethod
def finalize(self):
"""
Returns the results of processing the final block as bytes.
@@ -67,6 +74,16 @@ class AEADCipherContext(object):
@six.add_metaclass(abc.ABCMeta)
+class AEADDecryptionContext(object):
+ @abc.abstractmethod
+ def finalize_with_tag(self, tag):
+ """
+ Returns the results of processing the final block as bytes and allows
+ delayed passing of the authentication tag.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class AEADEncryptionContext(object):
@abc.abstractproperty
def tag(self):
@@ -106,11 +123,6 @@ class Cipher(object):
return self._wrap_ctx(ctx, encrypt=True)
def decryptor(self):
- if isinstance(self.mode, modes.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
)
@@ -136,6 +148,11 @@ class _CipherContext(object):
raise AlreadyFinalized("Context was already finalized.")
return self._ctx.update(data)
+ def update_into(self, data, buf):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ return self._ctx.update_into(data, buf)
+
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
@@ -146,18 +163,35 @@ class _CipherContext(object):
@utils.register_interface(AEADCipherContext)
@utils.register_interface(CipherContext)
+@utils.register_interface(AEADDecryptionContext)
class _AEADCipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
+ self._bytes_processed = 0
+ self._aad_bytes_processed = 0
self._tag = None
self._updated = False
- def update(self, data):
+ def _check_limit(self, data_size):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
self._updated = True
+ self._bytes_processed += data_size
+ if self._bytes_processed > self._ctx._mode._MAX_ENCRYPTED_BYTES:
+ raise ValueError(
+ "{} has a maximum encrypted byte limit of {}".format(
+ self._ctx._mode.name, self._ctx._mode._MAX_ENCRYPTED_BYTES
+ )
+ )
+
+ def update(self, data):
+ self._check_limit(len(data))
return self._ctx.update(data)
+ def update_into(self, data, buf):
+ self._check_limit(len(data))
+ return self._ctx.update_into(data, buf)
+
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
@@ -166,11 +200,28 @@ class _AEADCipherContext(object):
self._ctx = None
return data
+ def finalize_with_tag(self, tag):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ data = self._ctx.finalize_with_tag(tag)
+ 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._aad_bytes_processed += len(data)
+ if self._aad_bytes_processed > self._ctx._mode._MAX_AAD_BYTES:
+ raise ValueError(
+ "{} has a maximum AAD byte limit of {}".format(
+ self._ctx._mode.name, self._ctx._mode._MAX_AAD_BYTES
+ )
+ )
+
self._ctx.authenticate_additional_data(data)
diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py
index e31c9060..78fa1c48 100644
--- a/src/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/src/cryptography/hazmat/primitives/ciphers/modes.py
@@ -37,6 +37,15 @@ class ModeWithInitializationVector(object):
@six.add_metaclass(abc.ABCMeta)
+class ModeWithTweak(object):
+ @abc.abstractproperty
+ def tweak(self):
+ """
+ The value of the tweak for this mode as bytes.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class ModeWithNonce(object):
@abc.abstractproperty
def nonce(self):
@@ -54,31 +63,66 @@ class ModeWithAuthenticationTag(object):
"""
+def _check_aes_key_length(self, algorithm):
+ if algorithm.key_size > 256 and algorithm.name == "AES":
+ raise ValueError(
+ "Only 128, 192, and 256 bit keys are allowed for this AES mode"
+ )
+
+
def _check_iv_length(self, algorithm):
if len(self.initialization_vector) * 8 != algorithm.block_size:
- raise ValueError("Invalid IV size ({0}) for {1}.".format(
+ raise ValueError("Invalid IV size ({}) for {}.".format(
len(self.initialization_vector), self.name
))
+def _check_iv_and_key_length(self, algorithm):
+ _check_aes_key_length(self, algorithm)
+ _check_iv_length(self, algorithm)
+
+
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
class CBC(object):
name = "CBC"
def __init__(self, initialization_vector):
+ utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
- validate_for_algorithm = _check_iv_length
+ validate_for_algorithm = _check_iv_and_key_length
+
+
+@utils.register_interface(Mode)
+@utils.register_interface(ModeWithTweak)
+class XTS(object):
+ name = "XTS"
+
+ def __init__(self, tweak):
+ utils._check_byteslike("tweak", tweak)
+
+ if len(tweak) != 16:
+ raise ValueError("tweak must be 128-bits (16 bytes)")
+
+ self._tweak = tweak
+
+ tweak = utils.read_only_property("_tweak")
+
+ def validate_for_algorithm(self, algorithm):
+ if algorithm.key_size not in (256, 512):
+ raise ValueError(
+ "The XTS specification requires a 256-bit key for AES-128-XTS"
+ " and 512-bit key for AES-256-XTS"
+ )
@utils.register_interface(Mode)
class ECB(object):
name = "ECB"
- def validate_for_algorithm(self, algorithm):
- pass
+ validate_for_algorithm = _check_aes_key_length
@utils.register_interface(Mode)
@@ -87,10 +131,11 @@ class OFB(object):
name = "OFB"
def __init__(self, initialization_vector):
+ utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
- validate_for_algorithm = _check_iv_length
+ validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@@ -99,10 +144,11 @@ class CFB(object):
name = "CFB"
def __init__(self, initialization_vector):
+ utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
- validate_for_algorithm = _check_iv_length
+ validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@@ -111,10 +157,11 @@ class CFB8(object):
name = "CFB8"
def __init__(self, initialization_vector):
+ utils._check_byteslike("initialization_vector", initialization_vector)
self._initialization_vector = initialization_vector
initialization_vector = utils.read_only_property("_initialization_vector")
- validate_for_algorithm = _check_iv_length
+ validate_for_algorithm = _check_iv_and_key_length
@utils.register_interface(Mode)
@@ -123,13 +170,15 @@ class CTR(object):
name = "CTR"
def __init__(self, nonce):
+ utils._check_byteslike("nonce", nonce)
self._nonce = nonce
nonce = utils.read_only_property("_nonce")
def validate_for_algorithm(self, algorithm):
+ _check_aes_key_length(self, algorithm)
if len(self.nonce) * 8 != algorithm.block_size:
- raise ValueError("Invalid nonce size ({0}) for {1}.".format(
+ raise ValueError("Invalid nonce size ({}) for {}.".format(
len(self.nonce), self.name
))
@@ -139,24 +188,31 @@ class CTR(object):
@utils.register_interface(ModeWithAuthenticationTag)
class GCM(object):
name = "GCM"
+ _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
+ _MAX_AAD_BYTES = (2 ** 64) // 8
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)
- )
-
+ utils._check_byteslike("initialization_vector", initialization_vector)
+ if len(initialization_vector) == 0:
+ raise ValueError("initialization_vector must be at least 1 byte")
self._initialization_vector = initialization_vector
+ if tag is not None:
+ utils._check_bytes("tag", tag)
+ if min_tag_length < 4:
+ raise ValueError("min_tag_length must be >= 4")
+ if len(tag) < min_tag_length:
+ raise ValueError(
+ "Authentication tag must be {} bytes or longer.".format(
+ min_tag_length)
+ )
self._tag = tag
+ self._min_tag_length = min_tag_length
tag = utils.read_only_property("_tag")
initialization_vector = utils.read_only_property("_initialization_vector")
def validate_for_algorithm(self, algorithm):
- pass
+ _check_aes_key_length(self, algorithm)
diff --git a/src/cryptography/hazmat/primitives/cmac.py b/src/cryptography/hazmat/primitives/cmac.py
index c2038a30..95a8d975 100644
--- a/src/cryptography/hazmat/primitives/cmac.py
+++ b/src/cryptography/hazmat/primitives/cmac.py
@@ -9,10 +9,9 @@ from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import CMACBackend
-from cryptography.hazmat.primitives import ciphers, interfaces
+from cryptography.hazmat.primitives import ciphers
-@utils.register_interface(interfaces.MACContext)
class CMAC(object):
def __init__(self, algorithm, backend, ctx=None):
if not isinstance(backend, CMACBackend):
@@ -36,8 +35,8 @@ class CMAC(object):
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.")
+
+ utils._check_bytes("data", data)
self._ctx.update(data)
def finalize(self):
@@ -48,8 +47,7 @@ class CMAC(object):
return digest
def verify(self, signature):
- if not isinstance(signature, bytes):
- raise TypeError("signature must be bytes.")
+ utils._check_bytes("signature", signature)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
diff --git a/src/cryptography/hazmat/primitives/constant_time.py b/src/cryptography/hazmat/primitives/constant_time.py
index 5a682ca9..7f41b9ef 100644
--- a/src/cryptography/hazmat/primitives/constant_time.py
+++ b/src/cryptography/hazmat/primitives/constant_time.py
@@ -6,21 +6,9 @@ from __future__ import absolute_import, division, print_function
import hmac
-from cryptography.hazmat.bindings._constant_time import lib
+def bytes_eq(a, b):
+ if not isinstance(a, bytes) or not isinstance(b, bytes):
+ raise TypeError("a and b must be bytes.")
-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
+ return hmac.compare_digest(a, b)
diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py
index 6bc8500b..9be2b600 100644
--- a/src/cryptography/hazmat/primitives/hashes.py
+++ b/src/cryptography/hazmat/primitives/hashes.py
@@ -29,12 +29,6 @@ class HashAlgorithm(object):
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):
@@ -63,6 +57,13 @@ class HashContext(object):
"""
+@six.add_metaclass(abc.ABCMeta)
+class ExtendableOutputFunction(object):
+ """
+ An interface for extendable output functions.
+ """
+
+
@utils.register_interface(HashContext)
class Hash(object):
def __init__(self, algorithm, backend, ctx=None):
@@ -88,8 +89,7 @@ class Hash(object):
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.")
+ utils._check_byteslike("data", data)
self._ctx.update(data)
def copy(self):
@@ -115,6 +115,20 @@ class SHA1(object):
@utils.register_interface(HashAlgorithm)
+class SHA512_224(object): # noqa: N801
+ name = "sha512-224"
+ digest_size = 28
+ block_size = 128
+
+
+@utils.register_interface(HashAlgorithm)
+class SHA512_256(object): # noqa: N801
+ name = "sha512-256"
+ digest_size = 32
+ block_size = 128
+
+
+@utils.register_interface(HashAlgorithm)
class SHA224(object):
name = "sha224"
digest_size = 28
@@ -143,17 +157,61 @@ class SHA512(object):
@utils.register_interface(HashAlgorithm)
-class RIPEMD160(object):
- name = "ripemd160"
- digest_size = 20
- block_size = 64
+class SHA3_224(object): # noqa: N801
+ name = "sha3-224"
+ digest_size = 28
@utils.register_interface(HashAlgorithm)
-class Whirlpool(object):
- name = "whirlpool"
+class SHA3_256(object): # noqa: N801
+ name = "sha3-256"
+ digest_size = 32
+
+
+@utils.register_interface(HashAlgorithm)
+class SHA3_384(object): # noqa: N801
+ name = "sha3-384"
+ digest_size = 48
+
+
+@utils.register_interface(HashAlgorithm)
+class SHA3_512(object): # noqa: N801
+ name = "sha3-512"
digest_size = 64
- block_size = 64
+
+
+@utils.register_interface(HashAlgorithm)
+@utils.register_interface(ExtendableOutputFunction)
+class SHAKE128(object):
+ name = "shake128"
+
+ def __init__(self, digest_size):
+ if not isinstance(digest_size, six.integer_types):
+ raise TypeError("digest_size must be an integer")
+
+ if digest_size < 1:
+ raise ValueError("digest_size must be a positive integer")
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
+
+
+@utils.register_interface(HashAlgorithm)
+@utils.register_interface(ExtendableOutputFunction)
+class SHAKE256(object):
+ name = "shake256"
+
+ def __init__(self, digest_size):
+ if not isinstance(digest_size, six.integer_types):
+ raise TypeError("digest_size must be an integer")
+
+ if digest_size < 1:
+ raise ValueError("digest_size must be a positive integer")
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
@utils.register_interface(HashAlgorithm)
@@ -161,3 +219,37 @@ class MD5(object):
name = "md5"
digest_size = 16
block_size = 64
+
+
+@utils.register_interface(HashAlgorithm)
+class BLAKE2b(object):
+ name = "blake2b"
+ _max_digest_size = 64
+ _min_digest_size = 1
+ block_size = 128
+
+ def __init__(self, digest_size):
+
+ if digest_size != 64:
+ raise ValueError("Digest size must be 64")
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
+
+
+@utils.register_interface(HashAlgorithm)
+class BLAKE2s(object):
+ name = "blake2s"
+ block_size = 64
+ _max_digest_size = 32
+ _min_digest_size = 1
+
+ def __init__(self, digest_size):
+
+ if digest_size != 32:
+ raise ValueError("Digest size must be 32")
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
diff --git a/src/cryptography/hazmat/primitives/hmac.py b/src/cryptography/hazmat/primitives/hmac.py
index 15b9ee6e..9eceeac2 100644
--- a/src/cryptography/hazmat/primitives/hmac.py
+++ b/src/cryptography/hazmat/primitives/hmac.py
@@ -9,10 +9,9 @@ from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import HMACBackend
-from cryptography.hazmat.primitives import hashes, interfaces
+from cryptography.hazmat.primitives import hashes
-@utils.register_interface(interfaces.MACContext)
@utils.register_interface(hashes.HashContext)
class HMAC(object):
def __init__(self, key, algorithm, backend, ctx=None):
@@ -38,8 +37,7 @@ class HMAC(object):
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.")
+ utils._check_byteslike("data", data)
self._ctx.update(data)
def copy(self):
@@ -60,8 +58,7 @@ class HMAC(object):
return digest
def verify(self, signature):
- if not isinstance(signature, bytes):
- raise TypeError("signature must be bytes.")
+ utils._check_bytes("signature", signature)
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
diff --git a/src/cryptography/hazmat/primitives/interfaces/__init__.py b/src/cryptography/hazmat/primitives/interfaces/__init__.py
deleted file mode 100644
index 4c95190b..00000000
--- a/src/cryptography/hazmat/primitives/interfaces/__init__.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-import abc
-
-import six
-
-
-@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.
- """
diff --git a/src/cryptography/hazmat/primitives/kdf/concatkdf.py b/src/cryptography/hazmat/primitives/kdf/concatkdf.py
index c6399e4f..7cb63856 100644
--- a/src/cryptography/hazmat/primitives/kdf/concatkdf.py
+++ b/src/cryptography/hazmat/primitives/kdf/concatkdf.py
@@ -24,17 +24,15 @@ def _common_args_checks(algorithm, length, otherinfo):
max_length = algorithm.digest_size * (2 ** 32 - 1)
if length > max_length:
raise ValueError(
- "Can not derive keys larger than {0} bits.".format(
+ "Can not derive keys larger than {} bits.".format(
max_length
))
- if not (otherinfo is None or isinstance(otherinfo, bytes)):
- raise TypeError("otherinfo must be bytes.")
+ if otherinfo is not None:
+ utils._check_bytes("otherinfo", otherinfo)
def _concatkdf_derive(key_material, length, auxfn, otherinfo):
- if not isinstance(key_material, bytes):
- raise TypeError("key_material must be bytes.")
-
+ utils._check_byteslike("key_material", key_material)
output = [b""]
outlen = 0
counter = 1
@@ -96,10 +94,11 @@ class ConcatKDFHMAC(object):
if self._otherinfo is None:
self._otherinfo = b""
- if not (salt is None or isinstance(salt, bytes)):
- raise TypeError("salt must be bytes.")
if salt is None:
salt = b"\x00" * algorithm.block_size
+ else:
+ utils._check_bytes("salt", salt)
+
self._salt = salt
if not isinstance(backend, HMACBackend):
diff --git a/src/cryptography/hazmat/primitives/kdf/hkdf.py b/src/cryptography/hazmat/primitives/kdf/hkdf.py
index f738bbdc..01f0f288 100644
--- a/src/cryptography/hazmat/primitives/kdf/hkdf.py
+++ b/src/cryptography/hazmat/primitives/kdf/hkdf.py
@@ -26,11 +26,10 @@ class HKDF(object):
self._algorithm = algorithm
- if not (salt is None or isinstance(salt, bytes)):
- raise TypeError("salt must be bytes.")
-
if salt is None:
- salt = b"\x00" * (self._algorithm.digest_size // 8)
+ salt = b"\x00" * self._algorithm.digest_size
+ else:
+ utils._check_bytes("salt", salt)
self._salt = salt
@@ -44,9 +43,7 @@ class HKDF(object):
return h.finalize()
def derive(self, key_material):
- if not isinstance(key_material, bytes):
- raise TypeError("key_material must be bytes.")
-
+ utils._check_byteslike("key_material", key_material)
return self._hkdf_expand.derive(self._extract(key_material))
def verify(self, key_material, expected_key):
@@ -67,21 +64,20 @@ class HKDFExpand(object):
self._backend = backend
- max_length = 255 * (algorithm.digest_size // 8)
+ max_length = 255 * algorithm.digest_size
if length > max_length:
raise ValueError(
- "Can not derive keys larger than {0} octets.".format(
+ "Can not derive keys larger than {} octets.".format(
max_length
))
self._length = length
- if not (info is None or isinstance(info, bytes)):
- raise TypeError("info must be bytes.")
-
if info is None:
info = b""
+ else:
+ utils._check_bytes("info", info)
self._info = info
@@ -91,7 +87,7 @@ class HKDFExpand(object):
output = [b""]
counter = 1
- while (self._algorithm.digest_size // 8) * len(output) < self._length:
+ while self._algorithm.digest_size * (len(output) - 1) < self._length:
h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
h.update(output[-1])
h.update(self._info)
@@ -102,9 +98,7 @@ class HKDFExpand(object):
return b"".join(output)[:self._length]
def derive(self, key_material):
- if not isinstance(key_material, bytes):
- raise TypeError("key_material must be bytes.")
-
+ utils._check_byteslike("key_material", key_material)
if self._used:
raise AlreadyFinalized
diff --git a/src/cryptography/hazmat/primitives/kdf/kbkdf.py b/src/cryptography/hazmat/primitives/kdf/kbkdf.py
new file mode 100644
index 00000000..56783a85
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/kbkdf.py
@@ -0,0 +1,145 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from enum import Enum
+
+from six.moves import range
+
+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, hashes, hmac
+from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
+
+
+class Mode(Enum):
+ CounterMode = "ctr"
+
+
+class CounterLocation(Enum):
+ BeforeFixed = "before_fixed"
+ AfterFixed = "after_fixed"
+
+
+@utils.register_interface(KeyDerivationFunction)
+class KBKDFHMAC(object):
+ def __init__(self, algorithm, mode, length, rlen, llen,
+ location, label, context, fixed, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ if not isinstance(algorithm, hashes.HashAlgorithm):
+ raise UnsupportedAlgorithm(
+ "Algorithm supplied is not a supported hash algorithm.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if not backend.hmac_supported(algorithm):
+ raise UnsupportedAlgorithm(
+ "Algorithm supplied is not a supported hmac algorithm.",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ if not isinstance(mode, Mode):
+ raise TypeError("mode must be of type Mode")
+
+ if not isinstance(location, CounterLocation):
+ raise TypeError("location must be of type CounterLocation")
+
+ if (label or context) and fixed:
+ raise ValueError("When supplying fixed data, "
+ "label and context are ignored.")
+
+ if rlen is None or not self._valid_byte_length(rlen):
+ raise ValueError("rlen must be between 1 and 4")
+
+ if llen is None and fixed is None:
+ raise ValueError("Please specify an llen")
+
+ if llen is not None and not isinstance(llen, int):
+ raise TypeError("llen must be an integer")
+
+ if label is None:
+ label = b''
+
+ if context is None:
+ context = b''
+
+ utils._check_bytes("label", label)
+ utils._check_bytes("context", context)
+ self._algorithm = algorithm
+ self._mode = mode
+ self._length = length
+ self._rlen = rlen
+ self._llen = llen
+ self._location = location
+ self._label = label
+ self._context = context
+ self._backend = backend
+ self._used = False
+ self._fixed_data = fixed
+
+ def _valid_byte_length(self, value):
+ if not isinstance(value, int):
+ raise TypeError('value must be of type int')
+
+ value_bin = utils.int_to_bytes(1, value)
+ if not 1 <= len(value_bin) <= 4:
+ return False
+ return True
+
+ def derive(self, key_material):
+ if self._used:
+ raise AlreadyFinalized
+
+ utils._check_byteslike("key_material", key_material)
+ self._used = True
+
+ # inverse floor division (equivalent to ceiling)
+ rounds = -(-self._length // self._algorithm.digest_size)
+
+ output = [b'']
+
+ # For counter mode, the number of iterations shall not be
+ # larger than 2^r-1, where r <= 32 is the binary length of the counter
+ # This ensures that the counter values used as an input to the
+ # PRF will not repeat during a particular call to the KDF function.
+ r_bin = utils.int_to_bytes(1, self._rlen)
+ if rounds > pow(2, len(r_bin) * 8) - 1:
+ raise ValueError('There are too many iterations.')
+
+ for i in range(1, rounds + 1):
+ h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
+
+ counter = utils.int_to_bytes(i, self._rlen)
+ if self._location == CounterLocation.BeforeFixed:
+ h.update(counter)
+
+ h.update(self._generate_fixed_input())
+
+ if self._location == CounterLocation.AfterFixed:
+ h.update(counter)
+
+ output.append(h.finalize())
+
+ return b''.join(output)[:self._length]
+
+ def _generate_fixed_input(self):
+ if self._fixed_data and isinstance(self._fixed_data, bytes):
+ return self._fixed_data
+
+ l_val = utils.int_to_bytes(self._length * 8, self._llen)
+
+ return b"".join([self._label, b"\x00", self._context, l_val])
+
+ 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
index f8ce7a3b..07d8ac67 100644
--- a/src/cryptography/hazmat/primitives/kdf/pbkdf2.py
+++ b/src/cryptography/hazmat/primitives/kdf/pbkdf2.py
@@ -24,15 +24,14 @@ class PBKDF2HMAC(object):
if not backend.pbkdf2_hmac_supported(algorithm):
raise UnsupportedAlgorithm(
- "{0} is not supported for PBKDF2 by this backend.".format(
+ "{} 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.")
+ utils._check_bytes("salt", salt)
self._salt = salt
self._iterations = iterations
self._backend = backend
@@ -42,8 +41,7 @@ class PBKDF2HMAC(object):
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.")
+ utils._check_byteslike("key_material", key_material)
return self._backend.derive_pbkdf2_hmac(
self._algorithm,
self._length,
diff --git a/src/cryptography/hazmat/primitives/kdf/scrypt.py b/src/cryptography/hazmat/primitives/kdf/scrypt.py
new file mode 100644
index 00000000..df9745e6
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/scrypt.py
@@ -0,0 +1,63 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import sys
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import ScryptBackend
+from cryptography.hazmat.primitives import constant_time
+from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
+
+
+# This is used by the scrypt tests to skip tests that require more memory
+# than the MEM_LIMIT
+_MEM_LIMIT = sys.maxsize // 2
+
+
+@utils.register_interface(KeyDerivationFunction)
+class Scrypt(object):
+ def __init__(self, salt, length, n, r, p, backend):
+ if not isinstance(backend, ScryptBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement ScryptBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ self._length = length
+ utils._check_bytes("salt", salt)
+ if n < 2 or (n & (n - 1)) != 0:
+ raise ValueError("n must be greater than 1 and be a power of 2.")
+
+ if r < 1:
+ raise ValueError("r must be greater than or equal to 1.")
+
+ if p < 1:
+ raise ValueError("p must be greater than or equal to 1.")
+
+ self._used = False
+ self._salt = salt
+ self._n = n
+ self._r = r
+ self._p = p
+ self._backend = backend
+
+ def derive(self, key_material):
+ if self._used:
+ raise AlreadyFinalized("Scrypt instances can only be used once.")
+ self._used = True
+
+ utils._check_byteslike("key_material", key_material)
+ return self._backend.derive_scrypt(
+ key_material, self._salt, self._length, self._n, self._r, self._p
+ )
+
+ 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/kdf/x963kdf.py b/src/cryptography/hazmat/primitives/kdf/x963kdf.py
new file mode 100644
index 00000000..9eb50b0f
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/kdf/x963kdf.py
@@ -0,0 +1,68 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import struct
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+)
+from cryptography.hazmat.backends.interfaces import HashBackend
+from cryptography.hazmat.primitives import constant_time, hashes
+from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
+
+
+def _int_to_u32be(n):
+ return struct.pack('>I', n)
+
+
+@utils.register_interface(KeyDerivationFunction)
+class X963KDF(object):
+ def __init__(self, algorithm, length, sharedinfo, backend):
+
+ max_len = algorithm.digest_size * (2 ** 32 - 1)
+ if length > max_len:
+ raise ValueError(
+ "Can not derive keys larger than {} bits.".format(max_len))
+ if sharedinfo is not None:
+ utils._check_bytes("sharedinfo", sharedinfo)
+
+ self._algorithm = algorithm
+ self._length = length
+ self._sharedinfo = sharedinfo
+
+ if not isinstance(backend, HashBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HashBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+ self._backend = backend
+ self._used = False
+
+ def derive(self, key_material):
+ if self._used:
+ raise AlreadyFinalized
+ self._used = True
+ utils._check_byteslike("key_material", key_material)
+ output = [b""]
+ outlen = 0
+ counter = 1
+
+ while self._length > outlen:
+ h = hashes.Hash(self._algorithm, self._backend)
+ h.update(key_material)
+ h.update(_int_to_u32be(counter))
+ if self._sharedinfo is not None:
+ h.update(self._sharedinfo)
+ output.append(h.finalize())
+ outlen += len(output[-1])
+ counter += 1
+
+ return b"".join(output)[:self._length]
+
+ 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/keywrap.py b/src/cryptography/hazmat/primitives/keywrap.py
new file mode 100644
index 00000000..f55c519c
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/keywrap.py
@@ -0,0 +1,154 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import struct
+
+from cryptography.hazmat.primitives.ciphers import Cipher
+from cryptography.hazmat.primitives.ciphers.algorithms import AES
+from cryptography.hazmat.primitives.ciphers.modes import ECB
+from cryptography.hazmat.primitives.constant_time import bytes_eq
+
+
+def _wrap_core(wrapping_key, a, r, backend):
+ # RFC 3394 Key Wrap - 2.2.1 (index method)
+ encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
+ n = len(r)
+ for j in range(6):
+ for i in range(n):
+ # every encryption operation is a discrete 16 byte chunk (because
+ # AES has a 128-bit block size) and since we're using ECB it is
+ # safe to reuse the encryptor for the entire operation
+ b = encryptor.update(a + r[i])
+ # pack/unpack are safe as these are always 64-bit chunks
+ a = struct.pack(
+ ">Q", struct.unpack(">Q", b[:8])[0] ^ ((n * j) + i + 1)
+ )
+ r[i] = b[-8:]
+
+ assert encryptor.finalize() == b""
+
+ return a + b"".join(r)
+
+
+def aes_key_wrap(wrapping_key, key_to_wrap, backend):
+ if len(wrapping_key) not in [16, 24, 32]:
+ raise ValueError("The wrapping key must be a valid AES key length")
+
+ if len(key_to_wrap) < 16:
+ raise ValueError("The key to wrap must be at least 16 bytes")
+
+ if len(key_to_wrap) % 8 != 0:
+ raise ValueError("The key to wrap must be a multiple of 8 bytes")
+
+ a = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
+ r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
+ return _wrap_core(wrapping_key, a, r, backend)
+
+
+def _unwrap_core(wrapping_key, a, r, backend):
+ # Implement RFC 3394 Key Unwrap - 2.2.2 (index method)
+ decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
+ n = len(r)
+ for j in reversed(range(6)):
+ for i in reversed(range(n)):
+ # pack/unpack are safe as these are always 64-bit chunks
+ atr = struct.pack(
+ ">Q", struct.unpack(">Q", a)[0] ^ ((n * j) + i + 1)
+ ) + r[i]
+ # every decryption operation is a discrete 16 byte chunk so
+ # it is safe to reuse the decryptor for the entire operation
+ b = decryptor.update(atr)
+ a = b[:8]
+ r[i] = b[-8:]
+
+ assert decryptor.finalize() == b""
+ return a, r
+
+
+def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend):
+ if len(wrapping_key) not in [16, 24, 32]:
+ raise ValueError("The wrapping key must be a valid AES key length")
+
+ aiv = b"\xA6\x59\x59\xA6" + struct.pack(">i", len(key_to_wrap))
+ # pad the key to wrap if necessary
+ pad = (8 - (len(key_to_wrap) % 8)) % 8
+ key_to_wrap = key_to_wrap + b"\x00" * pad
+ if len(key_to_wrap) == 8:
+ # RFC 5649 - 4.1 - exactly 8 octets after padding
+ encryptor = Cipher(AES(wrapping_key), ECB(), backend).encryptor()
+ b = encryptor.update(aiv + key_to_wrap)
+ assert encryptor.finalize() == b""
+ return b
+ else:
+ r = [key_to_wrap[i:i + 8] for i in range(0, len(key_to_wrap), 8)]
+ return _wrap_core(wrapping_key, aiv, r, backend)
+
+
+def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend):
+ if len(wrapped_key) < 16:
+ raise InvalidUnwrap("Must be at least 16 bytes")
+
+ if len(wrapping_key) not in [16, 24, 32]:
+ raise ValueError("The wrapping key must be a valid AES key length")
+
+ if len(wrapped_key) == 16:
+ # RFC 5649 - 4.2 - exactly two 64-bit blocks
+ decryptor = Cipher(AES(wrapping_key), ECB(), backend).decryptor()
+ b = decryptor.update(wrapped_key)
+ assert decryptor.finalize() == b""
+ a = b[:8]
+ data = b[8:]
+ n = 1
+ else:
+ r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
+ encrypted_aiv = r.pop(0)
+ n = len(r)
+ a, r = _unwrap_core(wrapping_key, encrypted_aiv, r, backend)
+ data = b"".join(r)
+
+ # 1) Check that MSB(32,A) = A65959A6.
+ # 2) Check that 8*(n-1) < LSB(32,A) <= 8*n. If so, let
+ # MLI = LSB(32,A).
+ # 3) Let b = (8*n)-MLI, and then check that the rightmost b octets of
+ # the output data are zero.
+ (mli,) = struct.unpack(">I", a[4:])
+ b = (8 * n) - mli
+ if (
+ not bytes_eq(a[:4], b"\xa6\x59\x59\xa6") or not
+ 8 * (n - 1) < mli <= 8 * n or (
+ b != 0 and not bytes_eq(data[-b:], b"\x00" * b)
+ )
+ ):
+ raise InvalidUnwrap()
+
+ if b == 0:
+ return data
+ else:
+ return data[:-b]
+
+
+def aes_key_unwrap(wrapping_key, wrapped_key, backend):
+ if len(wrapped_key) < 24:
+ raise InvalidUnwrap("Must be at least 24 bytes")
+
+ if len(wrapped_key) % 8 != 0:
+ raise InvalidUnwrap("The wrapped key must be a multiple of 8 bytes")
+
+ if len(wrapping_key) not in [16, 24, 32]:
+ raise ValueError("The wrapping key must be a valid AES key length")
+
+ aiv = b"\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6"
+ r = [wrapped_key[i:i + 8] for i in range(0, len(wrapped_key), 8)]
+ a = r.pop(0)
+ a, r = _unwrap_core(wrapping_key, a, r, backend)
+ if not bytes_eq(a, aiv):
+ raise InvalidUnwrap()
+
+ return b"".join(r)
+
+
+class InvalidUnwrap(Exception):
+ pass
diff --git a/src/cryptography/hazmat/primitives/padding.py b/src/cryptography/hazmat/primitives/padding.py
index f6491eb7..170c8021 100644
--- a/src/cryptography/hazmat/primitives/padding.py
+++ b/src/cryptography/hazmat/primitives/padding.py
@@ -28,14 +28,73 @@ class PaddingContext(object):
"""
-class PKCS7(object):
- def __init__(self, block_size):
- if not (0 <= block_size < 256):
- raise ValueError("block_size must be in range(0, 256).")
+def _byte_padding_check(block_size):
+ if not (0 <= block_size <= 2040):
+ raise ValueError("block_size must be in range(0, 2041).")
+
+ if block_size % 8 != 0:
+ raise ValueError("block_size must be a multiple of 8.")
+
+
+def _byte_padding_update(buffer_, data, block_size):
+ if buffer_ is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ utils._check_bytes("data", data)
+
+ buffer_ += data
+
+ finished_blocks = len(buffer_) // (block_size // 8)
+
+ result = buffer_[:finished_blocks * (block_size // 8)]
+ buffer_ = buffer_[finished_blocks * (block_size // 8):]
+
+ return buffer_, result
+
+
+def _byte_padding_pad(buffer_, block_size, paddingfn):
+ if buffer_ is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ pad_size = block_size // 8 - len(buffer_)
+ return buffer_ + paddingfn(pad_size)
+
+
+def _byte_unpadding_update(buffer_, data, block_size):
+ if buffer_ is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ utils._check_bytes("data", data)
- if block_size % 8 != 0:
- raise ValueError("block_size must be a multiple of 8.")
+ buffer_ += data
+ finished_blocks = max(len(buffer_) // (block_size // 8) - 1, 0)
+
+ result = buffer_[:finished_blocks * (block_size // 8)]
+ buffer_ = buffer_[finished_blocks * (block_size // 8):]
+
+ return buffer_, result
+
+
+def _byte_unpadding_check(buffer_, block_size, checkfn):
+ if buffer_ is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ if len(buffer_) != block_size // 8:
+ raise ValueError("Invalid padding bytes.")
+
+ valid = checkfn(buffer_, block_size // 8)
+
+ if not valid:
+ raise ValueError("Invalid padding bytes.")
+
+ pad_size = six.indexbytes(buffer_, -1)
+ return buffer_[:-pad_size]
+
+
+class PKCS7(object):
+ def __init__(self, block_size):
+ _byte_padding_check(block_size)
self.block_size = block_size
def padder(self):
@@ -53,27 +112,16 @@ class _PKCS7PaddingContext(object):
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):]
-
+ self._buffer, result = _byte_padding_update(
+ self._buffer, data, self.block_size)
return result
- def finalize(self):
- if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized.")
+ def _padding(self, size):
+ return six.int2byte(size) * size
- pad_size = self.block_size // 8 - len(self._buffer)
- result = self._buffer + six.int2byte(pad_size) * pad_size
+ def finalize(self):
+ result = _byte_padding_pad(
+ self._buffer, self.block_size, self._padding)
self._buffer = None
return result
@@ -86,39 +134,67 @@ class _PKCS7UnpaddingContext(object):
self._buffer = b""
def update(self, data):
- if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized.")
+ self._buffer, result = _byte_unpadding_update(
+ self._buffer, data, self.block_size)
+ return result
+
+ def finalize(self):
+ result = _byte_unpadding_check(
+ self._buffer, self.block_size,
+ lib.Cryptography_check_pkcs7_padding)
+ self._buffer = None
+ return result
- if not isinstance(data, bytes):
- raise TypeError("data must be bytes.")
- self._buffer += data
+class ANSIX923(object):
+ def __init__(self, block_size):
+ _byte_padding_check(block_size)
+ self.block_size = block_size
+
+ def padder(self):
+ return _ANSIX923PaddingContext(self.block_size)
+
+ def unpadder(self):
+ return _ANSIX923UnpaddingContext(self.block_size)
- 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):]
+@utils.register_interface(PaddingContext)
+class _ANSIX923PaddingContext(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):
+ self._buffer, result = _byte_padding_update(
+ self._buffer, data, self.block_size)
return result
+ def _padding(self, size):
+ return six.int2byte(0) * (size - 1) + six.int2byte(size)
+
def finalize(self):
- if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized.")
+ result = _byte_padding_pad(
+ self._buffer, self.block_size, self._padding)
+ self._buffer = None
+ return result
- 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
- )
+@utils.register_interface(PaddingContext)
+class _ANSIX923UnpaddingContext(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""
- if not valid:
- raise ValueError("Invalid padding bytes.")
+ def update(self, data):
+ self._buffer, result = _byte_unpadding_update(
+ self._buffer, data, self.block_size)
+ return result
- pad_size = six.indexbytes(self._buffer, -1)
- res = self._buffer[:-pad_size]
+ def finalize(self):
+ result = _byte_unpadding_check(
+ self._buffer, self.block_size,
+ lib.Cryptography_check_ansix923_padding)
self._buffer = None
- return res
+ return result
diff --git a/src/cryptography/hazmat/primitives/poly1305.py b/src/cryptography/hazmat/primitives/poly1305.py
new file mode 100644
index 00000000..d92f62ad
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/poly1305.py
@@ -0,0 +1,55 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+
+from cryptography import utils
+from cryptography.exceptions import (
+ AlreadyFinalized, UnsupportedAlgorithm, _Reasons
+)
+
+
+class Poly1305(object):
+ def __init__(self, key):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not backend.poly1305_supported():
+ raise UnsupportedAlgorithm(
+ "poly1305 is not supported by this version of OpenSSL.",
+ _Reasons.UNSUPPORTED_MAC
+ )
+ self._ctx = backend.create_poly1305_ctx(key)
+
+ def update(self, data):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ utils._check_byteslike("data", data)
+ self._ctx.update(data)
+
+ def finalize(self):
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+ mac = self._ctx.finalize()
+ self._ctx = None
+ return mac
+
+ def verify(self, tag):
+ utils._check_bytes("tag", tag)
+ if self._ctx is None:
+ raise AlreadyFinalized("Context was already finalized.")
+
+ ctx, self._ctx = self._ctx, None
+ ctx.verify(tag)
+
+ @classmethod
+ def generate_tag(cls, key, data):
+ p = Poly1305(key)
+ p.update(data)
+ return p.finalize()
+
+ @classmethod
+ def verify_tag(cls, key, data, tag):
+ p = Poly1305(key)
+ p.update(data)
+ p.verify(tag)
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
deleted file mode 100644
index 8699fa91..00000000
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ /dev/null
@@ -1,203 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-import abc
-import base64
-import struct
-from enum import Enum
-
-import six
-
-from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
-
-
-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)
-
-
-def load_der_private_key(data, password, backend):
- return backend.load_der_private_key(data, password)
-
-
-def load_der_public_key(data, backend):
- return backend.load_der_public_key(data)
-
-
-def load_ssh_public_key(data, backend):
- key_parts = data.split(b' ')
-
- if len(key_parts) != 2 and len(key_parts) != 3:
- raise ValueError(
- 'Key is not in the proper format or contains extra data.')
-
- key_type = key_parts[0]
-
- if key_type == b'ssh-rsa':
- loader = _load_ssh_rsa_public_key
- elif key_type == b'ssh-dss':
- loader = _load_ssh_dss_public_key
- elif key_type in [
- b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521',
- ]:
- loader = _load_ssh_ecdsa_public_key
- else:
- raise UnsupportedAlgorithm('Key type is not supported.')
-
- key_body = key_parts[1]
-
- try:
- decoded_data = base64.b64decode(key_body)
- except TypeError:
- raise ValueError('Key is not in the proper format.')
-
- inner_key_type, rest = _read_next_string(decoded_data)
-
- if inner_key_type != key_type:
- raise ValueError(
- 'Key header and key body contain different key type values.'
- )
-
- return loader(key_type, rest, backend)
-
-
-def _load_ssh_rsa_public_key(key_type, decoded_data, backend):
- e, rest = _read_next_mpint(decoded_data)
- n, rest = _read_next_mpint(rest)
-
- if rest:
- raise ValueError('Key body contains extra bytes.')
-
- return rsa.RSAPublicNumbers(e, n).public_key(backend)
-
-
-def _load_ssh_dss_public_key(key_type, decoded_data, backend):
- p, rest = _read_next_mpint(decoded_data)
- q, rest = _read_next_mpint(rest)
- g, rest = _read_next_mpint(rest)
- y, rest = _read_next_mpint(rest)
-
- if rest:
- raise ValueError('Key body contains extra bytes.')
-
- parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
- public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
-
- return public_numbers.public_key(backend)
-
-
-def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend):
- curve_name, rest = _read_next_string(decoded_data)
- data, rest = _read_next_string(rest)
-
- if expected_key_type != b"ecdsa-sha2-" + curve_name:
- raise ValueError(
- 'Key header and key body contain different key type values.'
- )
-
- if rest:
- raise ValueError('Key body contains extra bytes.')
-
- if curve_name == b"nistp256":
- curve = ec.SECP256R1()
- elif curve_name == b"nistp384":
- curve = ec.SECP384R1()
- elif curve_name == b"nistp521":
- curve = ec.SECP521R1()
-
- if six.indexbytes(data, 0) != 4:
- raise NotImplementedError(
- "Compressed elliptic curve points are not supported"
- )
-
- # key_size is in bits, and sometimes it's not evenly divisible by 8, so we
- # add 7 to round up the number of bytes.
- if len(data) != 1 + 2 * ((curve.key_size + 7) // 8):
- raise ValueError("Malformed key bytes")
-
- x = _int_from_bytes(data[1:1 + (curve.key_size + 7) // 8], byteorder='big')
- y = _int_from_bytes(data[1 + (curve.key_size + 7) // 8:], byteorder='big')
- return ec.EllipticCurvePublicNumbers(x, y, curve).public_key(backend)
-
-
-def _read_next_string(data):
- """
- Retrieves the next RFC 4251 string value from the data.
-
- While the RFC calls these strings, in Python they are bytes objects.
- """
- str_len, = struct.unpack('>I', data[:4])
- return data[4:4 + str_len], data[4 + str_len:]
-
-
-def _read_next_mpint(data):
- """
- Reads the next mpint from the data.
-
- Currently, all mpints are interpreted as unsigned.
- """
- mpint_data, rest = _read_next_string(data)
-
- return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest
-
-
-if hasattr(int, "from_bytes"):
- _int_from_bytes = int.from_bytes
-else:
- def _int_from_bytes(data, byteorder, signed=False):
- assert byteorder == 'big'
- assert not signed
-
- if len(data) % 4 != 0:
- data = (b'\x00' * (4 - (len(data) % 4))) + data
-
- result = 0
-
- while len(data) > 0:
- digit, = struct.unpack('>I', data[:4])
- result = (result << 32) + digit
- data = data[4:]
-
- return result
-
-
-class Encoding(Enum):
- PEM = "PEM"
- DER = "DER"
-
-
-class PrivateFormat(Enum):
- PKCS8 = "PKCS8"
- TraditionalOpenSSL = "TraditionalOpenSSL"
-
-
-class PublicFormat(Enum):
- SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1"
- PKCS1 = "Raw PKCS#1"
-
-
-@six.add_metaclass(abc.ABCMeta)
-class KeySerializationEncryption(object):
- pass
-
-
-@utils.register_interface(KeySerializationEncryption)
-class BestAvailableEncryption(object):
- def __init__(self, password):
- if not isinstance(password, bytes) or len(password) == 0:
- raise ValueError("Password must be 1 or more bytes.")
-
- self.password = password
-
-
-@utils.register_interface(KeySerializationEncryption)
-class NoEncryption(object):
- pass
diff --git a/src/cryptography/hazmat/primitives/serialization/__init__.py b/src/cryptography/hazmat/primitives/serialization/__init__.py
new file mode 100644
index 00000000..b910751b
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/serialization/__init__.py
@@ -0,0 +1,24 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography.hazmat.primitives.serialization.base import (
+ BestAvailableEncryption, Encoding, KeySerializationEncryption,
+ NoEncryption, ParameterFormat, PrivateFormat, PublicFormat,
+ load_der_parameters, load_der_private_key, load_der_public_key,
+ load_pem_parameters, load_pem_private_key, load_pem_public_key,
+)
+from cryptography.hazmat.primitives.serialization.ssh import (
+ load_ssh_public_key
+)
+
+
+__all__ = [
+ "load_der_parameters", "load_der_private_key", "load_der_public_key",
+ "load_pem_parameters", "load_pem_private_key", "load_pem_public_key",
+ "load_ssh_public_key", "Encoding", "PrivateFormat", "PublicFormat",
+ "ParameterFormat", "KeySerializationEncryption", "BestAvailableEncryption",
+ "NoEncryption",
+]
diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py
new file mode 100644
index 00000000..4218ea82
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/serialization/base.py
@@ -0,0 +1,82 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+from enum import Enum
+
+import six
+
+from cryptography import utils
+
+
+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)
+
+
+def load_pem_parameters(data, backend):
+ return backend.load_pem_parameters(data)
+
+
+def load_der_private_key(data, password, backend):
+ return backend.load_der_private_key(data, password)
+
+
+def load_der_public_key(data, backend):
+ return backend.load_der_public_key(data)
+
+
+def load_der_parameters(data, backend):
+ return backend.load_der_parameters(data)
+
+
+class Encoding(Enum):
+ PEM = "PEM"
+ DER = "DER"
+ OpenSSH = "OpenSSH"
+ Raw = "Raw"
+ X962 = "ANSI X9.62"
+
+
+class PrivateFormat(Enum):
+ PKCS8 = "PKCS8"
+ TraditionalOpenSSL = "TraditionalOpenSSL"
+ Raw = "Raw"
+
+
+class PublicFormat(Enum):
+ SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1"
+ PKCS1 = "Raw PKCS#1"
+ OpenSSH = "OpenSSH"
+ Raw = "Raw"
+ CompressedPoint = "X9.62 Compressed Point"
+ UncompressedPoint = "X9.62 Uncompressed Point"
+
+
+class ParameterFormat(Enum):
+ PKCS3 = "PKCS3"
+
+
+@six.add_metaclass(abc.ABCMeta)
+class KeySerializationEncryption(object):
+ pass
+
+
+@utils.register_interface(KeySerializationEncryption)
+class BestAvailableEncryption(object):
+ def __init__(self, password):
+ if not isinstance(password, bytes) or len(password) == 0:
+ raise ValueError("Password must be 1 or more bytes.")
+
+ self.password = password
+
+
+@utils.register_interface(KeySerializationEncryption)
+class NoEncryption(object):
+ pass
diff --git a/src/cryptography/hazmat/backends/commoncrypto/__init__.py b/src/cryptography/hazmat/primitives/serialization/pkcs12.py
index 1d52a255..98161d57 100644
--- a/src/cryptography/hazmat/backends/commoncrypto/__init__.py
+++ b/src/cryptography/hazmat/primitives/serialization/pkcs12.py
@@ -4,7 +4,6 @@
from __future__ import absolute_import, division, print_function
-from cryptography.hazmat.backends.commoncrypto.backend import backend
-
-__all__ = ["backend"]
+def load_key_and_certificates(data, password, backend):
+ return backend.load_key_and_certificates_from_pkcs12(data, password)
diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py
new file mode 100644
index 00000000..a1d6c8c9
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/serialization/ssh.py
@@ -0,0 +1,153 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import base64
+import struct
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa
+
+
+def load_ssh_public_key(data, backend):
+ key_parts = data.split(b' ', 2)
+
+ if len(key_parts) < 2:
+ raise ValueError(
+ 'Key is not in the proper format or contains extra data.')
+
+ key_type = key_parts[0]
+
+ if key_type == b'ssh-rsa':
+ loader = _load_ssh_rsa_public_key
+ elif key_type == b'ssh-dss':
+ loader = _load_ssh_dss_public_key
+ elif key_type in [
+ b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521',
+ ]:
+ loader = _load_ssh_ecdsa_public_key
+ elif key_type == b'ssh-ed25519':
+ loader = _load_ssh_ed25519_public_key
+ else:
+ raise UnsupportedAlgorithm('Key type is not supported.')
+
+ key_body = key_parts[1]
+
+ try:
+ decoded_data = base64.b64decode(key_body)
+ except TypeError:
+ raise ValueError('Key is not in the proper format.')
+
+ inner_key_type, rest = _ssh_read_next_string(decoded_data)
+
+ if inner_key_type != key_type:
+ raise ValueError(
+ 'Key header and key body contain different key type values.'
+ )
+
+ return loader(key_type, rest, backend)
+
+
+def _load_ssh_rsa_public_key(key_type, decoded_data, backend):
+ e, rest = _ssh_read_next_mpint(decoded_data)
+ n, rest = _ssh_read_next_mpint(rest)
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ return rsa.RSAPublicNumbers(e, n).public_key(backend)
+
+
+def _load_ssh_dss_public_key(key_type, decoded_data, backend):
+ p, rest = _ssh_read_next_mpint(decoded_data)
+ q, rest = _ssh_read_next_mpint(rest)
+ g, rest = _ssh_read_next_mpint(rest)
+ y, rest = _ssh_read_next_mpint(rest)
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
+ public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
+
+ return public_numbers.public_key(backend)
+
+
+def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend):
+ curve_name, rest = _ssh_read_next_string(decoded_data)
+ data, rest = _ssh_read_next_string(rest)
+
+ if expected_key_type != b"ecdsa-sha2-" + curve_name:
+ raise ValueError(
+ 'Key header and key body contain different key type values.'
+ )
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ curve = {
+ b"nistp256": ec.SECP256R1,
+ b"nistp384": ec.SECP384R1,
+ b"nistp521": ec.SECP521R1,
+ }[curve_name]()
+
+ if six.indexbytes(data, 0) != 4:
+ raise NotImplementedError(
+ "Compressed elliptic curve points are not supported"
+ )
+
+ return ec.EllipticCurvePublicKey.from_encoded_point(curve, data)
+
+
+def _load_ssh_ed25519_public_key(expected_key_type, decoded_data, backend):
+ data, rest = _ssh_read_next_string(decoded_data)
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ return ed25519.Ed25519PublicKey.from_public_bytes(data)
+
+
+def _ssh_read_next_string(data):
+ """
+ Retrieves the next RFC 4251 string value from the data.
+
+ While the RFC calls these strings, in Python they are bytes objects.
+ """
+ if len(data) < 4:
+ raise ValueError("Key is not in the proper format")
+
+ str_len, = struct.unpack('>I', data[:4])
+ if len(data) < str_len + 4:
+ raise ValueError("Key is not in the proper format")
+
+ return data[4:4 + str_len], data[4 + str_len:]
+
+
+def _ssh_read_next_mpint(data):
+ """
+ Reads the next mpint from the data.
+
+ Currently, all mpints are interpreted as unsigned.
+ """
+ mpint_data, rest = _ssh_read_next_string(data)
+
+ return (
+ utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
+ )
+
+
+def _ssh_write_string(data):
+ return struct.pack(">I", len(data)) + data
+
+
+def _ssh_write_mpint(value):
+ data = utils.int_to_bytes(value)
+ if six.indexbytes(data, 0) & 0x80:
+ data = b"\x00" + data
+ return _ssh_write_string(data)
diff --git a/src/cryptography/hazmat/primitives/twofactor/hotp.py b/src/cryptography/hazmat/primitives/twofactor/hotp.py
index 12bc7661..4ad1bdc2 100644
--- a/src/cryptography/hazmat/primitives/twofactor/hotp.py
+++ b/src/cryptography/hazmat/primitives/twofactor/hotp.py
@@ -19,14 +19,15 @@ from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class HOTP(object):
- def __init__(self, key, length, algorithm, backend):
+ def __init__(self, key, length, algorithm, backend,
+ enforce_key_length=True):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
- if len(key) < 16:
+ if len(key) < 16 and enforce_key_length is True:
raise ValueError("Key length has to be at least 128 bits.")
if not isinstance(length, six.integer_types):
diff --git a/src/cryptography/hazmat/primitives/twofactor/totp.py b/src/cryptography/hazmat/primitives/twofactor/totp.py
index 60705901..499f2824 100644
--- a/src/cryptography/hazmat/primitives/twofactor/totp.py
+++ b/src/cryptography/hazmat/primitives/twofactor/totp.py
@@ -15,7 +15,8 @@ from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class TOTP(object):
- def __init__(self, key, length, algorithm, time_step, backend):
+ def __init__(self, key, length, algorithm, time_step, backend,
+ enforce_key_length=True):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
@@ -23,7 +24,7 @@ class TOTP(object):
)
self._time_step = time_step
- self._hotp = HOTP(key, length, algorithm, backend)
+ self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length)
def generate(self, time):
counter = int(time / self._time_step)
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 0bf8c0ea..ff4f81d2 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -5,12 +5,35 @@
from __future__ import absolute_import, division, print_function
import abc
+import binascii
import inspect
import sys
import warnings
-DeprecatedIn09 = DeprecationWarning
+# We use a UserWarning subclass, instead of DeprecationWarning, because CPython
+# decided deprecation warnings should be invisble by default.
+class CryptographyDeprecationWarning(UserWarning):
+ pass
+
+
+# Several APIs were deprecated with no specific end-of-life date because of the
+# ubiquity of their use. They should not be removed until we agree on when that
+# cycle ends.
+PersistentlyDeprecated2017 = CryptographyDeprecationWarning
+PersistentlyDeprecated2019 = CryptographyDeprecationWarning
+
+
+def _check_bytes(name, value):
+ if not isinstance(value, bytes):
+ raise TypeError("{} must be bytes".format(name))
+
+
+def _check_byteslike(name, value):
+ try:
+ memoryview(value)
+ except TypeError:
+ raise TypeError("{} must be bytes-like".format(name))
def read_only_property(name):
@@ -25,36 +48,74 @@ def register_interface(iface):
return register_decorator
+def register_interface_if(predicate, iface):
+ def register_decorator(klass):
+ if predicate:
+ verify_interface(iface, klass)
+ iface.register(klass)
+ return klass
+ return register_decorator
+
+
+if hasattr(int, "from_bytes"):
+ int_from_bytes = int.from_bytes
+else:
+ def int_from_bytes(data, byteorder, signed=False):
+ assert byteorder == 'big'
+ assert not signed
+
+ return int(binascii.hexlify(data), 16)
+
+
+if hasattr(int, "to_bytes"):
+ def int_to_bytes(integer, length=None):
+ return integer.to_bytes(
+ length or (integer.bit_length() + 7) // 8 or 1, 'big'
+ )
+else:
+ def int_to_bytes(integer, length=None):
+ hex_string = '%x' % integer
+ if length is None:
+ n = len(hex_string)
+ else:
+ n = length * 2
+ return binascii.unhexlify(hex_string.zfill(n + (n & 1)))
+
+
class InterfaceNotImplemented(Exception):
pass
+if hasattr(inspect, "signature"):
+ signature = inspect.signature
+else:
+ signature = inspect.getargspec
+
+
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)
+ "{} is missing a {!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:
+ sig = signature(getattr(iface, method))
+ actual = signature(getattr(klass, method))
+ if sig != actual:
raise InterfaceNotImplemented(
- "{0}.{1}'s signature differs from the expected. Expected: "
- "{2!r}. Received: {3!r}".format(
- klass, method, spec, actual
+ "{}.{}'s signature differs from the expected. Expected: "
+ "{!r}. Received: {!r}".format(
+ klass, method, sig, actual
)
)
-if sys.version_info >= (2, 7):
- def bit_length(x):
- return x.bit_length()
-else:
- def bit_length(x):
- return len(bin(x)) - (2 + (x <= 0))
+# No longer needed as of 2.2, but retained because we have external consumers
+# who use it.
+def bit_length(x):
+ return x.bit_length()
class _DeprecatedValue(object):
@@ -78,6 +139,13 @@ class _ModuleWithDeprecations(object):
def __setattr__(self, attr, value):
setattr(self._module, attr, value)
+ def __delattr__(self, attr):
+ obj = getattr(self._module, attr)
+ if isinstance(obj, _DeprecatedValue):
+ warnings.warn(obj.message, obj.warning_class, stacklevel=2)
+
+ delattr(self._module, attr)
+
def __dir__(self):
return ["_module"] + dir(self._module)
@@ -85,5 +153,19 @@ class _ModuleWithDeprecations(object):
def deprecated(value, module_name, message, warning_class):
module = sys.modules[module_name]
if not isinstance(module, _ModuleWithDeprecations):
- sys.modules[module_name] = module = _ModuleWithDeprecations(module)
+ sys.modules[module_name] = _ModuleWithDeprecations(module)
return _DeprecatedValue(value, message, warning_class)
+
+
+def cached_property(func):
+ cached_name = "_cached_{}".format(func)
+ sentinel = object()
+
+ def inner(instance):
+ cache = getattr(instance, cached_name, sentinel)
+ if cache is not sentinel:
+ return cache
+ result = func(instance)
+ setattr(instance, cached_name, result)
+ return result
+ return property(inner)
diff --git a/src/cryptography/x509.py b/src/cryptography/x509.py
deleted file mode 100644
index 0f72abb3..00000000
--- a/src/cryptography/x509.py
+++ /dev/null
@@ -1,1489 +0,0 @@
-# This file is dual licensed under the terms of the Apache License, Version
-# 2.0, and the BSD License. See the LICENSE file in the root of this repository
-# for complete details.
-
-from __future__ import absolute_import, division, print_function
-
-import abc
-import ipaddress
-from enum import Enum
-
-import six
-
-from cryptography import utils
-from cryptography.hazmat.primitives import hashes
-
-
-_OID_NAMES = {
- "2.5.4.3": "commonName",
- "2.5.4.6": "countryName",
- "2.5.4.7": "localityName",
- "2.5.4.8": "stateOrProvinceName",
- "2.5.4.10": "organizationName",
- "2.5.4.11": "organizationalUnitName",
- "2.5.4.5": "serialNumber",
- "2.5.4.4": "surname",
- "2.5.4.42": "givenName",
- "2.5.4.12": "title",
- "2.5.4.44": "generationQualifier",
- "2.5.4.46": "dnQualifier",
- "2.5.4.65": "pseudonym",
- "0.9.2342.19200300.100.1.25": "domainComponent",
- "1.2.840.113549.1.9.1": "emailAddress",
- "1.2.840.113549.1.1.4": "md5WithRSAEncryption",
- "1.2.840.113549.1.1.5": "sha1WithRSAEncryption",
- "1.2.840.113549.1.1.14": "sha224WithRSAEncryption",
- "1.2.840.113549.1.1.11": "sha256WithRSAEncryption",
- "1.2.840.113549.1.1.12": "sha384WithRSAEncryption",
- "1.2.840.113549.1.1.13": "sha512WithRSAEncryption",
- "1.2.840.10045.4.1": "ecdsa-with-SHA1",
- "1.2.840.10045.4.3.1": "ecdsa-with-SHA224",
- "1.2.840.10045.4.3.2": "ecdsa-with-SHA256",
- "1.2.840.10045.4.3.3": "ecdsa-with-SHA384",
- "1.2.840.10045.4.3.4": "ecdsa-with-SHA512",
- "1.2.840.10040.4.3": "dsa-with-sha1",
- "2.16.840.1.101.3.4.3.1": "dsa-with-sha224",
- "2.16.840.1.101.3.4.3.2": "dsa-with-sha256",
- "1.3.6.1.5.5.7.3.1": "serverAuth",
- "1.3.6.1.5.5.7.3.2": "clientAuth",
- "1.3.6.1.5.5.7.3.3": "codeSigning",
- "1.3.6.1.5.5.7.3.4": "emailProtection",
- "1.3.6.1.5.5.7.3.8": "timeStamping",
- "1.3.6.1.5.5.7.3.9": "OCSPSigning",
- "2.5.29.9": "subjectDirectoryAttributes",
- "2.5.29.14": "subjectKeyIdentifier",
- "2.5.29.15": "keyUsage",
- "2.5.29.17": "subjectAltName",
- "2.5.29.18": "issuerAltName",
- "2.5.29.19": "basicConstraints",
- "2.5.29.21": "cRLReason",
- "2.5.29.24": "invalidityDate",
- "2.5.29.29": "certificateIssuer",
- "2.5.29.30": "nameConstraints",
- "2.5.29.31": "cRLDistributionPoints",
- "2.5.29.32": "certificatePolicies",
- "2.5.29.33": "policyMappings",
- "2.5.29.35": "authorityKeyIdentifier",
- "2.5.29.36": "policyConstraints",
- "2.5.29.37": "extendedKeyUsage",
- "2.5.29.46": "freshestCRL",
- "2.5.29.54": "inhibitAnyPolicy",
- "1.3.6.1.5.5.7.1.1": "authorityInfoAccess",
- "1.3.6.1.5.5.7.1.11": "subjectInfoAccess",
- "1.3.6.1.5.5.7.48.1.5": "OCSPNoCheck",
- "1.3.6.1.5.5.7.48.1": "OCSP",
- "1.3.6.1.5.5.7.48.2": "caIssuers",
- "1.3.6.1.5.5.7.2.1": "id-qt-cps",
- "1.3.6.1.5.5.7.2.2": "id-qt-unotice",
-}
-
-
-_GENERAL_NAMES = {
- 0: "otherName",
- 1: "rfc822Name",
- 2: "dNSName",
- 3: "x400Address",
- 4: "directoryName",
- 5: "ediPartyName",
- 6: "uniformResourceIdentifier",
- 7: "iPAddress",
- 8: "registeredID",
-}
-
-
-class Version(Enum):
- v1 = 0
- v3 = 2
-
-
-def load_pem_x509_certificate(data, backend):
- return backend.load_pem_x509_certificate(data)
-
-
-def load_der_x509_certificate(data, backend):
- return backend.load_der_x509_certificate(data)
-
-
-def load_pem_x509_csr(data, backend):
- return backend.load_pem_x509_csr(data)
-
-
-def load_der_x509_csr(data, backend):
- return backend.load_der_x509_csr(data)
-
-
-class InvalidVersion(Exception):
- def __init__(self, msg, parsed_version):
- super(InvalidVersion, self).__init__(msg)
- self.parsed_version = parsed_version
-
-
-class DuplicateExtension(Exception):
- def __init__(self, msg, oid):
- super(DuplicateExtension, self).__init__(msg)
- self.oid = oid
-
-
-class UnsupportedExtension(Exception):
- def __init__(self, msg, oid):
- super(UnsupportedExtension, self).__init__(msg)
- self.oid = oid
-
-
-class ExtensionNotFound(Exception):
- def __init__(self, msg, oid):
- super(ExtensionNotFound, self).__init__(msg)
- self.oid = oid
-
-
-class UnsupportedGeneralNameType(Exception):
- def __init__(self, msg, type):
- super(UnsupportedGeneralNameType, self).__init__(msg)
- self.type = type
-
-
-class NameAttribute(object):
- def __init__(self, oid, value):
- if not isinstance(oid, ObjectIdentifier):
- raise TypeError(
- "oid argument must be an ObjectIdentifier instance."
- )
-
- if not isinstance(value, six.text_type):
- raise TypeError(
- "value argument must be a text type."
- )
-
- self._oid = oid
- self._value = value
-
- oid = utils.read_only_property("_oid")
- value = utils.read_only_property("_value")
-
- def __eq__(self, other):
- if not isinstance(other, NameAttribute):
- return NotImplemented
-
- return (
- self.oid == other.oid and
- self.value == other.value
- )
-
- def __ne__(self, other):
- return not self == other
-
- def __repr__(self):
- return "<NameAttribute(oid={0.oid}, value={0.value!r})>".format(self)
-
-
-class ObjectIdentifier(object):
- def __init__(self, dotted_string):
- self._dotted_string = dotted_string
-
- def __eq__(self, other):
- if not isinstance(other, ObjectIdentifier):
- return NotImplemented
-
- return self._dotted_string == other._dotted_string
-
- def __ne__(self, other):
- return not self == other
-
- def __repr__(self):
- return "<ObjectIdentifier(oid={0}, name={1})>".format(
- self._dotted_string,
- _OID_NAMES.get(self._dotted_string, "Unknown OID")
- )
-
- def __hash__(self):
- return hash(self.dotted_string)
-
- dotted_string = utils.read_only_property("_dotted_string")
-
-
-class Name(object):
- def __init__(self, attributes):
- self._attributes = attributes
-
- def get_attributes_for_oid(self, oid):
- return [i for i in self if i.oid == oid]
-
- def __eq__(self, other):
- if not isinstance(other, Name):
- return NotImplemented
-
- return self._attributes == other._attributes
-
- def __ne__(self, other):
- return not self == other
-
- def __iter__(self):
- return iter(self._attributes)
-
- def __len__(self):
- return len(self._attributes)
-
- def __repr__(self):
- return "<Name({0!r})>".format(self._attributes)
-
-
-OID_SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9")
-OID_SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14")
-OID_KEY_USAGE = ObjectIdentifier("2.5.29.15")
-OID_SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17")
-OID_ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18")
-OID_BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
-OID_CRL_REASON = ObjectIdentifier("2.5.29.21")
-OID_INVALIDITY_DATE = ObjectIdentifier("2.5.29.24")
-OID_CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29")
-OID_NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30")
-OID_CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31")
-OID_CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32")
-OID_POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33")
-OID_AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35")
-OID_POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36")
-OID_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37")
-OID_FRESHEST_CRL = ObjectIdentifier("2.5.29.46")
-OID_INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54")
-OID_AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1")
-OID_SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11")
-OID_OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
-
-
-class Extensions(object):
- def __init__(self, extensions):
- self._extensions = extensions
-
- def get_extension_for_oid(self, oid):
- for ext in self:
- if ext.oid == oid:
- return ext
-
- raise ExtensionNotFound("No {0} extension was found".format(oid), oid)
-
- def __iter__(self):
- return iter(self._extensions)
-
- def __len__(self):
- return len(self._extensions)
-
-
-class Extension(object):
- def __init__(self, oid, critical, value):
- if not isinstance(oid, ObjectIdentifier):
- raise TypeError(
- "oid argument must be an ObjectIdentifier instance."
- )
-
- if not isinstance(critical, bool):
- raise TypeError("critical must be a boolean value")
-
- self._oid = oid
- self._critical = critical
- self._value = value
-
- oid = utils.read_only_property("_oid")
- critical = utils.read_only_property("_critical")
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return ("<Extension(oid={0.oid}, critical={0.critical}, "
- "value={0.value})>").format(self)
-
- def __eq__(self, other):
- if not isinstance(other, Extension):
- return NotImplemented
-
- return (
- self.oid == other.oid and
- self.critical == other.critical and
- self.value == other.value
- )
-
- def __ne__(self, other):
- return not self == other
-
-
-class ExtendedKeyUsage(object):
- def __init__(self, usages):
- if not all(isinstance(x, ObjectIdentifier) for x in usages):
- raise TypeError(
- "Every item in the usages list must be an ObjectIdentifier"
- )
-
- self._usages = usages
-
- def __iter__(self):
- return iter(self._usages)
-
- def __len__(self):
- return len(self._usages)
-
- def __repr__(self):
- return "<ExtendedKeyUsage({0})>".format(self._usages)
-
- def __eq__(self, other):
- if not isinstance(other, ExtendedKeyUsage):
- return NotImplemented
-
- return self._usages == other._usages
-
- def __ne__(self, other):
- return not self == other
-
-
-class OCSPNoCheck(object):
- pass
-
-
-class BasicConstraints(object):
- def __init__(self, ca, path_length):
- if not isinstance(ca, bool):
- raise TypeError("ca must be a boolean value")
-
- if path_length is not None and not ca:
- raise ValueError("path_length must be None when ca is False")
-
- if (
- path_length is not None and
- (not isinstance(path_length, six.integer_types) or path_length < 0)
- ):
- raise TypeError(
- "path_length must be a non-negative integer or None"
- )
-
- self._ca = ca
- self._path_length = path_length
-
- ca = utils.read_only_property("_ca")
- path_length = utils.read_only_property("_path_length")
-
- def __repr__(self):
- return ("<BasicConstraints(ca={0.ca}, "
- "path_length={0.path_length})>").format(self)
-
- def __eq__(self, other):
- if not isinstance(other, BasicConstraints):
- return NotImplemented
-
- return self.ca == other.ca and self.path_length == other.path_length
-
- def __ne__(self, other):
- return not self == other
-
-
-class KeyUsage(object):
- def __init__(self, digital_signature, content_commitment, key_encipherment,
- data_encipherment, key_agreement, key_cert_sign, crl_sign,
- encipher_only, decipher_only):
- if not key_agreement and (encipher_only or decipher_only):
- raise ValueError(
- "encipher_only and decipher_only can only be true when "
- "key_agreement is true"
- )
-
- self._digital_signature = digital_signature
- self._content_commitment = content_commitment
- self._key_encipherment = key_encipherment
- self._data_encipherment = data_encipherment
- self._key_agreement = key_agreement
- self._key_cert_sign = key_cert_sign
- self._crl_sign = crl_sign
- self._encipher_only = encipher_only
- self._decipher_only = decipher_only
-
- digital_signature = utils.read_only_property("_digital_signature")
- content_commitment = utils.read_only_property("_content_commitment")
- key_encipherment = utils.read_only_property("_key_encipherment")
- data_encipherment = utils.read_only_property("_data_encipherment")
- key_agreement = utils.read_only_property("_key_agreement")
- key_cert_sign = utils.read_only_property("_key_cert_sign")
- crl_sign = utils.read_only_property("_crl_sign")
-
- @property
- def encipher_only(self):
- if not self.key_agreement:
- raise ValueError(
- "encipher_only is undefined unless key_agreement is true"
- )
- else:
- return self._encipher_only
-
- @property
- def decipher_only(self):
- if not self.key_agreement:
- raise ValueError(
- "decipher_only is undefined unless key_agreement is true"
- )
- else:
- return self._decipher_only
-
- def __repr__(self):
- try:
- encipher_only = self.encipher_only
- decipher_only = self.decipher_only
- except ValueError:
- encipher_only = None
- decipher_only = None
-
- return ("<KeyUsage(digital_signature={0.digital_signature}, "
- "content_commitment={0.content_commitment}, "
- "key_encipherment={0.key_encipherment}, "
- "data_encipherment={0.data_encipherment}, "
- "key_agreement={0.key_agreement}, "
- "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
- "encipher_only={1}, decipher_only={2})>").format(
- self, encipher_only, decipher_only)
-
- def __eq__(self, other):
- if not isinstance(other, KeyUsage):
- return NotImplemented
-
- return (
- self.digital_signature == other.digital_signature and
- self.content_commitment == other.content_commitment and
- self.key_encipherment == other.key_encipherment and
- self.data_encipherment == other.data_encipherment and
- self.key_agreement == other.key_agreement and
- self.key_cert_sign == other.key_cert_sign and
- self.crl_sign == other.crl_sign and
- self._encipher_only == other._encipher_only and
- self._decipher_only == other._decipher_only
- )
-
- def __ne__(self, other):
- return not self == other
-
-
-class AuthorityInformationAccess(object):
- def __init__(self, descriptions):
- if not all(isinstance(x, AccessDescription) for x in descriptions):
- raise TypeError(
- "Every item in the descriptions list must be an "
- "AccessDescription"
- )
-
- self._descriptions = descriptions
-
- def __iter__(self):
- return iter(self._descriptions)
-
- def __len__(self):
- return len(self._descriptions)
-
- def __repr__(self):
- return "<AuthorityInformationAccess({0})>".format(self._descriptions)
-
- def __eq__(self, other):
- if not isinstance(other, AuthorityInformationAccess):
- return NotImplemented
-
- return self._descriptions == other._descriptions
-
- def __ne__(self, other):
- return not self == other
-
-
-class AccessDescription(object):
- def __init__(self, access_method, access_location):
- if not (access_method == OID_OCSP or access_method == OID_CA_ISSUERS):
- raise ValueError(
- "access_method must be OID_OCSP or OID_CA_ISSUERS"
- )
-
- if not isinstance(access_location, GeneralName):
- raise TypeError("access_location must be a GeneralName")
-
- self._access_method = access_method
- self._access_location = access_location
-
- def __repr__(self):
- return (
- "<AccessDescription(access_method={0.access_method}, access_locati"
- "on={0.access_location})>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, AccessDescription):
- return NotImplemented
-
- return (
- self.access_method == other.access_method and
- self.access_location == other.access_location
- )
-
- def __ne__(self, other):
- return not self == other
-
- access_method = utils.read_only_property("_access_method")
- access_location = utils.read_only_property("_access_location")
-
-
-class CertificatePolicies(object):
- def __init__(self, policies):
- if not all(isinstance(x, PolicyInformation) for x in policies):
- raise TypeError(
- "Every item in the policies list must be a "
- "PolicyInformation"
- )
-
- self._policies = policies
-
- def __iter__(self):
- return iter(self._policies)
-
- def __len__(self):
- return len(self._policies)
-
- def __repr__(self):
- return "<CertificatePolicies({0})>".format(self._policies)
-
- def __eq__(self, other):
- if not isinstance(other, CertificatePolicies):
- return NotImplemented
-
- return self._policies == other._policies
-
- def __ne__(self, other):
- return not self == other
-
-
-class PolicyInformation(object):
- def __init__(self, policy_identifier, policy_qualifiers):
- if not isinstance(policy_identifier, ObjectIdentifier):
- raise TypeError("policy_identifier must be an ObjectIdentifier")
-
- self._policy_identifier = policy_identifier
- if policy_qualifiers and not all(
- isinstance(
- x, (six.text_type, UserNotice)
- ) for x in policy_qualifiers
- ):
- raise TypeError(
- "policy_qualifiers must be a list of strings and/or UserNotice"
- " objects or None"
- )
-
- self._policy_qualifiers = policy_qualifiers
-
- def __repr__(self):
- return (
- "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
- "y_qualifiers={0.policy_qualifiers})>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, PolicyInformation):
- return NotImplemented
-
- return (
- self.policy_identifier == other.policy_identifier and
- self.policy_qualifiers == other.policy_qualifiers
- )
-
- def __ne__(self, other):
- return not self == other
-
- policy_identifier = utils.read_only_property("_policy_identifier")
- policy_qualifiers = utils.read_only_property("_policy_qualifiers")
-
-
-class UserNotice(object):
- def __init__(self, notice_reference, explicit_text):
- if notice_reference and not isinstance(
- notice_reference, NoticeReference
- ):
- raise TypeError(
- "notice_reference must be None or a NoticeReference"
- )
-
- self._notice_reference = notice_reference
- self._explicit_text = explicit_text
-
- def __repr__(self):
- return (
- "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
- "{0.explicit_text!r})>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, UserNotice):
- return NotImplemented
-
- return (
- self.notice_reference == other.notice_reference and
- self.explicit_text == other.explicit_text
- )
-
- def __ne__(self, other):
- return not self == other
-
- notice_reference = utils.read_only_property("_notice_reference")
- explicit_text = utils.read_only_property("_explicit_text")
-
-
-class NoticeReference(object):
- def __init__(self, organization, notice_numbers):
- self._organization = organization
- if not isinstance(notice_numbers, list) or not all(
- isinstance(x, int) for x in notice_numbers
- ):
- raise TypeError(
- "notice_numbers must be a list of integers"
- )
-
- self._notice_numbers = notice_numbers
-
- def __repr__(self):
- return (
- "<NoticeReference(organization={0.organization!r}, notice_numbers="
- "{0.notice_numbers})>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, NoticeReference):
- return NotImplemented
-
- return (
- self.organization == other.organization and
- self.notice_numbers == other.notice_numbers
- )
-
- def __ne__(self, other):
- return not self == other
-
- organization = utils.read_only_property("_organization")
- notice_numbers = utils.read_only_property("_notice_numbers")
-
-
-class SubjectKeyIdentifier(object):
- def __init__(self, digest):
- self._digest = digest
-
- digest = utils.read_only_property("_digest")
-
- def __repr__(self):
- return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
-
- def __eq__(self, other):
- if not isinstance(other, SubjectKeyIdentifier):
- return NotImplemented
-
- return (
- self.digest == other.digest
- )
-
- def __ne__(self, other):
- return not self == other
-
-
-class NameConstraints(object):
- def __init__(self, permitted_subtrees, excluded_subtrees):
- if permitted_subtrees is not None:
- if not all(
- isinstance(x, GeneralName) for x in permitted_subtrees
- ):
- raise TypeError(
- "permitted_subtrees must be a list of GeneralName objects "
- "or None"
- )
-
- self._validate_ip_name(permitted_subtrees)
-
- if excluded_subtrees is not None:
- if not all(
- isinstance(x, GeneralName) for x in excluded_subtrees
- ):
- raise TypeError(
- "excluded_subtrees must be a list of GeneralName objects "
- "or None"
- )
-
- self._validate_ip_name(excluded_subtrees)
-
- if permitted_subtrees is None and excluded_subtrees is None:
- raise ValueError(
- "At least one of permitted_subtrees and excluded_subtrees "
- "must not be None"
- )
-
- self._permitted_subtrees = permitted_subtrees
- self._excluded_subtrees = excluded_subtrees
-
- def __eq__(self, other):
- if not isinstance(other, NameConstraints):
- return NotImplemented
-
- return (
- self.excluded_subtrees == other.excluded_subtrees and
- self.permitted_subtrees == other.permitted_subtrees
- )
-
- def __ne__(self, other):
- return not self == other
-
- def _validate_ip_name(self, tree):
- if any(isinstance(name, IPAddress) and not isinstance(
- name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
- ) for name in tree):
- raise TypeError(
- "IPAddress name constraints must be an IPv4Network or"
- " IPv6Network object"
- )
-
- def __repr__(self):
- return (
- u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
- u"excluded_subtrees={0.excluded_subtrees})>".format(self)
- )
-
- permitted_subtrees = utils.read_only_property("_permitted_subtrees")
- excluded_subtrees = utils.read_only_property("_excluded_subtrees")
-
-
-class CRLDistributionPoints(object):
- def __init__(self, distribution_points):
- if not all(
- isinstance(x, DistributionPoint) for x in distribution_points
- ):
- raise TypeError(
- "distribution_points must be a list of DistributionPoint "
- "objects"
- )
-
- self._distribution_points = distribution_points
-
- def __iter__(self):
- return iter(self._distribution_points)
-
- def __len__(self):
- return len(self._distribution_points)
-
- def __repr__(self):
- return "<CRLDistributionPoints({0})>".format(self._distribution_points)
-
- def __eq__(self, other):
- if not isinstance(other, CRLDistributionPoints):
- return NotImplemented
-
- return self._distribution_points == other._distribution_points
-
- def __ne__(self, other):
- return not self == other
-
-
-class DistributionPoint(object):
- def __init__(self, full_name, relative_name, reasons, crl_issuer):
- if full_name and relative_name:
- raise ValueError(
- "At least one of full_name and relative_name must be None"
- )
-
- if full_name and not all(
- isinstance(x, GeneralName) for x in full_name
- ):
- raise TypeError(
- "full_name must be a list of GeneralName objects"
- )
-
- if relative_name and not isinstance(relative_name, Name):
- raise TypeError("relative_name must be a Name")
-
- if crl_issuer and not all(
- isinstance(x, GeneralName) for x in crl_issuer
- ):
- raise TypeError(
- "crl_issuer must be None or a list of general names"
- )
-
- if reasons and (not isinstance(reasons, frozenset) or not all(
- isinstance(x, ReasonFlags) for x in reasons
- )):
- raise TypeError("reasons must be None or frozenset of ReasonFlags")
-
- if reasons and (
- ReasonFlags.unspecified in reasons or
- ReasonFlags.remove_from_crl in reasons
- ):
- raise ValueError(
- "unspecified and remove_from_crl are not valid reasons in a "
- "DistributionPoint"
- )
-
- if reasons and not crl_issuer and not (full_name or relative_name):
- raise ValueError(
- "You must supply crl_issuer, full_name, or relative_name when "
- "reasons is not None"
- )
-
- self._full_name = full_name
- self._relative_name = relative_name
- self._reasons = reasons
- self._crl_issuer = crl_issuer
-
- def __repr__(self):
- return (
- "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
- "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_is"
- "suer})>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, DistributionPoint):
- return NotImplemented
-
- return (
- self.full_name == other.full_name and
- self.relative_name == other.relative_name and
- self.reasons == other.reasons and
- self.crl_issuer == other.crl_issuer
- )
-
- def __ne__(self, other):
- return not self == other
-
- full_name = utils.read_only_property("_full_name")
- relative_name = utils.read_only_property("_relative_name")
- reasons = utils.read_only_property("_reasons")
- crl_issuer = utils.read_only_property("_crl_issuer")
-
-
-class ReasonFlags(Enum):
- unspecified = "unspecified"
- key_compromise = "keyCompromise"
- ca_compromise = "cACompromise"
- affiliation_changed = "affiliationChanged"
- superseded = "superseded"
- cessation_of_operation = "cessationOfOperation"
- certificate_hold = "certificateHold"
- privilege_withdrawn = "privilegeWithdrawn"
- aa_compromise = "aACompromise"
- remove_from_crl = "removeFromCRL"
-
-
-class InhibitAnyPolicy(object):
- def __init__(self, skip_certs):
- if not isinstance(skip_certs, six.integer_types):
- raise TypeError("skip_certs must be an integer")
-
- if skip_certs < 0:
- raise ValueError("skip_certs must be a non-negative integer")
-
- self._skip_certs = skip_certs
-
- def __repr__(self):
- return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
-
- def __eq__(self, other):
- if not isinstance(other, InhibitAnyPolicy):
- return NotImplemented
-
- return self.skip_certs == other.skip_certs
-
- def __ne__(self, other):
- return not self == other
-
- skip_certs = utils.read_only_property("_skip_certs")
-
-
-@six.add_metaclass(abc.ABCMeta)
-class GeneralName(object):
- @abc.abstractproperty
- def value(self):
- """
- Return the value of the object
- """
-
-
-@utils.register_interface(GeneralName)
-class RFC822Name(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<RFC822Name(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, RFC822Name):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class DNSName(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<DNSName(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, DNSName):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class UniformResourceIdentifier(object):
- def __init__(self, value):
- if not isinstance(value, six.text_type):
- raise TypeError("value must be a unicode string")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<UniformResourceIdentifier(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, UniformResourceIdentifier):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class DirectoryName(object):
- def __init__(self, value):
- if not isinstance(value, Name):
- raise TypeError("value must be a Name")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<DirectoryName(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, DirectoryName):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class RegisteredID(object):
- def __init__(self, value):
- if not isinstance(value, ObjectIdentifier):
- raise TypeError("value must be an ObjectIdentifier")
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<RegisteredID(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, RegisteredID):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-@utils.register_interface(GeneralName)
-class IPAddress(object):
- def __init__(self, value):
- if not isinstance(
- value,
- (
- ipaddress.IPv4Address,
- ipaddress.IPv6Address,
- ipaddress.IPv4Network,
- ipaddress.IPv6Network
- )
- ):
- raise TypeError(
- "value must be an instance of ipaddress.IPv4Address, "
- "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
- "ipaddress.IPv6Network"
- )
-
- self._value = value
-
- value = utils.read_only_property("_value")
-
- def __repr__(self):
- return "<IPAddress(value={0})>".format(self.value)
-
- def __eq__(self, other):
- if not isinstance(other, IPAddress):
- return NotImplemented
-
- return self.value == other.value
-
- def __ne__(self, other):
- return not self == other
-
-
-class GeneralNames(object):
- def __init__(self, general_names):
- if not all(isinstance(x, GeneralName) for x in general_names):
- raise TypeError(
- "Every item in the general_names list must be an "
- "object conforming to the GeneralName interface"
- )
-
- self._general_names = general_names
-
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._general_names)
-
- def get_values_for_type(self, type):
- return [i.value for i in self if isinstance(i, type)]
-
- def __repr__(self):
- return "<GeneralNames({0})>".format(self._general_names)
-
- def __eq__(self, other):
- if not isinstance(other, GeneralNames):
- return NotImplemented
-
- return self._general_names == other._general_names
-
- def __ne__(self, other):
- return not self == other
-
-
-class SubjectAlternativeName(object):
- def __init__(self, general_names):
- self._general_names = GeneralNames(general_names)
-
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._general_names)
-
- def get_values_for_type(self, type):
- return self._general_names.get_values_for_type(type)
-
- def __repr__(self):
- return "<SubjectAlternativeName({0})>".format(self._general_names)
-
- def __eq__(self, other):
- if not isinstance(other, SubjectAlternativeName):
- return NotImplemented
-
- return self._general_names == other._general_names
-
- def __ne__(self, other):
- return not self == other
-
-
-class IssuerAlternativeName(object):
- def __init__(self, general_names):
- self._general_names = GeneralNames(general_names)
-
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._general_names)
-
- def get_values_for_type(self, type):
- return self._general_names.get_values_for_type(type)
-
- def __repr__(self):
- return "<IssuerAlternativeName({0})>".format(self._general_names)
-
- def __eq__(self, other):
- if not isinstance(other, IssuerAlternativeName):
- return NotImplemented
-
- return self._general_names == other._general_names
-
- def __ne__(self, other):
- return not self == other
-
-
-class AuthorityKeyIdentifier(object):
- def __init__(self, key_identifier, authority_cert_issuer,
- authority_cert_serial_number):
- if authority_cert_issuer or authority_cert_serial_number:
- if not authority_cert_issuer or not authority_cert_serial_number:
- raise ValueError(
- "authority_cert_issuer and authority_cert_serial_number "
- "must both be present or both None"
- )
-
- if not all(
- isinstance(x, GeneralName) for x in authority_cert_issuer
- ):
- raise TypeError(
- "authority_cert_issuer must be a list of GeneralName "
- "objects"
- )
-
- if not isinstance(authority_cert_serial_number, six.integer_types):
- raise TypeError(
- "authority_cert_serial_number must be an integer"
- )
-
- self._key_identifier = key_identifier
- self._authority_cert_issuer = authority_cert_issuer
- self._authority_cert_serial_number = authority_cert_serial_number
-
- def __repr__(self):
- return (
- "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
- "authority_cert_issuer={0.authority_cert_issuer}, "
- "authority_cert_serial_number={0.authority_cert_serial_number}"
- ")>".format(self)
- )
-
- def __eq__(self, other):
- if not isinstance(other, AuthorityKeyIdentifier):
- return NotImplemented
-
- return (
- self.key_identifier == other.key_identifier and
- self.authority_cert_issuer == other.authority_cert_issuer and
- self.authority_cert_serial_number ==
- other.authority_cert_serial_number
- )
-
- def __ne__(self, other):
- return not self == other
-
- key_identifier = utils.read_only_property("_key_identifier")
- authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
- authority_cert_serial_number = utils.read_only_property(
- "_authority_cert_serial_number"
- )
-
-
-OID_COMMON_NAME = ObjectIdentifier("2.5.4.3")
-OID_COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
-OID_LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
-OID_STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
-OID_ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
-OID_ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
-OID_SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
-OID_SURNAME = ObjectIdentifier("2.5.4.4")
-OID_GIVEN_NAME = ObjectIdentifier("2.5.4.42")
-OID_TITLE = ObjectIdentifier("2.5.4.12")
-OID_GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
-OID_DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
-OID_PSEUDONYM = ObjectIdentifier("2.5.4.65")
-OID_DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
-OID_EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
-
-OID_RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4")
-OID_RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5")
-OID_RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14")
-OID_RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11")
-OID_RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12")
-OID_RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13")
-OID_ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1")
-OID_ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1")
-OID_ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2")
-OID_ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3")
-OID_ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4")
-OID_DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3")
-OID_DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1")
-OID_DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2")
-
-_SIG_OIDS_TO_HASH = {
- OID_RSA_WITH_MD5.dotted_string: hashes.MD5(),
- OID_RSA_WITH_SHA1.dotted_string: hashes.SHA1(),
- OID_RSA_WITH_SHA224.dotted_string: hashes.SHA224(),
- OID_RSA_WITH_SHA256.dotted_string: hashes.SHA256(),
- OID_RSA_WITH_SHA384.dotted_string: hashes.SHA384(),
- OID_RSA_WITH_SHA512.dotted_string: hashes.SHA512(),
- OID_ECDSA_WITH_SHA1.dotted_string: hashes.SHA1(),
- OID_ECDSA_WITH_SHA224.dotted_string: hashes.SHA224(),
- OID_ECDSA_WITH_SHA256.dotted_string: hashes.SHA256(),
- OID_ECDSA_WITH_SHA384.dotted_string: hashes.SHA384(),
- OID_ECDSA_WITH_SHA512.dotted_string: hashes.SHA512(),
- OID_DSA_WITH_SHA1.dotted_string: hashes.SHA1(),
- OID_DSA_WITH_SHA224.dotted_string: hashes.SHA224(),
- OID_DSA_WITH_SHA256.dotted_string: hashes.SHA256()
-}
-
-OID_SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1")
-OID_CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2")
-OID_CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3")
-OID_EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4")
-OID_TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8")
-OID_OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9")
-
-OID_CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2")
-OID_OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1")
-
-OID_CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1")
-OID_CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2")
-OID_ANY_POLICY = ObjectIdentifier("2.5.29.32.0")
-
-
-@six.add_metaclass(abc.ABCMeta)
-class Certificate(object):
- @abc.abstractmethod
- def fingerprint(self, algorithm):
- """
- Returns bytes using digest passed.
- """
-
- @abc.abstractproperty
- def serial(self):
- """
- Returns certificate serial number
- """
-
- @abc.abstractproperty
- def version(self):
- """
- Returns the certificate version
- """
-
- @abc.abstractmethod
- def public_key(self):
- """
- Returns the public key
- """
-
- @abc.abstractproperty
- def not_valid_before(self):
- """
- Not before time (represented as UTC datetime)
- """
-
- @abc.abstractproperty
- def not_valid_after(self):
- """
- Not after time (represented as UTC datetime)
- """
-
- @abc.abstractproperty
- def issuer(self):
- """
- Returns the issuer name object.
- """
-
- @abc.abstractproperty
- def subject(self):
- """
- Returns the subject name object.
- """
-
- @abc.abstractproperty
- def signature_hash_algorithm(self):
- """
- Returns a HashAlgorithm corresponding to the type of the digest signed
- in the certificate.
- """
-
- @abc.abstractproperty
- def extensions(self):
- """
- Returns an Extensions object.
- """
-
- @abc.abstractmethod
- def __eq__(self, other):
- """
- Checks equality.
- """
-
- @abc.abstractmethod
- def __ne__(self, other):
- """
- Checks not equal.
- """
-
- @abc.abstractmethod
- def public_bytes(self, encoding):
- """
- Serializes the certificate to PEM or DER format.
- """
-
-
-@six.add_metaclass(abc.ABCMeta)
-class CertificateRevocationList(object):
-
- @abc.abstractmethod
- def fingerprint(self, algorithm):
- """
- Returns bytes using digest passed.
- """
-
- @abc.abstractproperty
- def signature_hash_algorithm(self):
- """
- Returns a HashAlgorithm corresponding to the type of the digest signed
- in the certificate.
- """
-
- @abc.abstractproperty
- def issuer(self):
- """
- Returns the X509Name with the issuer of this CRL.
- """
-
- @abc.abstractproperty
- def next_update(self):
- """
- Returns the date of next update for this CRL.
- """
-
- @abc.abstractproperty
- def last_update(self):
- """
- Returns the date of last update for this CRL.
- """
-
- @abc.abstractproperty
- def revoked_certificates(self):
- """
- Returns a list of RevokedCertificate objects for this CRL.
- """
-
- @abc.abstractproperty
- def extensions(self):
- """
- Returns an Extensions object containing a list of CRL extensions.
- """
-
- @abc.abstractmethod
- def __eq__(self, other):
- """
- Checks equality.
- """
-
- @abc.abstractmethod
- def __ne__(self, other):
- """
- Checks not equal.
- """
-
-
-@six.add_metaclass(abc.ABCMeta)
-class CertificateSigningRequest(object):
- @abc.abstractmethod
- def public_key(self):
- """
- Returns the public key
- """
-
- @abc.abstractproperty
- def subject(self):
- """
- Returns the subject name object.
- """
-
- @abc.abstractproperty
- def signature_hash_algorithm(self):
- """
- Returns a HashAlgorithm corresponding to the type of the digest signed
- in the certificate.
- """
-
- @abc.abstractproperty
- def extensions(self):
- """
- Returns the extensions in the signing request.
- """
-
- @abc.abstractmethod
- def public_bytes(self, encoding):
- """
- Encodes the request to PEM or DER format.
- """
-
-
-@six.add_metaclass(abc.ABCMeta)
-class RevokedCertificate(object):
- @abc.abstractproperty
- def serial_number(self):
- """
- Returns the serial number of the revoked certificate.
- """
-
- @abc.abstractproperty
- def revocation_date(self):
- """
- Returns the date of when this certificate was revoked.
- """
-
- @abc.abstractproperty
- def extensions(self):
- """
- Returns an Extensions object containing a list of Revoked extensions.
- """
-
-
-class CertificateSigningRequestBuilder(object):
- def __init__(self, subject_name=None, extensions=[]):
- """
- Creates an empty X.509 certificate request (v1).
- """
- self._subject_name = subject_name
- self._extensions = extensions
-
- def subject_name(self, name):
- """
- Sets the certificate requestor's distinguished name.
- """
- if not isinstance(name, Name):
- raise TypeError('Expecting x509.Name object.')
- if self._subject_name is not None:
- raise ValueError('The subject name may only be set once.')
- return CertificateSigningRequestBuilder(name, self._extensions)
-
- def add_extension(self, extension, critical):
- """
- Adds an X.509 extension to the certificate request.
- """
- if isinstance(extension, BasicConstraints):
- extension = Extension(OID_BASIC_CONSTRAINTS, critical, extension)
- elif isinstance(extension, SubjectAlternativeName):
- extension = Extension(
- OID_SUBJECT_ALTERNATIVE_NAME, critical, extension
- )
- else:
- raise NotImplementedError('Unsupported X.509 extension.')
- # TODO: This is quadratic in the number of extensions
- for e in self._extensions:
- if e.oid == extension.oid:
- raise ValueError('This extension has already been set.')
- return CertificateSigningRequestBuilder(
- self._subject_name, self._extensions + [extension]
- )
-
- def sign(self, private_key, algorithm, backend):
- """
- Signs the request using the requestor's private key.
- """
- return backend.create_x509_csr(self, private_key, algorithm)
diff --git a/src/cryptography/x509/__init__.py b/src/cryptography/x509/__init__.py
new file mode 100644
index 00000000..b761e264
--- /dev/null
+++ b/src/cryptography/x509/__init__.py
@@ -0,0 +1,189 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography.x509 import certificate_transparency
+from cryptography.x509.base import (
+ Certificate, CertificateBuilder, CertificateRevocationList,
+ CertificateRevocationListBuilder,
+ CertificateSigningRequest, CertificateSigningRequestBuilder,
+ InvalidVersion, RevokedCertificate, RevokedCertificateBuilder,
+ Version, load_der_x509_certificate, load_der_x509_crl, load_der_x509_csr,
+ load_pem_x509_certificate, load_pem_x509_crl, load_pem_x509_csr,
+ random_serial_number,
+)
+from cryptography.x509.extensions import (
+ AccessDescription, AuthorityInformationAccess,
+ AuthorityKeyIdentifier, BasicConstraints, CRLDistributionPoints,
+ CRLNumber, CRLReason, CertificateIssuer, CertificatePolicies,
+ DeltaCRLIndicator, DistributionPoint, DuplicateExtension, ExtendedKeyUsage,
+ Extension, ExtensionNotFound, ExtensionType, Extensions, FreshestCRL,
+ GeneralNames, InhibitAnyPolicy, InvalidityDate, IssuerAlternativeName,
+ IssuingDistributionPoint, KeyUsage, NameConstraints, NoticeReference,
+ OCSPNoCheck, OCSPNonce, PolicyConstraints, PolicyInformation,
+ PrecertPoison, PrecertificateSignedCertificateTimestamps, ReasonFlags,
+ SubjectAlternativeName, SubjectKeyIdentifier, TLSFeature, TLSFeatureType,
+ UnrecognizedExtension, UserNotice
+)
+from cryptography.x509.general_name import (
+ DNSName, DirectoryName, GeneralName, IPAddress, OtherName, RFC822Name,
+ RegisteredID, UniformResourceIdentifier, UnsupportedGeneralNameType,
+ _GENERAL_NAMES
+)
+from cryptography.x509.name import (
+ Name, NameAttribute, RelativeDistinguishedName
+)
+from cryptography.x509.oid import (
+ AuthorityInformationAccessOID, CRLEntryExtensionOID,
+ CertificatePoliciesOID, ExtendedKeyUsageOID, ExtensionOID, NameOID,
+ ObjectIdentifier, SignatureAlgorithmOID, _SIG_OIDS_TO_HASH
+)
+
+
+OID_AUTHORITY_INFORMATION_ACCESS = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
+OID_AUTHORITY_KEY_IDENTIFIER = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
+OID_BASIC_CONSTRAINTS = ExtensionOID.BASIC_CONSTRAINTS
+OID_CERTIFICATE_POLICIES = ExtensionOID.CERTIFICATE_POLICIES
+OID_CRL_DISTRIBUTION_POINTS = ExtensionOID.CRL_DISTRIBUTION_POINTS
+OID_EXTENDED_KEY_USAGE = ExtensionOID.EXTENDED_KEY_USAGE
+OID_FRESHEST_CRL = ExtensionOID.FRESHEST_CRL
+OID_INHIBIT_ANY_POLICY = ExtensionOID.INHIBIT_ANY_POLICY
+OID_ISSUER_ALTERNATIVE_NAME = ExtensionOID.ISSUER_ALTERNATIVE_NAME
+OID_KEY_USAGE = ExtensionOID.KEY_USAGE
+OID_NAME_CONSTRAINTS = ExtensionOID.NAME_CONSTRAINTS
+OID_OCSP_NO_CHECK = ExtensionOID.OCSP_NO_CHECK
+OID_POLICY_CONSTRAINTS = ExtensionOID.POLICY_CONSTRAINTS
+OID_POLICY_MAPPINGS = ExtensionOID.POLICY_MAPPINGS
+OID_SUBJECT_ALTERNATIVE_NAME = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
+OID_SUBJECT_DIRECTORY_ATTRIBUTES = ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES
+OID_SUBJECT_INFORMATION_ACCESS = ExtensionOID.SUBJECT_INFORMATION_ACCESS
+OID_SUBJECT_KEY_IDENTIFIER = ExtensionOID.SUBJECT_KEY_IDENTIFIER
+
+OID_DSA_WITH_SHA1 = SignatureAlgorithmOID.DSA_WITH_SHA1
+OID_DSA_WITH_SHA224 = SignatureAlgorithmOID.DSA_WITH_SHA224
+OID_DSA_WITH_SHA256 = SignatureAlgorithmOID.DSA_WITH_SHA256
+OID_ECDSA_WITH_SHA1 = SignatureAlgorithmOID.ECDSA_WITH_SHA1
+OID_ECDSA_WITH_SHA224 = SignatureAlgorithmOID.ECDSA_WITH_SHA224
+OID_ECDSA_WITH_SHA256 = SignatureAlgorithmOID.ECDSA_WITH_SHA256
+OID_ECDSA_WITH_SHA384 = SignatureAlgorithmOID.ECDSA_WITH_SHA384
+OID_ECDSA_WITH_SHA512 = SignatureAlgorithmOID.ECDSA_WITH_SHA512
+OID_RSA_WITH_MD5 = SignatureAlgorithmOID.RSA_WITH_MD5
+OID_RSA_WITH_SHA1 = SignatureAlgorithmOID.RSA_WITH_SHA1
+OID_RSA_WITH_SHA224 = SignatureAlgorithmOID.RSA_WITH_SHA224
+OID_RSA_WITH_SHA256 = SignatureAlgorithmOID.RSA_WITH_SHA256
+OID_RSA_WITH_SHA384 = SignatureAlgorithmOID.RSA_WITH_SHA384
+OID_RSA_WITH_SHA512 = SignatureAlgorithmOID.RSA_WITH_SHA512
+OID_RSASSA_PSS = SignatureAlgorithmOID.RSASSA_PSS
+
+OID_COMMON_NAME = NameOID.COMMON_NAME
+OID_COUNTRY_NAME = NameOID.COUNTRY_NAME
+OID_DOMAIN_COMPONENT = NameOID.DOMAIN_COMPONENT
+OID_DN_QUALIFIER = NameOID.DN_QUALIFIER
+OID_EMAIL_ADDRESS = NameOID.EMAIL_ADDRESS
+OID_GENERATION_QUALIFIER = NameOID.GENERATION_QUALIFIER
+OID_GIVEN_NAME = NameOID.GIVEN_NAME
+OID_LOCALITY_NAME = NameOID.LOCALITY_NAME
+OID_ORGANIZATIONAL_UNIT_NAME = NameOID.ORGANIZATIONAL_UNIT_NAME
+OID_ORGANIZATION_NAME = NameOID.ORGANIZATION_NAME
+OID_PSEUDONYM = NameOID.PSEUDONYM
+OID_SERIAL_NUMBER = NameOID.SERIAL_NUMBER
+OID_STATE_OR_PROVINCE_NAME = NameOID.STATE_OR_PROVINCE_NAME
+OID_SURNAME = NameOID.SURNAME
+OID_TITLE = NameOID.TITLE
+
+OID_CLIENT_AUTH = ExtendedKeyUsageOID.CLIENT_AUTH
+OID_CODE_SIGNING = ExtendedKeyUsageOID.CODE_SIGNING
+OID_EMAIL_PROTECTION = ExtendedKeyUsageOID.EMAIL_PROTECTION
+OID_OCSP_SIGNING = ExtendedKeyUsageOID.OCSP_SIGNING
+OID_SERVER_AUTH = ExtendedKeyUsageOID.SERVER_AUTH
+OID_TIME_STAMPING = ExtendedKeyUsageOID.TIME_STAMPING
+
+OID_ANY_POLICY = CertificatePoliciesOID.ANY_POLICY
+OID_CPS_QUALIFIER = CertificatePoliciesOID.CPS_QUALIFIER
+OID_CPS_USER_NOTICE = CertificatePoliciesOID.CPS_USER_NOTICE
+
+OID_CERTIFICATE_ISSUER = CRLEntryExtensionOID.CERTIFICATE_ISSUER
+OID_CRL_REASON = CRLEntryExtensionOID.CRL_REASON
+OID_INVALIDITY_DATE = CRLEntryExtensionOID.INVALIDITY_DATE
+
+OID_CA_ISSUERS = AuthorityInformationAccessOID.CA_ISSUERS
+OID_OCSP = AuthorityInformationAccessOID.OCSP
+
+__all__ = [
+ "certificate_transparency",
+ "load_pem_x509_certificate",
+ "load_der_x509_certificate",
+ "load_pem_x509_csr",
+ "load_der_x509_csr",
+ "load_pem_x509_crl",
+ "load_der_x509_crl",
+ "random_serial_number",
+ "InvalidVersion",
+ "DeltaCRLIndicator",
+ "DuplicateExtension",
+ "ExtensionNotFound",
+ "UnsupportedGeneralNameType",
+ "NameAttribute",
+ "Name",
+ "RelativeDistinguishedName",
+ "ObjectIdentifier",
+ "ExtensionType",
+ "Extensions",
+ "Extension",
+ "ExtendedKeyUsage",
+ "FreshestCRL",
+ "IssuingDistributionPoint",
+ "TLSFeature",
+ "TLSFeatureType",
+ "OCSPNoCheck",
+ "BasicConstraints",
+ "CRLNumber",
+ "KeyUsage",
+ "AuthorityInformationAccess",
+ "AccessDescription",
+ "CertificatePolicies",
+ "PolicyInformation",
+ "UserNotice",
+ "NoticeReference",
+ "SubjectKeyIdentifier",
+ "NameConstraints",
+ "CRLDistributionPoints",
+ "DistributionPoint",
+ "ReasonFlags",
+ "InhibitAnyPolicy",
+ "SubjectAlternativeName",
+ "IssuerAlternativeName",
+ "AuthorityKeyIdentifier",
+ "GeneralNames",
+ "GeneralName",
+ "RFC822Name",
+ "DNSName",
+ "UniformResourceIdentifier",
+ "RegisteredID",
+ "DirectoryName",
+ "IPAddress",
+ "OtherName",
+ "Certificate",
+ "CertificateRevocationList",
+ "CertificateRevocationListBuilder",
+ "CertificateSigningRequest",
+ "RevokedCertificate",
+ "RevokedCertificateBuilder",
+ "CertificateSigningRequestBuilder",
+ "CertificateBuilder",
+ "Version",
+ "_SIG_OIDS_TO_HASH",
+ "OID_CA_ISSUERS",
+ "OID_OCSP",
+ "_GENERAL_NAMES",
+ "CertificateIssuer",
+ "CRLReason",
+ "InvalidityDate",
+ "UnrecognizedExtension",
+ "PolicyConstraints",
+ "PrecertificateSignedCertificateTimestamps",
+ "PrecertPoison",
+ "OCSPNonce",
+]
diff --git a/src/cryptography/x509/base.py b/src/cryptography/x509/base.py
new file mode 100644
index 00000000..3983c9b3
--- /dev/null
+++ b/src/cryptography/x509/base.py
@@ -0,0 +1,758 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+import datetime
+import os
+from enum import Enum
+
+import six
+
+from cryptography import utils
+from cryptography.hazmat.primitives.asymmetric import (
+ dsa, ec, ed25519, ed448, rsa
+)
+from cryptography.x509.extensions import Extension, ExtensionType
+from cryptography.x509.name import Name
+
+
+_EARLIEST_UTC_TIME = datetime.datetime(1950, 1, 1)
+
+
+def _reject_duplicate_extension(extension, extensions):
+ # This is quadratic in the number of extensions
+ for e in extensions:
+ if e.oid == extension.oid:
+ raise ValueError('This extension has already been set.')
+
+
+def _convert_to_naive_utc_time(time):
+ """Normalizes a datetime to a naive datetime in UTC.
+
+ time -- datetime to normalize. Assumed to be in UTC if not timezone
+ aware.
+ """
+ if time.tzinfo is not None:
+ offset = time.utcoffset()
+ offset = offset if offset else datetime.timedelta()
+ return time.replace(tzinfo=None) - offset
+ else:
+ return time
+
+
+class Version(Enum):
+ v1 = 0
+ v3 = 2
+
+
+def load_pem_x509_certificate(data, backend):
+ return backend.load_pem_x509_certificate(data)
+
+
+def load_der_x509_certificate(data, backend):
+ return backend.load_der_x509_certificate(data)
+
+
+def load_pem_x509_csr(data, backend):
+ return backend.load_pem_x509_csr(data)
+
+
+def load_der_x509_csr(data, backend):
+ return backend.load_der_x509_csr(data)
+
+
+def load_pem_x509_crl(data, backend):
+ return backend.load_pem_x509_crl(data)
+
+
+def load_der_x509_crl(data, backend):
+ return backend.load_der_x509_crl(data)
+
+
+class InvalidVersion(Exception):
+ def __init__(self, msg, parsed_version):
+ super(InvalidVersion, self).__init__(msg)
+ self.parsed_version = parsed_version
+
+
+@six.add_metaclass(abc.ABCMeta)
+class Certificate(object):
+ @abc.abstractmethod
+ def fingerprint(self, algorithm):
+ """
+ Returns bytes using digest passed.
+ """
+
+ @abc.abstractproperty
+ def serial_number(self):
+ """
+ Returns certificate serial number
+ """
+
+ @abc.abstractproperty
+ def version(self):
+ """
+ Returns the certificate version
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ Returns the public key
+ """
+
+ @abc.abstractproperty
+ def not_valid_before(self):
+ """
+ Not before time (represented as UTC datetime)
+ """
+
+ @abc.abstractproperty
+ def not_valid_after(self):
+ """
+ Not after time (represented as UTC datetime)
+ """
+
+ @abc.abstractproperty
+ def issuer(self):
+ """
+ Returns the issuer name object.
+ """
+
+ @abc.abstractproperty
+ def subject(self):
+ """
+ Returns the subject name object.
+ """
+
+ @abc.abstractproperty
+ def signature_hash_algorithm(self):
+ """
+ Returns a HashAlgorithm corresponding to the type of the digest signed
+ in the certificate.
+ """
+
+ @abc.abstractproperty
+ def signature_algorithm_oid(self):
+ """
+ Returns the ObjectIdentifier of the signature algorithm.
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ Returns an Extensions object.
+ """
+
+ @abc.abstractproperty
+ def signature(self):
+ """
+ Returns the signature bytes.
+ """
+
+ @abc.abstractproperty
+ def tbs_certificate_bytes(self):
+ """
+ Returns the tbsCertificate payload bytes as defined in RFC 5280.
+ """
+
+ @abc.abstractmethod
+ def __eq__(self, other):
+ """
+ Checks equality.
+ """
+
+ @abc.abstractmethod
+ def __ne__(self, other):
+ """
+ Checks not equal.
+ """
+
+ @abc.abstractmethod
+ def __hash__(self):
+ """
+ Computes a hash.
+ """
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding):
+ """
+ Serializes the certificate to PEM or DER format.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CertificateRevocationList(object):
+ @abc.abstractmethod
+ def public_bytes(self, encoding):
+ """
+ Serializes the CRL to PEM or DER format.
+ """
+
+ @abc.abstractmethod
+ def fingerprint(self, algorithm):
+ """
+ Returns bytes using digest passed.
+ """
+
+ @abc.abstractmethod
+ def get_revoked_certificate_by_serial_number(self, serial_number):
+ """
+ Returns an instance of RevokedCertificate or None if the serial_number
+ is not in the CRL.
+ """
+
+ @abc.abstractproperty
+ def signature_hash_algorithm(self):
+ """
+ Returns a HashAlgorithm corresponding to the type of the digest signed
+ in the certificate.
+ """
+
+ @abc.abstractproperty
+ def signature_algorithm_oid(self):
+ """
+ Returns the ObjectIdentifier of the signature algorithm.
+ """
+
+ @abc.abstractproperty
+ def issuer(self):
+ """
+ Returns the X509Name with the issuer of this CRL.
+ """
+
+ @abc.abstractproperty
+ def next_update(self):
+ """
+ Returns the date of next update for this CRL.
+ """
+
+ @abc.abstractproperty
+ def last_update(self):
+ """
+ Returns the date of last update for this CRL.
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ Returns an Extensions object containing a list of CRL extensions.
+ """
+
+ @abc.abstractproperty
+ def signature(self):
+ """
+ Returns the signature bytes.
+ """
+
+ @abc.abstractproperty
+ def tbs_certlist_bytes(self):
+ """
+ Returns the tbsCertList payload bytes as defined in RFC 5280.
+ """
+
+ @abc.abstractmethod
+ def __eq__(self, other):
+ """
+ Checks equality.
+ """
+
+ @abc.abstractmethod
+ def __ne__(self, other):
+ """
+ Checks not equal.
+ """
+
+ @abc.abstractmethod
+ def __len__(self):
+ """
+ Number of revoked certificates in the CRL.
+ """
+
+ @abc.abstractmethod
+ def __getitem__(self, idx):
+ """
+ Returns a revoked certificate (or slice of revoked certificates).
+ """
+
+ @abc.abstractmethod
+ def __iter__(self):
+ """
+ Iterator over the revoked certificates
+ """
+
+ @abc.abstractmethod
+ def is_signature_valid(self, public_key):
+ """
+ Verifies signature of revocation list against given public key.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CertificateSigningRequest(object):
+ @abc.abstractmethod
+ def __eq__(self, other):
+ """
+ Checks equality.
+ """
+
+ @abc.abstractmethod
+ def __ne__(self, other):
+ """
+ Checks not equal.
+ """
+
+ @abc.abstractmethod
+ def __hash__(self):
+ """
+ Computes a hash.
+ """
+
+ @abc.abstractmethod
+ def public_key(self):
+ """
+ Returns the public key
+ """
+
+ @abc.abstractproperty
+ def subject(self):
+ """
+ Returns the subject name object.
+ """
+
+ @abc.abstractproperty
+ def signature_hash_algorithm(self):
+ """
+ Returns a HashAlgorithm corresponding to the type of the digest signed
+ in the certificate.
+ """
+
+ @abc.abstractproperty
+ def signature_algorithm_oid(self):
+ """
+ Returns the ObjectIdentifier of the signature algorithm.
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ Returns the extensions in the signing request.
+ """
+
+ @abc.abstractmethod
+ def public_bytes(self, encoding):
+ """
+ Encodes the request to PEM or DER format.
+ """
+
+ @abc.abstractproperty
+ def signature(self):
+ """
+ Returns the signature bytes.
+ """
+
+ @abc.abstractproperty
+ def tbs_certrequest_bytes(self):
+ """
+ Returns the PKCS#10 CertificationRequestInfo bytes as defined in RFC
+ 2986.
+ """
+
+ @abc.abstractproperty
+ def is_signature_valid(self):
+ """
+ Verifies signature of signing request.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RevokedCertificate(object):
+ @abc.abstractproperty
+ def serial_number(self):
+ """
+ Returns the serial number of the revoked certificate.
+ """
+
+ @abc.abstractproperty
+ def revocation_date(self):
+ """
+ Returns the date of when this certificate was revoked.
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ Returns an Extensions object containing a list of Revoked extensions.
+ """
+
+
+class CertificateSigningRequestBuilder(object):
+ def __init__(self, subject_name=None, extensions=[]):
+ """
+ Creates an empty X.509 certificate request (v1).
+ """
+ self._subject_name = subject_name
+ self._extensions = extensions
+
+ def subject_name(self, name):
+ """
+ Sets the certificate requestor's distinguished name.
+ """
+ if not isinstance(name, Name):
+ raise TypeError('Expecting x509.Name object.')
+ if self._subject_name is not None:
+ raise ValueError('The subject name may only be set once.')
+ return CertificateSigningRequestBuilder(name, self._extensions)
+
+ def add_extension(self, extension, critical):
+ """
+ Adds an X.509 extension to the certificate request.
+ """
+ if not isinstance(extension, ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+
+ return CertificateSigningRequestBuilder(
+ self._subject_name, self._extensions + [extension]
+ )
+
+ def sign(self, private_key, algorithm, backend):
+ """
+ Signs the request using the requestor's private key.
+ """
+ if self._subject_name is None:
+ raise ValueError("A CertificateSigningRequest must have a subject")
+ return backend.create_x509_csr(self, private_key, algorithm)
+
+
+class CertificateBuilder(object):
+ def __init__(self, issuer_name=None, subject_name=None,
+ public_key=None, serial_number=None, not_valid_before=None,
+ not_valid_after=None, extensions=[]):
+ self._version = Version.v3
+ self._issuer_name = issuer_name
+ self._subject_name = subject_name
+ self._public_key = public_key
+ self._serial_number = serial_number
+ self._not_valid_before = not_valid_before
+ self._not_valid_after = not_valid_after
+ self._extensions = extensions
+
+ def issuer_name(self, name):
+ """
+ Sets the CA's distinguished name.
+ """
+ if not isinstance(name, Name):
+ raise TypeError('Expecting x509.Name object.')
+ if self._issuer_name is not None:
+ raise ValueError('The issuer name may only be set once.')
+ return CertificateBuilder(
+ name, self._subject_name, self._public_key,
+ self._serial_number, self._not_valid_before,
+ self._not_valid_after, self._extensions
+ )
+
+ def subject_name(self, name):
+ """
+ Sets the requestor's distinguished name.
+ """
+ if not isinstance(name, Name):
+ raise TypeError('Expecting x509.Name object.')
+ if self._subject_name is not None:
+ raise ValueError('The subject name may only be set once.')
+ return CertificateBuilder(
+ self._issuer_name, name, self._public_key,
+ self._serial_number, self._not_valid_before,
+ self._not_valid_after, self._extensions
+ )
+
+ def public_key(self, key):
+ """
+ Sets the requestor's public key (as found in the signing request).
+ """
+ if not isinstance(key, (dsa.DSAPublicKey, rsa.RSAPublicKey,
+ ec.EllipticCurvePublicKey,
+ ed25519.Ed25519PublicKey,
+ ed448.Ed448PublicKey)):
+ raise TypeError('Expecting one of DSAPublicKey, RSAPublicKey,'
+ ' EllipticCurvePublicKey, Ed25519PublicKey or'
+ ' Ed448PublicKey.')
+ if self._public_key is not None:
+ raise ValueError('The public key may only be set once.')
+ return CertificateBuilder(
+ self._issuer_name, self._subject_name, key,
+ self._serial_number, self._not_valid_before,
+ self._not_valid_after, self._extensions
+ )
+
+ def serial_number(self, number):
+ """
+ Sets the certificate serial number.
+ """
+ if not isinstance(number, six.integer_types):
+ raise TypeError('Serial number must be of integral type.')
+ if self._serial_number is not None:
+ raise ValueError('The serial number may only be set once.')
+ if number <= 0:
+ raise ValueError('The serial number should be positive.')
+
+ # ASN.1 integers are always signed, so most significant bit must be
+ # zero.
+ if number.bit_length() >= 160: # As defined in RFC 5280
+ raise ValueError('The serial number should not be more than 159 '
+ 'bits.')
+ return CertificateBuilder(
+ self._issuer_name, self._subject_name,
+ self._public_key, number, self._not_valid_before,
+ self._not_valid_after, self._extensions
+ )
+
+ def not_valid_before(self, time):
+ """
+ Sets the certificate activation time.
+ """
+ if not isinstance(time, datetime.datetime):
+ raise TypeError('Expecting datetime object.')
+ if self._not_valid_before is not None:
+ raise ValueError('The not valid before may only be set once.')
+ time = _convert_to_naive_utc_time(time)
+ if time < _EARLIEST_UTC_TIME:
+ raise ValueError('The not valid before date must be on or after'
+ ' 1950 January 1).')
+ if self._not_valid_after is not None and time > self._not_valid_after:
+ raise ValueError(
+ 'The not valid before date must be before the not valid after '
+ 'date.'
+ )
+ return CertificateBuilder(
+ self._issuer_name, self._subject_name,
+ self._public_key, self._serial_number, time,
+ self._not_valid_after, self._extensions
+ )
+
+ def not_valid_after(self, time):
+ """
+ Sets the certificate expiration time.
+ """
+ if not isinstance(time, datetime.datetime):
+ raise TypeError('Expecting datetime object.')
+ if self._not_valid_after is not None:
+ raise ValueError('The not valid after may only be set once.')
+ time = _convert_to_naive_utc_time(time)
+ if time < _EARLIEST_UTC_TIME:
+ raise ValueError('The not valid after date must be on or after'
+ ' 1950 January 1.')
+ if (self._not_valid_before is not None and
+ time < self._not_valid_before):
+ raise ValueError(
+ 'The not valid after date must be after the not valid before '
+ 'date.'
+ )
+ return CertificateBuilder(
+ self._issuer_name, self._subject_name,
+ self._public_key, self._serial_number, self._not_valid_before,
+ time, self._extensions
+ )
+
+ def add_extension(self, extension, critical):
+ """
+ Adds an X.509 extension to the certificate.
+ """
+ if not isinstance(extension, ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+
+ return CertificateBuilder(
+ self._issuer_name, self._subject_name,
+ self._public_key, self._serial_number, self._not_valid_before,
+ self._not_valid_after, self._extensions + [extension]
+ )
+
+ def sign(self, private_key, algorithm, backend):
+ """
+ Signs the certificate using the CA's private key.
+ """
+ if self._subject_name is None:
+ raise ValueError("A certificate must have a subject name")
+
+ if self._issuer_name is None:
+ raise ValueError("A certificate must have an issuer name")
+
+ if self._serial_number is None:
+ raise ValueError("A certificate must have a serial number")
+
+ if self._not_valid_before is None:
+ raise ValueError("A certificate must have a not valid before time")
+
+ if self._not_valid_after is None:
+ raise ValueError("A certificate must have a not valid after time")
+
+ if self._public_key is None:
+ raise ValueError("A certificate must have a public key")
+
+ return backend.create_x509_certificate(self, private_key, algorithm)
+
+
+class CertificateRevocationListBuilder(object):
+ def __init__(self, issuer_name=None, last_update=None, next_update=None,
+ extensions=[], revoked_certificates=[]):
+ self._issuer_name = issuer_name
+ self._last_update = last_update
+ self._next_update = next_update
+ self._extensions = extensions
+ self._revoked_certificates = revoked_certificates
+
+ def issuer_name(self, issuer_name):
+ if not isinstance(issuer_name, Name):
+ raise TypeError('Expecting x509.Name object.')
+ if self._issuer_name is not None:
+ raise ValueError('The issuer name may only be set once.')
+ return CertificateRevocationListBuilder(
+ issuer_name, self._last_update, self._next_update,
+ self._extensions, self._revoked_certificates
+ )
+
+ def last_update(self, last_update):
+ if not isinstance(last_update, datetime.datetime):
+ raise TypeError('Expecting datetime object.')
+ if self._last_update is not None:
+ raise ValueError('Last update may only be set once.')
+ last_update = _convert_to_naive_utc_time(last_update)
+ if last_update < _EARLIEST_UTC_TIME:
+ raise ValueError('The last update date must be on or after'
+ ' 1950 January 1.')
+ if self._next_update is not None and last_update > self._next_update:
+ raise ValueError(
+ 'The last update date must be before the next update date.'
+ )
+ return CertificateRevocationListBuilder(
+ self._issuer_name, last_update, self._next_update,
+ self._extensions, self._revoked_certificates
+ )
+
+ def next_update(self, next_update):
+ if not isinstance(next_update, datetime.datetime):
+ raise TypeError('Expecting datetime object.')
+ if self._next_update is not None:
+ raise ValueError('Last update may only be set once.')
+ next_update = _convert_to_naive_utc_time(next_update)
+ if next_update < _EARLIEST_UTC_TIME:
+ raise ValueError('The last update date must be on or after'
+ ' 1950 January 1.')
+ if self._last_update is not None and next_update < self._last_update:
+ raise ValueError(
+ 'The next update date must be after the last update date.'
+ )
+ return CertificateRevocationListBuilder(
+ self._issuer_name, self._last_update, next_update,
+ self._extensions, self._revoked_certificates
+ )
+
+ def add_extension(self, extension, critical):
+ """
+ Adds an X.509 extension to the certificate revocation list.
+ """
+ if not isinstance(extension, ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+ return CertificateRevocationListBuilder(
+ self._issuer_name, self._last_update, self._next_update,
+ self._extensions + [extension], self._revoked_certificates
+ )
+
+ def add_revoked_certificate(self, revoked_certificate):
+ """
+ Adds a revoked certificate to the CRL.
+ """
+ if not isinstance(revoked_certificate, RevokedCertificate):
+ raise TypeError("Must be an instance of RevokedCertificate")
+
+ return CertificateRevocationListBuilder(
+ self._issuer_name, self._last_update,
+ self._next_update, self._extensions,
+ self._revoked_certificates + [revoked_certificate]
+ )
+
+ def sign(self, private_key, algorithm, backend):
+ if self._issuer_name is None:
+ raise ValueError("A CRL must have an issuer name")
+
+ if self._last_update is None:
+ raise ValueError("A CRL must have a last update time")
+
+ if self._next_update is None:
+ raise ValueError("A CRL must have a next update time")
+
+ return backend.create_x509_crl(self, private_key, algorithm)
+
+
+class RevokedCertificateBuilder(object):
+ def __init__(self, serial_number=None, revocation_date=None,
+ extensions=[]):
+ self._serial_number = serial_number
+ self._revocation_date = revocation_date
+ self._extensions = extensions
+
+ def serial_number(self, number):
+ if not isinstance(number, six.integer_types):
+ raise TypeError('Serial number must be of integral type.')
+ if self._serial_number is not None:
+ raise ValueError('The serial number may only be set once.')
+ if number <= 0:
+ raise ValueError('The serial number should be positive')
+
+ # ASN.1 integers are always signed, so most significant bit must be
+ # zero.
+ if number.bit_length() >= 160: # As defined in RFC 5280
+ raise ValueError('The serial number should not be more than 159 '
+ 'bits.')
+ return RevokedCertificateBuilder(
+ number, self._revocation_date, self._extensions
+ )
+
+ def revocation_date(self, time):
+ if not isinstance(time, datetime.datetime):
+ raise TypeError('Expecting datetime object.')
+ if self._revocation_date is not None:
+ raise ValueError('The revocation date may only be set once.')
+ time = _convert_to_naive_utc_time(time)
+ if time < _EARLIEST_UTC_TIME:
+ raise ValueError('The revocation date must be on or after'
+ ' 1950 January 1.')
+ return RevokedCertificateBuilder(
+ self._serial_number, time, self._extensions
+ )
+
+ def add_extension(self, extension, critical):
+ if not isinstance(extension, ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+ return RevokedCertificateBuilder(
+ self._serial_number, self._revocation_date,
+ self._extensions + [extension]
+ )
+
+ def build(self, backend):
+ if self._serial_number is None:
+ raise ValueError("A revoked certificate must have a serial number")
+ if self._revocation_date is None:
+ raise ValueError(
+ "A revoked certificate must have a revocation date"
+ )
+
+ return backend.create_x509_revoked_certificate(self)
+
+
+def random_serial_number():
+ return utils.int_from_bytes(os.urandom(20), "big") >> 1
diff --git a/src/cryptography/x509/certificate_transparency.py b/src/cryptography/x509/certificate_transparency.py
new file mode 100644
index 00000000..d00fe812
--- /dev/null
+++ b/src/cryptography/x509/certificate_transparency.py
@@ -0,0 +1,46 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+from enum import Enum
+
+import six
+
+
+class LogEntryType(Enum):
+ X509_CERTIFICATE = 0
+ PRE_CERTIFICATE = 1
+
+
+class Version(Enum):
+ v1 = 0
+
+
+@six.add_metaclass(abc.ABCMeta)
+class SignedCertificateTimestamp(object):
+ @abc.abstractproperty
+ def version(self):
+ """
+ Returns the SCT version.
+ """
+
+ @abc.abstractproperty
+ def log_id(self):
+ """
+ Returns an identifier indicating which log this SCT is for.
+ """
+
+ @abc.abstractproperty
+ def timestamp(self):
+ """
+ Returns the timestamp for this SCT.
+ """
+
+ @abc.abstractproperty
+ def entry_type(self):
+ """
+ Returns whether this is an SCT for a certificate or pre-certificate.
+ """
diff --git a/src/cryptography/x509/extensions.py b/src/cryptography/x509/extensions.py
new file mode 100644
index 00000000..1b96ffd7
--- /dev/null
+++ b/src/cryptography/x509/extensions.py
@@ -0,0 +1,1595 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+import datetime
+import hashlib
+import ipaddress
+from enum import Enum
+
+import six
+
+from cryptography import utils
+from cryptography.hazmat._der import (
+ BIT_STRING, DERReader, OBJECT_IDENTIFIER, SEQUENCE
+)
+from cryptography.hazmat.primitives import constant_time, serialization
+from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey
+from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey
+from cryptography.x509.certificate_transparency import (
+ SignedCertificateTimestamp
+)
+from cryptography.x509.general_name import GeneralName, IPAddress, OtherName
+from cryptography.x509.name import RelativeDistinguishedName
+from cryptography.x509.oid import (
+ CRLEntryExtensionOID, ExtensionOID, OCSPExtensionOID, ObjectIdentifier,
+)
+
+
+def _key_identifier_from_public_key(public_key):
+ if isinstance(public_key, RSAPublicKey):
+ data = public_key.public_bytes(
+ serialization.Encoding.DER,
+ serialization.PublicFormat.PKCS1,
+ )
+ elif isinstance(public_key, EllipticCurvePublicKey):
+ data = public_key.public_bytes(
+ serialization.Encoding.X962,
+ serialization.PublicFormat.UncompressedPoint
+ )
+ else:
+ # This is a very slow way to do this.
+ serialized = public_key.public_bytes(
+ serialization.Encoding.DER,
+ serialization.PublicFormat.SubjectPublicKeyInfo
+ )
+
+ reader = DERReader(serialized)
+ with reader.read_single_element(SEQUENCE) as public_key_info:
+ algorithm = public_key_info.read_element(SEQUENCE)
+ public_key = public_key_info.read_element(BIT_STRING)
+
+ # Double-check the algorithm structure.
+ with algorithm:
+ algorithm.read_element(OBJECT_IDENTIFIER)
+ if not algorithm.is_empty():
+ # Skip the optional parameters field.
+ algorithm.read_any_element()
+
+ # BIT STRING contents begin with the number of padding bytes added. It
+ # must be zero for SubjectPublicKeyInfo structures.
+ if public_key.read_byte() != 0:
+ raise ValueError('Invalid public key encoding')
+
+ data = public_key.data
+
+ return hashlib.sha1(data).digest()
+
+
+def _make_sequence_methods(field_name):
+ def len_method(self):
+ return len(getattr(self, field_name))
+
+ def iter_method(self):
+ return iter(getattr(self, field_name))
+
+ def getitem_method(self, idx):
+ return getattr(self, field_name)[idx]
+
+ return len_method, iter_method, getitem_method
+
+
+class DuplicateExtension(Exception):
+ def __init__(self, msg, oid):
+ super(DuplicateExtension, self).__init__(msg)
+ self.oid = oid
+
+
+class ExtensionNotFound(Exception):
+ def __init__(self, msg, oid):
+ super(ExtensionNotFound, self).__init__(msg)
+ self.oid = oid
+
+
+@six.add_metaclass(abc.ABCMeta)
+class ExtensionType(object):
+ @abc.abstractproperty
+ def oid(self):
+ """
+ Returns the oid associated with the given extension type.
+ """
+
+
+class Extensions(object):
+ def __init__(self, extensions):
+ self._extensions = extensions
+
+ def get_extension_for_oid(self, oid):
+ for ext in self:
+ if ext.oid == oid:
+ return ext
+
+ raise ExtensionNotFound("No {} extension was found".format(oid), oid)
+
+ def get_extension_for_class(self, extclass):
+ if extclass is UnrecognizedExtension:
+ raise TypeError(
+ "UnrecognizedExtension can't be used with "
+ "get_extension_for_class because more than one instance of the"
+ " class may be present."
+ )
+
+ for ext in self:
+ if isinstance(ext.value, extclass):
+ return ext
+
+ raise ExtensionNotFound(
+ "No {} extension was found".format(extclass), extclass.oid
+ )
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
+
+ def __repr__(self):
+ return (
+ "<Extensions({})>".format(self._extensions)
+ )
+
+
+@utils.register_interface(ExtensionType)
+class CRLNumber(object):
+ oid = ExtensionOID.CRL_NUMBER
+
+ def __init__(self, crl_number):
+ if not isinstance(crl_number, six.integer_types):
+ raise TypeError("crl_number must be an integer")
+
+ self._crl_number = crl_number
+
+ def __eq__(self, other):
+ if not isinstance(other, CRLNumber):
+ return NotImplemented
+
+ return self.crl_number == other.crl_number
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.crl_number)
+
+ def __repr__(self):
+ return "<CRLNumber({})>".format(self.crl_number)
+
+ crl_number = utils.read_only_property("_crl_number")
+
+
+@utils.register_interface(ExtensionType)
+class AuthorityKeyIdentifier(object):
+ oid = ExtensionOID.AUTHORITY_KEY_IDENTIFIER
+
+ def __init__(self, key_identifier, authority_cert_issuer,
+ authority_cert_serial_number):
+ if (authority_cert_issuer is None) != (
+ authority_cert_serial_number is None
+ ):
+ raise ValueError(
+ "authority_cert_issuer and authority_cert_serial_number "
+ "must both be present or both None"
+ )
+
+ if authority_cert_issuer is not None:
+ authority_cert_issuer = list(authority_cert_issuer)
+ if not all(
+ isinstance(x, GeneralName) for x in authority_cert_issuer
+ ):
+ raise TypeError(
+ "authority_cert_issuer must be a list of GeneralName "
+ "objects"
+ )
+
+ if authority_cert_serial_number is not None and not isinstance(
+ authority_cert_serial_number, six.integer_types
+ ):
+ raise TypeError(
+ "authority_cert_serial_number must be an integer"
+ )
+
+ self._key_identifier = key_identifier
+ self._authority_cert_issuer = authority_cert_issuer
+ self._authority_cert_serial_number = authority_cert_serial_number
+
+ @classmethod
+ def from_issuer_public_key(cls, public_key):
+ digest = _key_identifier_from_public_key(public_key)
+ return cls(
+ key_identifier=digest,
+ authority_cert_issuer=None,
+ authority_cert_serial_number=None
+ )
+
+ @classmethod
+ def from_issuer_subject_key_identifier(cls, ski):
+ return cls(
+ key_identifier=ski.digest,
+ authority_cert_issuer=None,
+ authority_cert_serial_number=None
+ )
+
+ def __repr__(self):
+ return (
+ "<AuthorityKeyIdentifier(key_identifier={0.key_identifier!r}, "
+ "authority_cert_issuer={0.authority_cert_issuer}, "
+ "authority_cert_serial_number={0.authority_cert_serial_number}"
+ ")>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, AuthorityKeyIdentifier):
+ return NotImplemented
+
+ return (
+ self.key_identifier == other.key_identifier and
+ self.authority_cert_issuer == other.authority_cert_issuer and
+ self.authority_cert_serial_number ==
+ other.authority_cert_serial_number
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ if self.authority_cert_issuer is None:
+ aci = None
+ else:
+ aci = tuple(self.authority_cert_issuer)
+ return hash((
+ self.key_identifier, aci, self.authority_cert_serial_number
+ ))
+
+ key_identifier = utils.read_only_property("_key_identifier")
+ authority_cert_issuer = utils.read_only_property("_authority_cert_issuer")
+ authority_cert_serial_number = utils.read_only_property(
+ "_authority_cert_serial_number"
+ )
+
+
+@utils.register_interface(ExtensionType)
+class SubjectKeyIdentifier(object):
+ oid = ExtensionOID.SUBJECT_KEY_IDENTIFIER
+
+ def __init__(self, digest):
+ self._digest = digest
+
+ @classmethod
+ def from_public_key(cls, public_key):
+ return cls(_key_identifier_from_public_key(public_key))
+
+ digest = utils.read_only_property("_digest")
+
+ def __repr__(self):
+ return "<SubjectKeyIdentifier(digest={0!r})>".format(self.digest)
+
+ def __eq__(self, other):
+ if not isinstance(other, SubjectKeyIdentifier):
+ return NotImplemented
+
+ return constant_time.bytes_eq(self.digest, other.digest)
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.digest)
+
+
+@utils.register_interface(ExtensionType)
+class AuthorityInformationAccess(object):
+ oid = ExtensionOID.AUTHORITY_INFORMATION_ACCESS
+
+ def __init__(self, descriptions):
+ descriptions = list(descriptions)
+ if not all(isinstance(x, AccessDescription) for x in descriptions):
+ raise TypeError(
+ "Every item in the descriptions list must be an "
+ "AccessDescription"
+ )
+
+ self._descriptions = descriptions
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_descriptions")
+
+ def __repr__(self):
+ return "<AuthorityInformationAccess({})>".format(self._descriptions)
+
+ def __eq__(self, other):
+ if not isinstance(other, AuthorityInformationAccess):
+ return NotImplemented
+
+ return self._descriptions == other._descriptions
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._descriptions))
+
+
+class AccessDescription(object):
+ def __init__(self, access_method, access_location):
+ if not isinstance(access_method, ObjectIdentifier):
+ raise TypeError("access_method must be an ObjectIdentifier")
+
+ if not isinstance(access_location, GeneralName):
+ raise TypeError("access_location must be a GeneralName")
+
+ self._access_method = access_method
+ self._access_location = access_location
+
+ def __repr__(self):
+ return (
+ "<AccessDescription(access_method={0.access_method}, access_locati"
+ "on={0.access_location})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, AccessDescription):
+ return NotImplemented
+
+ return (
+ self.access_method == other.access_method and
+ self.access_location == other.access_location
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.access_method, self.access_location))
+
+ access_method = utils.read_only_property("_access_method")
+ access_location = utils.read_only_property("_access_location")
+
+
+@utils.register_interface(ExtensionType)
+class BasicConstraints(object):
+ oid = ExtensionOID.BASIC_CONSTRAINTS
+
+ def __init__(self, ca, path_length):
+ if not isinstance(ca, bool):
+ raise TypeError("ca must be a boolean value")
+
+ if path_length is not None and not ca:
+ raise ValueError("path_length must be None when ca is False")
+
+ if (
+ path_length is not None and
+ (not isinstance(path_length, six.integer_types) or path_length < 0)
+ ):
+ raise TypeError(
+ "path_length must be a non-negative integer or None"
+ )
+
+ self._ca = ca
+ self._path_length = path_length
+
+ ca = utils.read_only_property("_ca")
+ path_length = utils.read_only_property("_path_length")
+
+ def __repr__(self):
+ return ("<BasicConstraints(ca={0.ca}, "
+ "path_length={0.path_length})>").format(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, BasicConstraints):
+ return NotImplemented
+
+ return self.ca == other.ca and self.path_length == other.path_length
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.ca, self.path_length))
+
+
+@utils.register_interface(ExtensionType)
+class DeltaCRLIndicator(object):
+ oid = ExtensionOID.DELTA_CRL_INDICATOR
+
+ def __init__(self, crl_number):
+ if not isinstance(crl_number, six.integer_types):
+ raise TypeError("crl_number must be an integer")
+
+ self._crl_number = crl_number
+
+ crl_number = utils.read_only_property("_crl_number")
+
+ def __eq__(self, other):
+ if not isinstance(other, DeltaCRLIndicator):
+ return NotImplemented
+
+ return self.crl_number == other.crl_number
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.crl_number)
+
+ def __repr__(self):
+ return "<DeltaCRLIndicator(crl_number={0.crl_number})>".format(self)
+
+
+@utils.register_interface(ExtensionType)
+class CRLDistributionPoints(object):
+ oid = ExtensionOID.CRL_DISTRIBUTION_POINTS
+
+ def __init__(self, distribution_points):
+ distribution_points = list(distribution_points)
+ if not all(
+ isinstance(x, DistributionPoint) for x in distribution_points
+ ):
+ raise TypeError(
+ "distribution_points must be a list of DistributionPoint "
+ "objects"
+ )
+
+ self._distribution_points = distribution_points
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
+ "_distribution_points"
+ )
+
+ def __repr__(self):
+ return "<CRLDistributionPoints({})>".format(self._distribution_points)
+
+ def __eq__(self, other):
+ if not isinstance(other, CRLDistributionPoints):
+ return NotImplemented
+
+ return self._distribution_points == other._distribution_points
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._distribution_points))
+
+
+@utils.register_interface(ExtensionType)
+class FreshestCRL(object):
+ oid = ExtensionOID.FRESHEST_CRL
+
+ def __init__(self, distribution_points):
+ distribution_points = list(distribution_points)
+ if not all(
+ isinstance(x, DistributionPoint) for x in distribution_points
+ ):
+ raise TypeError(
+ "distribution_points must be a list of DistributionPoint "
+ "objects"
+ )
+
+ self._distribution_points = distribution_points
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
+ "_distribution_points"
+ )
+
+ def __repr__(self):
+ return "<FreshestCRL({})>".format(self._distribution_points)
+
+ def __eq__(self, other):
+ if not isinstance(other, FreshestCRL):
+ return NotImplemented
+
+ return self._distribution_points == other._distribution_points
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._distribution_points))
+
+
+class DistributionPoint(object):
+ def __init__(self, full_name, relative_name, reasons, crl_issuer):
+ if full_name and relative_name:
+ raise ValueError(
+ "You cannot provide both full_name and relative_name, at "
+ "least one must be None."
+ )
+
+ if full_name:
+ full_name = list(full_name)
+ if not all(isinstance(x, GeneralName) for x in full_name):
+ raise TypeError(
+ "full_name must be a list of GeneralName objects"
+ )
+
+ if relative_name:
+ if not isinstance(relative_name, RelativeDistinguishedName):
+ raise TypeError(
+ "relative_name must be a RelativeDistinguishedName"
+ )
+
+ if crl_issuer:
+ crl_issuer = list(crl_issuer)
+ if not all(isinstance(x, GeneralName) for x in crl_issuer):
+ raise TypeError(
+ "crl_issuer must be None or a list of general names"
+ )
+
+ if reasons and (not isinstance(reasons, frozenset) or not all(
+ isinstance(x, ReasonFlags) for x in reasons
+ )):
+ raise TypeError("reasons must be None or frozenset of ReasonFlags")
+
+ if reasons and (
+ ReasonFlags.unspecified in reasons or
+ ReasonFlags.remove_from_crl in reasons
+ ):
+ raise ValueError(
+ "unspecified and remove_from_crl are not valid reasons in a "
+ "DistributionPoint"
+ )
+
+ if reasons and not crl_issuer and not (full_name or relative_name):
+ raise ValueError(
+ "You must supply crl_issuer, full_name, or relative_name when "
+ "reasons is not None"
+ )
+
+ self._full_name = full_name
+ self._relative_name = relative_name
+ self._reasons = reasons
+ self._crl_issuer = crl_issuer
+
+ def __repr__(self):
+ return (
+ "<DistributionPoint(full_name={0.full_name}, relative_name={0.rela"
+ "tive_name}, reasons={0.reasons}, crl_issuer={0.crl_issuer})>"
+ .format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, DistributionPoint):
+ return NotImplemented
+
+ return (
+ self.full_name == other.full_name and
+ self.relative_name == other.relative_name and
+ self.reasons == other.reasons and
+ self.crl_issuer == other.crl_issuer
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ if self.full_name is not None:
+ fn = tuple(self.full_name)
+ else:
+ fn = None
+
+ if self.crl_issuer is not None:
+ crl_issuer = tuple(self.crl_issuer)
+ else:
+ crl_issuer = None
+
+ return hash((fn, self.relative_name, self.reasons, crl_issuer))
+
+ full_name = utils.read_only_property("_full_name")
+ relative_name = utils.read_only_property("_relative_name")
+ reasons = utils.read_only_property("_reasons")
+ crl_issuer = utils.read_only_property("_crl_issuer")
+
+
+class ReasonFlags(Enum):
+ unspecified = "unspecified"
+ key_compromise = "keyCompromise"
+ ca_compromise = "cACompromise"
+ affiliation_changed = "affiliationChanged"
+ superseded = "superseded"
+ cessation_of_operation = "cessationOfOperation"
+ certificate_hold = "certificateHold"
+ privilege_withdrawn = "privilegeWithdrawn"
+ aa_compromise = "aACompromise"
+ remove_from_crl = "removeFromCRL"
+
+
+@utils.register_interface(ExtensionType)
+class PolicyConstraints(object):
+ oid = ExtensionOID.POLICY_CONSTRAINTS
+
+ def __init__(self, require_explicit_policy, inhibit_policy_mapping):
+ if require_explicit_policy is not None and not isinstance(
+ require_explicit_policy, six.integer_types
+ ):
+ raise TypeError(
+ "require_explicit_policy must be a non-negative integer or "
+ "None"
+ )
+
+ if inhibit_policy_mapping is not None and not isinstance(
+ inhibit_policy_mapping, six.integer_types
+ ):
+ raise TypeError(
+ "inhibit_policy_mapping must be a non-negative integer or None"
+ )
+
+ if inhibit_policy_mapping is None and require_explicit_policy is None:
+ raise ValueError(
+ "At least one of require_explicit_policy and "
+ "inhibit_policy_mapping must not be None"
+ )
+
+ self._require_explicit_policy = require_explicit_policy
+ self._inhibit_policy_mapping = inhibit_policy_mapping
+
+ def __repr__(self):
+ return (
+ u"<PolicyConstraints(require_explicit_policy={0.require_explicit"
+ u"_policy}, inhibit_policy_mapping={0.inhibit_policy_"
+ u"mapping})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, PolicyConstraints):
+ return NotImplemented
+
+ return (
+ self.require_explicit_policy == other.require_explicit_policy and
+ self.inhibit_policy_mapping == other.inhibit_policy_mapping
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(
+ (self.require_explicit_policy, self.inhibit_policy_mapping)
+ )
+
+ require_explicit_policy = utils.read_only_property(
+ "_require_explicit_policy"
+ )
+ inhibit_policy_mapping = utils.read_only_property(
+ "_inhibit_policy_mapping"
+ )
+
+
+@utils.register_interface(ExtensionType)
+class CertificatePolicies(object):
+ oid = ExtensionOID.CERTIFICATE_POLICIES
+
+ def __init__(self, policies):
+ policies = list(policies)
+ if not all(isinstance(x, PolicyInformation) for x in policies):
+ raise TypeError(
+ "Every item in the policies list must be a "
+ "PolicyInformation"
+ )
+
+ self._policies = policies
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_policies")
+
+ def __repr__(self):
+ return "<CertificatePolicies({})>".format(self._policies)
+
+ def __eq__(self, other):
+ if not isinstance(other, CertificatePolicies):
+ return NotImplemented
+
+ return self._policies == other._policies
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._policies))
+
+
+class PolicyInformation(object):
+ def __init__(self, policy_identifier, policy_qualifiers):
+ if not isinstance(policy_identifier, ObjectIdentifier):
+ raise TypeError("policy_identifier must be an ObjectIdentifier")
+
+ self._policy_identifier = policy_identifier
+
+ if policy_qualifiers:
+ policy_qualifiers = list(policy_qualifiers)
+ if not all(
+ isinstance(x, (six.text_type, UserNotice))
+ for x in policy_qualifiers
+ ):
+ raise TypeError(
+ "policy_qualifiers must be a list of strings and/or "
+ "UserNotice objects or None"
+ )
+
+ self._policy_qualifiers = policy_qualifiers
+
+ def __repr__(self):
+ return (
+ "<PolicyInformation(policy_identifier={0.policy_identifier}, polic"
+ "y_qualifiers={0.policy_qualifiers})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, PolicyInformation):
+ return NotImplemented
+
+ return (
+ self.policy_identifier == other.policy_identifier and
+ self.policy_qualifiers == other.policy_qualifiers
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ if self.policy_qualifiers is not None:
+ pq = tuple(self.policy_qualifiers)
+ else:
+ pq = None
+
+ return hash((self.policy_identifier, pq))
+
+ policy_identifier = utils.read_only_property("_policy_identifier")
+ policy_qualifiers = utils.read_only_property("_policy_qualifiers")
+
+
+class UserNotice(object):
+ def __init__(self, notice_reference, explicit_text):
+ if notice_reference and not isinstance(
+ notice_reference, NoticeReference
+ ):
+ raise TypeError(
+ "notice_reference must be None or a NoticeReference"
+ )
+
+ self._notice_reference = notice_reference
+ self._explicit_text = explicit_text
+
+ def __repr__(self):
+ return (
+ "<UserNotice(notice_reference={0.notice_reference}, explicit_text="
+ "{0.explicit_text!r})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, UserNotice):
+ return NotImplemented
+
+ return (
+ self.notice_reference == other.notice_reference and
+ self.explicit_text == other.explicit_text
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.notice_reference, self.explicit_text))
+
+ notice_reference = utils.read_only_property("_notice_reference")
+ explicit_text = utils.read_only_property("_explicit_text")
+
+
+class NoticeReference(object):
+ def __init__(self, organization, notice_numbers):
+ self._organization = organization
+ notice_numbers = list(notice_numbers)
+ if not all(isinstance(x, int) for x in notice_numbers):
+ raise TypeError(
+ "notice_numbers must be a list of integers"
+ )
+
+ self._notice_numbers = notice_numbers
+
+ def __repr__(self):
+ return (
+ "<NoticeReference(organization={0.organization!r}, notice_numbers="
+ "{0.notice_numbers})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, NoticeReference):
+ return NotImplemented
+
+ return (
+ self.organization == other.organization and
+ self.notice_numbers == other.notice_numbers
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.organization, tuple(self.notice_numbers)))
+
+ organization = utils.read_only_property("_organization")
+ notice_numbers = utils.read_only_property("_notice_numbers")
+
+
+@utils.register_interface(ExtensionType)
+class ExtendedKeyUsage(object):
+ oid = ExtensionOID.EXTENDED_KEY_USAGE
+
+ def __init__(self, usages):
+ usages = list(usages)
+ if not all(isinstance(x, ObjectIdentifier) for x in usages):
+ raise TypeError(
+ "Every item in the usages list must be an ObjectIdentifier"
+ )
+
+ self._usages = usages
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_usages")
+
+ def __repr__(self):
+ return "<ExtendedKeyUsage({})>".format(self._usages)
+
+ def __eq__(self, other):
+ if not isinstance(other, ExtendedKeyUsage):
+ return NotImplemented
+
+ return self._usages == other._usages
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._usages))
+
+
+@utils.register_interface(ExtensionType)
+class OCSPNoCheck(object):
+ oid = ExtensionOID.OCSP_NO_CHECK
+
+ def __eq__(self, other):
+ if not isinstance(other, OCSPNoCheck):
+ return NotImplemented
+
+ return True
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(OCSPNoCheck)
+
+ def __repr__(self):
+ return "<OCSPNoCheck()>"
+
+
+@utils.register_interface(ExtensionType)
+class PrecertPoison(object):
+ oid = ExtensionOID.PRECERT_POISON
+
+ def __eq__(self, other):
+ if not isinstance(other, PrecertPoison):
+ return NotImplemented
+
+ return True
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(PrecertPoison)
+
+ def __repr__(self):
+ return "<PrecertPoison()>"
+
+
+@utils.register_interface(ExtensionType)
+class TLSFeature(object):
+ oid = ExtensionOID.TLS_FEATURE
+
+ def __init__(self, features):
+ features = list(features)
+ if (
+ not all(isinstance(x, TLSFeatureType) for x in features) or
+ len(features) == 0
+ ):
+ raise TypeError(
+ "features must be a list of elements from the TLSFeatureType "
+ "enum"
+ )
+
+ self._features = features
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_features")
+
+ def __repr__(self):
+ return "<TLSFeature(features={0._features})>".format(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, TLSFeature):
+ return NotImplemented
+
+ return self._features == other._features
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._features))
+
+
+class TLSFeatureType(Enum):
+ # status_request is defined in RFC 6066 and is used for what is commonly
+ # called OCSP Must-Staple when present in the TLS Feature extension in an
+ # X.509 certificate.
+ status_request = 5
+ # status_request_v2 is defined in RFC 6961 and allows multiple OCSP
+ # responses to be provided. It is not currently in use by clients or
+ # servers.
+ status_request_v2 = 17
+
+
+_TLS_FEATURE_TYPE_TO_ENUM = {x.value: x for x in TLSFeatureType}
+
+
+@utils.register_interface(ExtensionType)
+class InhibitAnyPolicy(object):
+ oid = ExtensionOID.INHIBIT_ANY_POLICY
+
+ def __init__(self, skip_certs):
+ if not isinstance(skip_certs, six.integer_types):
+ raise TypeError("skip_certs must be an integer")
+
+ if skip_certs < 0:
+ raise ValueError("skip_certs must be a non-negative integer")
+
+ self._skip_certs = skip_certs
+
+ def __repr__(self):
+ return "<InhibitAnyPolicy(skip_certs={0.skip_certs})>".format(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, InhibitAnyPolicy):
+ return NotImplemented
+
+ return self.skip_certs == other.skip_certs
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.skip_certs)
+
+ skip_certs = utils.read_only_property("_skip_certs")
+
+
+@utils.register_interface(ExtensionType)
+class KeyUsage(object):
+ oid = ExtensionOID.KEY_USAGE
+
+ def __init__(self, digital_signature, content_commitment, key_encipherment,
+ data_encipherment, key_agreement, key_cert_sign, crl_sign,
+ encipher_only, decipher_only):
+ if not key_agreement and (encipher_only or decipher_only):
+ raise ValueError(
+ "encipher_only and decipher_only can only be true when "
+ "key_agreement is true"
+ )
+
+ self._digital_signature = digital_signature
+ self._content_commitment = content_commitment
+ self._key_encipherment = key_encipherment
+ self._data_encipherment = data_encipherment
+ self._key_agreement = key_agreement
+ self._key_cert_sign = key_cert_sign
+ self._crl_sign = crl_sign
+ self._encipher_only = encipher_only
+ self._decipher_only = decipher_only
+
+ digital_signature = utils.read_only_property("_digital_signature")
+ content_commitment = utils.read_only_property("_content_commitment")
+ key_encipherment = utils.read_only_property("_key_encipherment")
+ data_encipherment = utils.read_only_property("_data_encipherment")
+ key_agreement = utils.read_only_property("_key_agreement")
+ key_cert_sign = utils.read_only_property("_key_cert_sign")
+ crl_sign = utils.read_only_property("_crl_sign")
+
+ @property
+ def encipher_only(self):
+ if not self.key_agreement:
+ raise ValueError(
+ "encipher_only is undefined unless key_agreement is true"
+ )
+ else:
+ return self._encipher_only
+
+ @property
+ def decipher_only(self):
+ if not self.key_agreement:
+ raise ValueError(
+ "decipher_only is undefined unless key_agreement is true"
+ )
+ else:
+ return self._decipher_only
+
+ def __repr__(self):
+ try:
+ encipher_only = self.encipher_only
+ decipher_only = self.decipher_only
+ except ValueError:
+ encipher_only = None
+ decipher_only = None
+
+ return ("<KeyUsage(digital_signature={0.digital_signature}, "
+ "content_commitment={0.content_commitment}, "
+ "key_encipherment={0.key_encipherment}, "
+ "data_encipherment={0.data_encipherment}, "
+ "key_agreement={0.key_agreement}, "
+ "key_cert_sign={0.key_cert_sign}, crl_sign={0.crl_sign}, "
+ "encipher_only={1}, decipher_only={2})>").format(
+ self, encipher_only, decipher_only)
+
+ def __eq__(self, other):
+ if not isinstance(other, KeyUsage):
+ return NotImplemented
+
+ return (
+ self.digital_signature == other.digital_signature and
+ self.content_commitment == other.content_commitment and
+ self.key_encipherment == other.key_encipherment and
+ self.data_encipherment == other.data_encipherment and
+ self.key_agreement == other.key_agreement and
+ self.key_cert_sign == other.key_cert_sign and
+ self.crl_sign == other.crl_sign and
+ self._encipher_only == other._encipher_only and
+ self._decipher_only == other._decipher_only
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((
+ self.digital_signature, self.content_commitment,
+ self.key_encipherment, self.data_encipherment,
+ self.key_agreement, self.key_cert_sign,
+ self.crl_sign, self._encipher_only,
+ self._decipher_only
+ ))
+
+
+@utils.register_interface(ExtensionType)
+class NameConstraints(object):
+ oid = ExtensionOID.NAME_CONSTRAINTS
+
+ def __init__(self, permitted_subtrees, excluded_subtrees):
+ if permitted_subtrees is not None:
+ permitted_subtrees = list(permitted_subtrees)
+ if not all(
+ isinstance(x, GeneralName) for x in permitted_subtrees
+ ):
+ raise TypeError(
+ "permitted_subtrees must be a list of GeneralName objects "
+ "or None"
+ )
+
+ self._validate_ip_name(permitted_subtrees)
+
+ if excluded_subtrees is not None:
+ excluded_subtrees = list(excluded_subtrees)
+ if not all(
+ isinstance(x, GeneralName) for x in excluded_subtrees
+ ):
+ raise TypeError(
+ "excluded_subtrees must be a list of GeneralName objects "
+ "or None"
+ )
+
+ self._validate_ip_name(excluded_subtrees)
+
+ if permitted_subtrees is None and excluded_subtrees is None:
+ raise ValueError(
+ "At least one of permitted_subtrees and excluded_subtrees "
+ "must not be None"
+ )
+
+ self._permitted_subtrees = permitted_subtrees
+ self._excluded_subtrees = excluded_subtrees
+
+ def __eq__(self, other):
+ if not isinstance(other, NameConstraints):
+ return NotImplemented
+
+ return (
+ self.excluded_subtrees == other.excluded_subtrees and
+ self.permitted_subtrees == other.permitted_subtrees
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def _validate_ip_name(self, tree):
+ if any(isinstance(name, IPAddress) and not isinstance(
+ name.value, (ipaddress.IPv4Network, ipaddress.IPv6Network)
+ ) for name in tree):
+ raise TypeError(
+ "IPAddress name constraints must be an IPv4Network or"
+ " IPv6Network object"
+ )
+
+ def __repr__(self):
+ return (
+ u"<NameConstraints(permitted_subtrees={0.permitted_subtrees}, "
+ u"excluded_subtrees={0.excluded_subtrees})>".format(self)
+ )
+
+ def __hash__(self):
+ if self.permitted_subtrees is not None:
+ ps = tuple(self.permitted_subtrees)
+ else:
+ ps = None
+
+ if self.excluded_subtrees is not None:
+ es = tuple(self.excluded_subtrees)
+ else:
+ es = None
+
+ return hash((ps, es))
+
+ permitted_subtrees = utils.read_only_property("_permitted_subtrees")
+ excluded_subtrees = utils.read_only_property("_excluded_subtrees")
+
+
+class Extension(object):
+ def __init__(self, oid, critical, value):
+ if not isinstance(oid, ObjectIdentifier):
+ raise TypeError(
+ "oid argument must be an ObjectIdentifier instance."
+ )
+
+ if not isinstance(critical, bool):
+ raise TypeError("critical must be a boolean value")
+
+ self._oid = oid
+ self._critical = critical
+ self._value = value
+
+ oid = utils.read_only_property("_oid")
+ critical = utils.read_only_property("_critical")
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return ("<Extension(oid={0.oid}, critical={0.critical}, "
+ "value={0.value})>").format(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, Extension):
+ return NotImplemented
+
+ return (
+ self.oid == other.oid and
+ self.critical == other.critical and
+ self.value == other.value
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.oid, self.critical, self.value))
+
+
+class GeneralNames(object):
+ def __init__(self, general_names):
+ general_names = list(general_names)
+ if not all(isinstance(x, GeneralName) for x in general_names):
+ raise TypeError(
+ "Every item in the general_names list must be an "
+ "object conforming to the GeneralName interface"
+ )
+
+ self._general_names = general_names
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
+
+ def get_values_for_type(self, type):
+ # Return the value of each GeneralName, except for OtherName instances
+ # which we return directly because it has two important properties not
+ # just one value.
+ objs = (i for i in self if isinstance(i, type))
+ if type != OtherName:
+ objs = (i.value for i in objs)
+ return list(objs)
+
+ def __repr__(self):
+ return "<GeneralNames({})>".format(self._general_names)
+
+ def __eq__(self, other):
+ if not isinstance(other, GeneralNames):
+ return NotImplemented
+
+ return self._general_names == other._general_names
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(tuple(self._general_names))
+
+
+@utils.register_interface(ExtensionType)
+class SubjectAlternativeName(object):
+ oid = ExtensionOID.SUBJECT_ALTERNATIVE_NAME
+
+ def __init__(self, general_names):
+ self._general_names = GeneralNames(general_names)
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
+
+ def get_values_for_type(self, type):
+ return self._general_names.get_values_for_type(type)
+
+ def __repr__(self):
+ return "<SubjectAlternativeName({})>".format(self._general_names)
+
+ def __eq__(self, other):
+ if not isinstance(other, SubjectAlternativeName):
+ return NotImplemented
+
+ return self._general_names == other._general_names
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self._general_names)
+
+
+@utils.register_interface(ExtensionType)
+class IssuerAlternativeName(object):
+ oid = ExtensionOID.ISSUER_ALTERNATIVE_NAME
+
+ def __init__(self, general_names):
+ self._general_names = GeneralNames(general_names)
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
+
+ def get_values_for_type(self, type):
+ return self._general_names.get_values_for_type(type)
+
+ def __repr__(self):
+ return "<IssuerAlternativeName({})>".format(self._general_names)
+
+ def __eq__(self, other):
+ if not isinstance(other, IssuerAlternativeName):
+ return NotImplemented
+
+ return self._general_names == other._general_names
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self._general_names)
+
+
+@utils.register_interface(ExtensionType)
+class CertificateIssuer(object):
+ oid = CRLEntryExtensionOID.CERTIFICATE_ISSUER
+
+ def __init__(self, general_names):
+ self._general_names = GeneralNames(general_names)
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_general_names")
+
+ def get_values_for_type(self, type):
+ return self._general_names.get_values_for_type(type)
+
+ def __repr__(self):
+ return "<CertificateIssuer({})>".format(self._general_names)
+
+ def __eq__(self, other):
+ if not isinstance(other, CertificateIssuer):
+ return NotImplemented
+
+ return self._general_names == other._general_names
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self._general_names)
+
+
+@utils.register_interface(ExtensionType)
+class CRLReason(object):
+ oid = CRLEntryExtensionOID.CRL_REASON
+
+ def __init__(self, reason):
+ if not isinstance(reason, ReasonFlags):
+ raise TypeError("reason must be an element from ReasonFlags")
+
+ self._reason = reason
+
+ def __repr__(self):
+ return "<CRLReason(reason={})>".format(self._reason)
+
+ def __eq__(self, other):
+ if not isinstance(other, CRLReason):
+ return NotImplemented
+
+ return self.reason == other.reason
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.reason)
+
+ reason = utils.read_only_property("_reason")
+
+
+@utils.register_interface(ExtensionType)
+class InvalidityDate(object):
+ oid = CRLEntryExtensionOID.INVALIDITY_DATE
+
+ def __init__(self, invalidity_date):
+ if not isinstance(invalidity_date, datetime.datetime):
+ raise TypeError("invalidity_date must be a datetime.datetime")
+
+ self._invalidity_date = invalidity_date
+
+ def __repr__(self):
+ return "<InvalidityDate(invalidity_date={})>".format(
+ self._invalidity_date
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, InvalidityDate):
+ return NotImplemented
+
+ return self.invalidity_date == other.invalidity_date
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.invalidity_date)
+
+ invalidity_date = utils.read_only_property("_invalidity_date")
+
+
+@utils.register_interface(ExtensionType)
+class PrecertificateSignedCertificateTimestamps(object):
+ oid = ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS
+
+ def __init__(self, signed_certificate_timestamps):
+ signed_certificate_timestamps = list(signed_certificate_timestamps)
+ if not all(
+ isinstance(sct, SignedCertificateTimestamp)
+ for sct in signed_certificate_timestamps
+ ):
+ raise TypeError(
+ "Every item in the signed_certificate_timestamps list must be "
+ "a SignedCertificateTimestamp"
+ )
+ self._signed_certificate_timestamps = signed_certificate_timestamps
+
+ __len__, __iter__, __getitem__ = _make_sequence_methods(
+ "_signed_certificate_timestamps"
+ )
+
+ def __repr__(self):
+ return (
+ "<PrecertificateSignedCertificateTimestamps({})>".format(
+ list(self)
+ )
+ )
+
+ def __hash__(self):
+ return hash(tuple(self._signed_certificate_timestamps))
+
+ def __eq__(self, other):
+ if not isinstance(other, PrecertificateSignedCertificateTimestamps):
+ return NotImplemented
+
+ return (
+ self._signed_certificate_timestamps ==
+ other._signed_certificate_timestamps
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+
+@utils.register_interface(ExtensionType)
+class OCSPNonce(object):
+ oid = OCSPExtensionOID.NONCE
+
+ def __init__(self, nonce):
+ if not isinstance(nonce, bytes):
+ raise TypeError("nonce must be bytes")
+
+ self._nonce = nonce
+
+ def __eq__(self, other):
+ if not isinstance(other, OCSPNonce):
+ return NotImplemented
+
+ return self.nonce == other.nonce
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.nonce)
+
+ def __repr__(self):
+ return "<OCSPNonce(nonce={0.nonce!r})>".format(self)
+
+ nonce = utils.read_only_property("_nonce")
+
+
+@utils.register_interface(ExtensionType)
+class IssuingDistributionPoint(object):
+ oid = ExtensionOID.ISSUING_DISTRIBUTION_POINT
+
+ def __init__(self, full_name, relative_name, only_contains_user_certs,
+ only_contains_ca_certs, only_some_reasons, indirect_crl,
+ only_contains_attribute_certs):
+ if (
+ only_some_reasons and (
+ not isinstance(only_some_reasons, frozenset) or not all(
+ isinstance(x, ReasonFlags) for x in only_some_reasons
+ )
+ )
+ ):
+ raise TypeError(
+ "only_some_reasons must be None or frozenset of ReasonFlags"
+ )
+
+ if only_some_reasons and (
+ ReasonFlags.unspecified in only_some_reasons or
+ ReasonFlags.remove_from_crl in only_some_reasons
+ ):
+ raise ValueError(
+ "unspecified and remove_from_crl are not valid reasons in an "
+ "IssuingDistributionPoint"
+ )
+
+ if not (
+ isinstance(only_contains_user_certs, bool) and
+ isinstance(only_contains_ca_certs, bool) and
+ isinstance(indirect_crl, bool) and
+ isinstance(only_contains_attribute_certs, bool)
+ ):
+ raise TypeError(
+ "only_contains_user_certs, only_contains_ca_certs, "
+ "indirect_crl and only_contains_attribute_certs "
+ "must all be boolean."
+ )
+
+ crl_constraints = [
+ only_contains_user_certs, only_contains_ca_certs,
+ indirect_crl, only_contains_attribute_certs
+ ]
+
+ if len([x for x in crl_constraints if x]) > 1:
+ raise ValueError(
+ "Only one of the following can be set to True: "
+ "only_contains_user_certs, only_contains_ca_certs, "
+ "indirect_crl, only_contains_attribute_certs"
+ )
+
+ if (
+ not any([
+ only_contains_user_certs, only_contains_ca_certs,
+ indirect_crl, only_contains_attribute_certs, full_name,
+ relative_name, only_some_reasons
+ ])
+ ):
+ raise ValueError(
+ "Cannot create empty extension: "
+ "if only_contains_user_certs, only_contains_ca_certs, "
+ "indirect_crl, and only_contains_attribute_certs are all False"
+ ", then either full_name, relative_name, or only_some_reasons "
+ "must have a value."
+ )
+
+ self._only_contains_user_certs = only_contains_user_certs
+ self._only_contains_ca_certs = only_contains_ca_certs
+ self._indirect_crl = indirect_crl
+ self._only_contains_attribute_certs = only_contains_attribute_certs
+ self._only_some_reasons = only_some_reasons
+ self._full_name = full_name
+ self._relative_name = relative_name
+
+ def __repr__(self):
+ return (
+ "<IssuingDistributionPoint(full_name={0.full_name}, "
+ "relative_name={0.relative_name}, "
+ "only_contains_user_certs={0.only_contains_user_certs}, "
+ "only_contains_ca_certs={0.only_contains_ca_certs}, "
+ "only_some_reasons={0.only_some_reasons}, "
+ "indirect_crl={0.indirect_crl}, "
+ "only_contains_attribute_certs="
+ "{0.only_contains_attribute_certs})>".format(self)
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, IssuingDistributionPoint):
+ return NotImplemented
+
+ return (
+ self.full_name == other.full_name and
+ self.relative_name == other.relative_name and
+ self.only_contains_user_certs == other.only_contains_user_certs and
+ self.only_contains_ca_certs == other.only_contains_ca_certs and
+ self.only_some_reasons == other.only_some_reasons and
+ self.indirect_crl == other.indirect_crl and
+ self.only_contains_attribute_certs ==
+ other.only_contains_attribute_certs
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((
+ self.full_name,
+ self.relative_name,
+ self.only_contains_user_certs,
+ self.only_contains_ca_certs,
+ self.only_some_reasons,
+ self.indirect_crl,
+ self.only_contains_attribute_certs,
+ ))
+
+ full_name = utils.read_only_property("_full_name")
+ relative_name = utils.read_only_property("_relative_name")
+ only_contains_user_certs = utils.read_only_property(
+ "_only_contains_user_certs"
+ )
+ only_contains_ca_certs = utils.read_only_property(
+ "_only_contains_ca_certs"
+ )
+ only_some_reasons = utils.read_only_property("_only_some_reasons")
+ indirect_crl = utils.read_only_property("_indirect_crl")
+ only_contains_attribute_certs = utils.read_only_property(
+ "_only_contains_attribute_certs"
+ )
+
+
+@utils.register_interface(ExtensionType)
+class UnrecognizedExtension(object):
+ def __init__(self, oid, value):
+ if not isinstance(oid, ObjectIdentifier):
+ raise TypeError("oid must be an ObjectIdentifier")
+ self._oid = oid
+ self._value = value
+
+ oid = utils.read_only_property("_oid")
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return (
+ "<UnrecognizedExtension(oid={0.oid}, value={0.value!r})>".format(
+ self
+ )
+ )
+
+ def __eq__(self, other):
+ if not isinstance(other, UnrecognizedExtension):
+ return NotImplemented
+
+ return self.oid == other.oid and self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.oid, self.value))
diff --git a/src/cryptography/x509/general_name.py b/src/cryptography/x509/general_name.py
new file mode 100644
index 00000000..12338415
--- /dev/null
+++ b/src/cryptography/x509/general_name.py
@@ -0,0 +1,360 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+import ipaddress
+import warnings
+from email.utils import parseaddr
+
+import six
+from six.moves import urllib_parse
+
+from cryptography import utils
+from cryptography.x509.name import Name
+from cryptography.x509.oid import ObjectIdentifier
+
+
+_GENERAL_NAMES = {
+ 0: "otherName",
+ 1: "rfc822Name",
+ 2: "dNSName",
+ 3: "x400Address",
+ 4: "directoryName",
+ 5: "ediPartyName",
+ 6: "uniformResourceIdentifier",
+ 7: "iPAddress",
+ 8: "registeredID",
+}
+
+
+def _lazy_import_idna():
+ # Import idna lazily becase it allocates a decent amount of memory, and
+ # we're only using it in deprecated paths.
+ try:
+ import idna
+ return idna
+ except ImportError:
+ raise ImportError(
+ "idna is not installed, but a deprecated feature that requires it"
+ " was used. See: https://cryptography.io/en/latest/faq/#importe"
+ "rror-idna-is-not-installed"
+ )
+
+
+class UnsupportedGeneralNameType(Exception):
+ def __init__(self, msg, type):
+ super(UnsupportedGeneralNameType, self).__init__(msg)
+ self.type = type
+
+
+@six.add_metaclass(abc.ABCMeta)
+class GeneralName(object):
+ @abc.abstractproperty
+ def value(self):
+ """
+ Return the value of the object
+ """
+
+
+@utils.register_interface(GeneralName)
+class RFC822Name(object):
+ def __init__(self, value):
+ if isinstance(value, six.text_type):
+ try:
+ value.encode("ascii")
+ except UnicodeEncodeError:
+ value = self._idna_encode(value)
+ warnings.warn(
+ "RFC822Name values should be passed as an A-label string. "
+ "This means unicode characters should be encoded via "
+ "idna. Support for passing unicode strings (aka U-label) "
+ "will be removed in a future version.",
+ utils.PersistentlyDeprecated2017,
+ stacklevel=2,
+ )
+ else:
+ raise TypeError("value must be string")
+
+ name, address = parseaddr(value)
+ if name or not address:
+ # parseaddr has found a name (e.g. Name <email>) or the entire
+ # value is an empty string.
+ raise ValueError("Invalid rfc822name value")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ @classmethod
+ def _init_without_validation(cls, value):
+ instance = cls.__new__(cls)
+ instance._value = value
+ return instance
+
+ def _idna_encode(self, value):
+ idna = _lazy_import_idna()
+ _, address = parseaddr(value)
+ parts = address.split(u"@")
+ return parts[0] + "@" + idna.encode(parts[1]).decode("ascii")
+
+ def __repr__(self):
+ return "<RFC822Name(value={0!r})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, RFC822Name):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+def _idna_encode(value):
+ idna = _lazy_import_idna()
+ # Retain prefixes '*.' for common/alt names and '.' for name constraints
+ for prefix in ['*.', '.']:
+ if value.startswith(prefix):
+ value = value[len(prefix):]
+ return prefix + idna.encode(value).decode("ascii")
+ return idna.encode(value).decode("ascii")
+
+
+@utils.register_interface(GeneralName)
+class DNSName(object):
+ def __init__(self, value):
+ if isinstance(value, six.text_type):
+ try:
+ value.encode("ascii")
+ except UnicodeEncodeError:
+ value = _idna_encode(value)
+ warnings.warn(
+ "DNSName values should be passed as an A-label string. "
+ "This means unicode characters should be encoded via "
+ "idna. Support for passing unicode strings (aka U-label) "
+ "will be removed in a future version.",
+ utils.PersistentlyDeprecated2017,
+ stacklevel=2,
+ )
+ else:
+ raise TypeError("value must be string")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ @classmethod
+ def _init_without_validation(cls, value):
+ instance = cls.__new__(cls)
+ instance._value = value
+ return instance
+
+ def __repr__(self):
+ return "<DNSName(value={0!r})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, DNSName):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+@utils.register_interface(GeneralName)
+class UniformResourceIdentifier(object):
+ def __init__(self, value):
+ if isinstance(value, six.text_type):
+ try:
+ value.encode("ascii")
+ except UnicodeEncodeError:
+ value = self._idna_encode(value)
+ warnings.warn(
+ "URI values should be passed as an A-label string. "
+ "This means unicode characters should be encoded via "
+ "idna. Support for passing unicode strings (aka U-label) "
+ " will be removed in a future version.",
+ utils.PersistentlyDeprecated2017,
+ stacklevel=2,
+ )
+ else:
+ raise TypeError("value must be string")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ @classmethod
+ def _init_without_validation(cls, value):
+ instance = cls.__new__(cls)
+ instance._value = value
+ return instance
+
+ def _idna_encode(self, value):
+ idna = _lazy_import_idna()
+ parsed = urllib_parse.urlparse(value)
+ if parsed.port:
+ netloc = (
+ idna.encode(parsed.hostname) +
+ ":{}".format(parsed.port).encode("ascii")
+ ).decode("ascii")
+ else:
+ netloc = idna.encode(parsed.hostname).decode("ascii")
+
+ # Note that building a URL in this fashion means it should be
+ # semantically indistinguishable from the original but is not
+ # guaranteed to be exactly the same.
+ return urllib_parse.urlunparse((
+ parsed.scheme,
+ netloc,
+ parsed.path,
+ parsed.params,
+ parsed.query,
+ parsed.fragment
+ ))
+
+ def __repr__(self):
+ return "<UniformResourceIdentifier(value={0!r})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, UniformResourceIdentifier):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+@utils.register_interface(GeneralName)
+class DirectoryName(object):
+ def __init__(self, value):
+ if not isinstance(value, Name):
+ raise TypeError("value must be a Name")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<DirectoryName(value={})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, DirectoryName):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+@utils.register_interface(GeneralName)
+class RegisteredID(object):
+ def __init__(self, value):
+ if not isinstance(value, ObjectIdentifier):
+ raise TypeError("value must be an ObjectIdentifier")
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<RegisteredID(value={})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, RegisteredID):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+@utils.register_interface(GeneralName)
+class IPAddress(object):
+ def __init__(self, value):
+ if not isinstance(
+ value,
+ (
+ ipaddress.IPv4Address,
+ ipaddress.IPv6Address,
+ ipaddress.IPv4Network,
+ ipaddress.IPv6Network
+ )
+ ):
+ raise TypeError(
+ "value must be an instance of ipaddress.IPv4Address, "
+ "ipaddress.IPv6Address, ipaddress.IPv4Network, or "
+ "ipaddress.IPv6Network"
+ )
+
+ self._value = value
+
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<IPAddress(value={})>".format(self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, IPAddress):
+ return NotImplemented
+
+ return self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self.value)
+
+
+@utils.register_interface(GeneralName)
+class OtherName(object):
+ def __init__(self, type_id, value):
+ if not isinstance(type_id, ObjectIdentifier):
+ raise TypeError("type_id must be an ObjectIdentifier")
+ if not isinstance(value, bytes):
+ raise TypeError("value must be a binary string")
+
+ self._type_id = type_id
+ self._value = value
+
+ type_id = utils.read_only_property("_type_id")
+ value = utils.read_only_property("_value")
+
+ def __repr__(self):
+ return "<OtherName(type_id={}, value={!r})>".format(
+ self.type_id, self.value)
+
+ def __eq__(self, other):
+ if not isinstance(other, OtherName):
+ return NotImplemented
+
+ return self.type_id == other.type_id and self.value == other.value
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.type_id, self.value))
diff --git a/src/cryptography/x509/name.py b/src/cryptography/x509/name.py
new file mode 100644
index 00000000..6816e063
--- /dev/null
+++ b/src/cryptography/x509/name.py
@@ -0,0 +1,263 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from enum import Enum
+
+import six
+
+from cryptography import utils
+from cryptography.x509.oid import NameOID, ObjectIdentifier
+
+
+class _ASN1Type(Enum):
+ UTF8String = 12
+ NumericString = 18
+ PrintableString = 19
+ T61String = 20
+ IA5String = 22
+ UTCTime = 23
+ GeneralizedTime = 24
+ VisibleString = 26
+ UniversalString = 28
+ BMPString = 30
+
+
+_ASN1_TYPE_TO_ENUM = {i.value: i for i in _ASN1Type}
+_SENTINEL = object()
+_NAMEOID_DEFAULT_TYPE = {
+ NameOID.COUNTRY_NAME: _ASN1Type.PrintableString,
+ NameOID.JURISDICTION_COUNTRY_NAME: _ASN1Type.PrintableString,
+ NameOID.SERIAL_NUMBER: _ASN1Type.PrintableString,
+ NameOID.DN_QUALIFIER: _ASN1Type.PrintableString,
+ NameOID.EMAIL_ADDRESS: _ASN1Type.IA5String,
+ NameOID.DOMAIN_COMPONENT: _ASN1Type.IA5String,
+}
+
+#: Short attribute names from RFC 4514:
+#: https://tools.ietf.org/html/rfc4514#page-7
+_NAMEOID_TO_NAME = {
+ NameOID.COMMON_NAME: 'CN',
+ NameOID.LOCALITY_NAME: 'L',
+ NameOID.STATE_OR_PROVINCE_NAME: 'ST',
+ NameOID.ORGANIZATION_NAME: 'O',
+ NameOID.ORGANIZATIONAL_UNIT_NAME: 'OU',
+ NameOID.COUNTRY_NAME: 'C',
+ NameOID.STREET_ADDRESS: 'STREET',
+ NameOID.DOMAIN_COMPONENT: 'DC',
+ NameOID.USER_ID: 'UID',
+}
+
+
+def _escape_dn_value(val):
+ """Escape special characters in RFC4514 Distinguished Name value."""
+
+ if not val:
+ return ''
+
+ # See https://tools.ietf.org/html/rfc4514#section-2.4
+ val = val.replace('\\', '\\\\')
+ val = val.replace('"', '\\"')
+ val = val.replace('+', '\\+')
+ val = val.replace(',', '\\,')
+ val = val.replace(';', '\\;')
+ val = val.replace('<', '\\<')
+ val = val.replace('>', '\\>')
+ val = val.replace('\0', '\\00')
+
+ if val[0] in ('#', ' '):
+ val = '\\' + val
+ if val[-1] == ' ':
+ val = val[:-1] + '\\ '
+
+ return val
+
+
+class NameAttribute(object):
+ def __init__(self, oid, value, _type=_SENTINEL):
+ if not isinstance(oid, ObjectIdentifier):
+ raise TypeError(
+ "oid argument must be an ObjectIdentifier instance."
+ )
+
+ if not isinstance(value, six.text_type):
+ raise TypeError(
+ "value argument must be a text type."
+ )
+
+ if (
+ oid == NameOID.COUNTRY_NAME or
+ oid == NameOID.JURISDICTION_COUNTRY_NAME
+ ):
+ if len(value.encode("utf8")) != 2:
+ raise ValueError(
+ "Country name must be a 2 character country code"
+ )
+
+ # The appropriate ASN1 string type varies by OID and is defined across
+ # multiple RFCs including 2459, 3280, and 5280. In general UTF8String
+ # is preferred (2459), but 3280 and 5280 specify several OIDs with
+ # alternate types. This means when we see the sentinel value we need
+ # to look up whether the OID has a non-UTF8 type. If it does, set it
+ # to that. Otherwise, UTF8!
+ if _type == _SENTINEL:
+ _type = _NAMEOID_DEFAULT_TYPE.get(oid, _ASN1Type.UTF8String)
+
+ if not isinstance(_type, _ASN1Type):
+ raise TypeError("_type must be from the _ASN1Type enum")
+
+ self._oid = oid
+ self._value = value
+ self._type = _type
+
+ oid = utils.read_only_property("_oid")
+ value = utils.read_only_property("_value")
+
+ def rfc4514_string(self):
+ """
+ Format as RFC4514 Distinguished Name string.
+
+ Use short attribute name if available, otherwise fall back to OID
+ dotted string.
+ """
+ key = _NAMEOID_TO_NAME.get(self.oid, self.oid.dotted_string)
+ return '%s=%s' % (key, _escape_dn_value(self.value))
+
+ def __eq__(self, other):
+ if not isinstance(other, NameAttribute):
+ return NotImplemented
+
+ return (
+ self.oid == other.oid and
+ self.value == other.value
+ )
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash((self.oid, self.value))
+
+ def __repr__(self):
+ return "<NameAttribute(oid={0.oid}, value={0.value!r})>".format(self)
+
+
+class RelativeDistinguishedName(object):
+ def __init__(self, attributes):
+ attributes = list(attributes)
+ if not attributes:
+ raise ValueError("a relative distinguished name cannot be empty")
+ if not all(isinstance(x, NameAttribute) for x in attributes):
+ raise TypeError("attributes must be an iterable of NameAttribute")
+
+ # Keep list and frozenset to preserve attribute order where it matters
+ self._attributes = attributes
+ self._attribute_set = frozenset(attributes)
+
+ if len(self._attribute_set) != len(attributes):
+ raise ValueError("duplicate attributes are not allowed")
+
+ def get_attributes_for_oid(self, oid):
+ return [i for i in self if i.oid == oid]
+
+ def rfc4514_string(self):
+ """
+ Format as RFC4514 Distinguished Name string.
+
+ Within each RDN, attributes are joined by '+', although that is rarely
+ used in certificates.
+ """
+ return '+'.join(attr.rfc4514_string() for attr in self._attributes)
+
+ def __eq__(self, other):
+ if not isinstance(other, RelativeDistinguishedName):
+ return NotImplemented
+
+ return self._attribute_set == other._attribute_set
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ return hash(self._attribute_set)
+
+ def __iter__(self):
+ return iter(self._attributes)
+
+ def __len__(self):
+ return len(self._attributes)
+
+ def __repr__(self):
+ return "<RelativeDistinguishedName({})>".format(self.rfc4514_string())
+
+
+class Name(object):
+ def __init__(self, attributes):
+ attributes = list(attributes)
+ if all(isinstance(x, NameAttribute) for x in attributes):
+ self._attributes = [
+ RelativeDistinguishedName([x]) for x in attributes
+ ]
+ elif all(isinstance(x, RelativeDistinguishedName) for x in attributes):
+ self._attributes = attributes
+ else:
+ raise TypeError(
+ "attributes must be a list of NameAttribute"
+ " or a list RelativeDistinguishedName"
+ )
+
+ def rfc4514_string(self):
+ """
+ Format as RFC4514 Distinguished Name string.
+ For example 'CN=foobar.com,O=Foo Corp,C=US'
+
+ An X.509 name is a two-level structure: a list of sets of attributes.
+ Each list element is separated by ',' and within each list element, set
+ elements are separated by '+'. The latter is almost never used in
+ real world certificates. According to RFC4514 section 2.1 the
+ RDNSequence must be reversed when converting to string representation.
+ """
+ return ','.join(
+ attr.rfc4514_string() for attr in reversed(self._attributes))
+
+ def get_attributes_for_oid(self, oid):
+ return [i for i in self if i.oid == oid]
+
+ @property
+ def rdns(self):
+ return self._attributes
+
+ def public_bytes(self, backend):
+ return backend.x509_name_bytes(self)
+
+ def __eq__(self, other):
+ if not isinstance(other, Name):
+ return NotImplemented
+
+ return self._attributes == other._attributes
+
+ def __ne__(self, other):
+ return not self == other
+
+ def __hash__(self):
+ # TODO: this is relatively expensive, if this looks like a bottleneck
+ # for you, consider optimizing!
+ return hash(tuple(self._attributes))
+
+ def __iter__(self):
+ for rdn in self._attributes:
+ for ava in rdn:
+ yield ava
+
+ def __len__(self):
+ return sum(len(rdn) for rdn in self._attributes)
+
+ def __repr__(self):
+ rdns = ','.join(attr.rfc4514_string() for attr in self._attributes)
+
+ if six.PY2:
+ return "<Name({})>".format(rdns.encode('utf8'))
+ else:
+ return "<Name({})>".format(rdns)
diff --git a/src/cryptography/x509/ocsp.py b/src/cryptography/x509/ocsp.py
new file mode 100644
index 00000000..7db92b90
--- /dev/null
+++ b/src/cryptography/x509/ocsp.py
@@ -0,0 +1,425 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import abc
+import datetime
+from enum import Enum
+
+import six
+
+from cryptography import x509
+from cryptography.hazmat.primitives import hashes
+from cryptography.x509.base import (
+ _EARLIEST_UTC_TIME, _convert_to_naive_utc_time, _reject_duplicate_extension
+)
+
+
+_OIDS_TO_HASH = {
+ "1.3.14.3.2.26": hashes.SHA1(),
+ "2.16.840.1.101.3.4.2.4": hashes.SHA224(),
+ "2.16.840.1.101.3.4.2.1": hashes.SHA256(),
+ "2.16.840.1.101.3.4.2.2": hashes.SHA384(),
+ "2.16.840.1.101.3.4.2.3": hashes.SHA512(),
+}
+
+
+class OCSPResponderEncoding(Enum):
+ HASH = "By Hash"
+ NAME = "By Name"
+
+
+class OCSPResponseStatus(Enum):
+ SUCCESSFUL = 0
+ MALFORMED_REQUEST = 1
+ INTERNAL_ERROR = 2
+ TRY_LATER = 3
+ SIG_REQUIRED = 5
+ UNAUTHORIZED = 6
+
+
+_RESPONSE_STATUS_TO_ENUM = {x.value: x for x in OCSPResponseStatus}
+_ALLOWED_HASHES = (
+ hashes.SHA1, hashes.SHA224, hashes.SHA256,
+ hashes.SHA384, hashes.SHA512
+)
+
+
+def _verify_algorithm(algorithm):
+ if not isinstance(algorithm, _ALLOWED_HASHES):
+ raise ValueError(
+ "Algorithm must be SHA1, SHA224, SHA256, SHA384, or SHA512"
+ )
+
+
+class OCSPCertStatus(Enum):
+ GOOD = 0
+ REVOKED = 1
+ UNKNOWN = 2
+
+
+_CERT_STATUS_TO_ENUM = {x.value: x for x in OCSPCertStatus}
+
+
+def load_der_ocsp_request(data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ return backend.load_der_ocsp_request(data)
+
+
+def load_der_ocsp_response(data):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ return backend.load_der_ocsp_response(data)
+
+
+class OCSPRequestBuilder(object):
+ def __init__(self, request=None, extensions=[]):
+ self._request = request
+ self._extensions = extensions
+
+ def add_certificate(self, cert, issuer, algorithm):
+ if self._request is not None:
+ raise ValueError("Only one certificate can be added to a request")
+
+ _verify_algorithm(algorithm)
+ if (
+ not isinstance(cert, x509.Certificate) or
+ not isinstance(issuer, x509.Certificate)
+ ):
+ raise TypeError("cert and issuer must be a Certificate")
+
+ return OCSPRequestBuilder((cert, issuer, algorithm), self._extensions)
+
+ def add_extension(self, extension, critical):
+ if not isinstance(extension, x509.ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = x509.Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+
+ return OCSPRequestBuilder(
+ self._request, self._extensions + [extension]
+ )
+
+ def build(self):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if self._request is None:
+ raise ValueError("You must add a certificate before building")
+
+ return backend.create_ocsp_request(self)
+
+
+class _SingleResponse(object):
+ def __init__(self, cert, issuer, algorithm, cert_status, this_update,
+ next_update, revocation_time, revocation_reason):
+ if (
+ not isinstance(cert, x509.Certificate) or
+ not isinstance(issuer, x509.Certificate)
+ ):
+ raise TypeError("cert and issuer must be a Certificate")
+
+ _verify_algorithm(algorithm)
+ if not isinstance(this_update, datetime.datetime):
+ raise TypeError("this_update must be a datetime object")
+ if (
+ next_update is not None and
+ not isinstance(next_update, datetime.datetime)
+ ):
+ raise TypeError("next_update must be a datetime object or None")
+
+ self._cert = cert
+ self._issuer = issuer
+ self._algorithm = algorithm
+ self._this_update = this_update
+ self._next_update = next_update
+
+ if not isinstance(cert_status, OCSPCertStatus):
+ raise TypeError(
+ "cert_status must be an item from the OCSPCertStatus enum"
+ )
+ if cert_status is not OCSPCertStatus.REVOKED:
+ if revocation_time is not None:
+ raise ValueError(
+ "revocation_time can only be provided if the certificate "
+ "is revoked"
+ )
+ if revocation_reason is not None:
+ raise ValueError(
+ "revocation_reason can only be provided if the certificate"
+ " is revoked"
+ )
+ else:
+ if not isinstance(revocation_time, datetime.datetime):
+ raise TypeError("revocation_time must be a datetime object")
+
+ revocation_time = _convert_to_naive_utc_time(revocation_time)
+ if revocation_time < _EARLIEST_UTC_TIME:
+ raise ValueError('The revocation_time must be on or after'
+ ' 1950 January 1.')
+
+ if (
+ revocation_reason is not None and
+ not isinstance(revocation_reason, x509.ReasonFlags)
+ ):
+ raise TypeError(
+ "revocation_reason must be an item from the ReasonFlags "
+ "enum or None"
+ )
+
+ self._cert_status = cert_status
+ self._revocation_time = revocation_time
+ self._revocation_reason = revocation_reason
+
+
+class OCSPResponseBuilder(object):
+ def __init__(self, response=None, responder_id=None, certs=None,
+ extensions=[]):
+ self._response = response
+ self._responder_id = responder_id
+ self._certs = certs
+ self._extensions = extensions
+
+ def add_response(self, cert, issuer, algorithm, cert_status, this_update,
+ next_update, revocation_time, revocation_reason):
+ if self._response is not None:
+ raise ValueError("Only one response per OCSPResponse.")
+
+ singleresp = _SingleResponse(
+ cert, issuer, algorithm, cert_status, this_update, next_update,
+ revocation_time, revocation_reason
+ )
+ return OCSPResponseBuilder(
+ singleresp, self._responder_id,
+ self._certs, self._extensions,
+ )
+
+ def responder_id(self, encoding, responder_cert):
+ if self._responder_id is not None:
+ raise ValueError("responder_id can only be set once")
+ if not isinstance(responder_cert, x509.Certificate):
+ raise TypeError("responder_cert must be a Certificate")
+ if not isinstance(encoding, OCSPResponderEncoding):
+ raise TypeError(
+ "encoding must be an element from OCSPResponderEncoding"
+ )
+
+ return OCSPResponseBuilder(
+ self._response, (responder_cert, encoding),
+ self._certs, self._extensions,
+ )
+
+ def certificates(self, certs):
+ if self._certs is not None:
+ raise ValueError("certificates may only be set once")
+ certs = list(certs)
+ if len(certs) == 0:
+ raise ValueError("certs must not be an empty list")
+ if not all(isinstance(x, x509.Certificate) for x in certs):
+ raise TypeError("certs must be a list of Certificates")
+ return OCSPResponseBuilder(
+ self._response, self._responder_id,
+ certs, self._extensions,
+ )
+
+ def add_extension(self, extension, critical):
+ if not isinstance(extension, x509.ExtensionType):
+ raise TypeError("extension must be an ExtensionType")
+
+ extension = x509.Extension(extension.oid, critical, extension)
+ _reject_duplicate_extension(extension, self._extensions)
+
+ return OCSPResponseBuilder(
+ self._response, self._responder_id,
+ self._certs, self._extensions + [extension],
+ )
+
+ def sign(self, private_key, algorithm):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if self._response is None:
+ raise ValueError("You must add a response before signing")
+ if self._responder_id is None:
+ raise ValueError("You must add a responder_id before signing")
+
+ return backend.create_ocsp_response(
+ OCSPResponseStatus.SUCCESSFUL, self, private_key, algorithm
+ )
+
+ @classmethod
+ def build_unsuccessful(cls, response_status):
+ from cryptography.hazmat.backends.openssl.backend import backend
+ if not isinstance(response_status, OCSPResponseStatus):
+ raise TypeError(
+ "response_status must be an item from OCSPResponseStatus"
+ )
+ if response_status is OCSPResponseStatus.SUCCESSFUL:
+ raise ValueError("response_status cannot be SUCCESSFUL")
+
+ return backend.create_ocsp_response(response_status, None, None, None)
+
+
+@six.add_metaclass(abc.ABCMeta)
+class OCSPRequest(object):
+ @abc.abstractproperty
+ def issuer_key_hash(self):
+ """
+ The hash of the issuer public key
+ """
+
+ @abc.abstractproperty
+ def issuer_name_hash(self):
+ """
+ The hash of the issuer name
+ """
+
+ @abc.abstractproperty
+ def hash_algorithm(self):
+ """
+ The hash algorithm used in the issuer name and key hashes
+ """
+
+ @abc.abstractproperty
+ def serial_number(self):
+ """
+ The serial number of the cert whose status is being checked
+ """
+ @abc.abstractmethod
+ def public_bytes(self, encoding):
+ """
+ Serializes the request to DER
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ The list of request extensions. Not single request extensions.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
+class OCSPResponse(object):
+ @abc.abstractproperty
+ def response_status(self):
+ """
+ The status of the response. This is a value from the OCSPResponseStatus
+ enumeration
+ """
+
+ @abc.abstractproperty
+ def signature_algorithm_oid(self):
+ """
+ The ObjectIdentifier of the signature algorithm
+ """
+
+ @abc.abstractproperty
+ def signature_hash_algorithm(self):
+ """
+ Returns a HashAlgorithm corresponding to the type of the digest signed
+ """
+
+ @abc.abstractproperty
+ def signature(self):
+ """
+ The signature bytes
+ """
+
+ @abc.abstractproperty
+ def tbs_response_bytes(self):
+ """
+ The tbsResponseData bytes
+ """
+
+ @abc.abstractproperty
+ def certificates(self):
+ """
+ A list of certificates used to help build a chain to verify the OCSP
+ response. This situation occurs when the OCSP responder uses a delegate
+ certificate.
+ """
+
+ @abc.abstractproperty
+ def responder_key_hash(self):
+ """
+ The responder's key hash or None
+ """
+
+ @abc.abstractproperty
+ def responder_name(self):
+ """
+ The responder's Name or None
+ """
+
+ @abc.abstractproperty
+ def produced_at(self):
+ """
+ The time the response was produced
+ """
+
+ @abc.abstractproperty
+ def certificate_status(self):
+ """
+ The status of the certificate (an element from the OCSPCertStatus enum)
+ """
+
+ @abc.abstractproperty
+ def revocation_time(self):
+ """
+ The date of when the certificate was revoked or None if not
+ revoked.
+ """
+
+ @abc.abstractproperty
+ def revocation_reason(self):
+ """
+ The reason the certificate was revoked or None if not specified or
+ not revoked.
+ """
+
+ @abc.abstractproperty
+ def this_update(self):
+ """
+ The most recent time at which the status being indicated is known by
+ the responder to have been correct
+ """
+
+ @abc.abstractproperty
+ def next_update(self):
+ """
+ The time when newer information will be available
+ """
+
+ @abc.abstractproperty
+ def issuer_key_hash(self):
+ """
+ The hash of the issuer public key
+ """
+
+ @abc.abstractproperty
+ def issuer_name_hash(self):
+ """
+ The hash of the issuer name
+ """
+
+ @abc.abstractproperty
+ def hash_algorithm(self):
+ """
+ The hash algorithm used in the issuer name and key hashes
+ """
+
+ @abc.abstractproperty
+ def serial_number(self):
+ """
+ The serial number of the cert whose status is being checked
+ """
+
+ @abc.abstractproperty
+ def extensions(self):
+ """
+ The list of response extensions. Not single response extensions.
+ """
+
+ @abc.abstractproperty
+ def single_extensions(self):
+ """
+ The list of single response extensions. Not response extensions.
+ """
diff --git a/src/cryptography/x509/oid.py b/src/cryptography/x509/oid.py
new file mode 100644
index 00000000..284db54f
--- /dev/null
+++ b/src/cryptography/x509/oid.py
@@ -0,0 +1,257 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+from cryptography.hazmat._oid import ObjectIdentifier
+from cryptography.hazmat.primitives import hashes
+
+
+class ExtensionOID(object):
+ SUBJECT_DIRECTORY_ATTRIBUTES = ObjectIdentifier("2.5.29.9")
+ SUBJECT_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.14")
+ KEY_USAGE = ObjectIdentifier("2.5.29.15")
+ SUBJECT_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.17")
+ ISSUER_ALTERNATIVE_NAME = ObjectIdentifier("2.5.29.18")
+ BASIC_CONSTRAINTS = ObjectIdentifier("2.5.29.19")
+ NAME_CONSTRAINTS = ObjectIdentifier("2.5.29.30")
+ CRL_DISTRIBUTION_POINTS = ObjectIdentifier("2.5.29.31")
+ CERTIFICATE_POLICIES = ObjectIdentifier("2.5.29.32")
+ POLICY_MAPPINGS = ObjectIdentifier("2.5.29.33")
+ AUTHORITY_KEY_IDENTIFIER = ObjectIdentifier("2.5.29.35")
+ POLICY_CONSTRAINTS = ObjectIdentifier("2.5.29.36")
+ EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37")
+ FRESHEST_CRL = ObjectIdentifier("2.5.29.46")
+ INHIBIT_ANY_POLICY = ObjectIdentifier("2.5.29.54")
+ ISSUING_DISTRIBUTION_POINT = ObjectIdentifier("2.5.29.28")
+ AUTHORITY_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.1")
+ SUBJECT_INFORMATION_ACCESS = ObjectIdentifier("1.3.6.1.5.5.7.1.11")
+ OCSP_NO_CHECK = ObjectIdentifier("1.3.6.1.5.5.7.48.1.5")
+ TLS_FEATURE = ObjectIdentifier("1.3.6.1.5.5.7.1.24")
+ CRL_NUMBER = ObjectIdentifier("2.5.29.20")
+ DELTA_CRL_INDICATOR = ObjectIdentifier("2.5.29.27")
+ PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS = (
+ ObjectIdentifier("1.3.6.1.4.1.11129.2.4.2")
+ )
+ PRECERT_POISON = (
+ ObjectIdentifier("1.3.6.1.4.1.11129.2.4.3")
+ )
+
+
+class OCSPExtensionOID(object):
+ NONCE = ObjectIdentifier("1.3.6.1.5.5.7.48.1.2")
+
+
+class CRLEntryExtensionOID(object):
+ CERTIFICATE_ISSUER = ObjectIdentifier("2.5.29.29")
+ CRL_REASON = ObjectIdentifier("2.5.29.21")
+ INVALIDITY_DATE = ObjectIdentifier("2.5.29.24")
+
+
+class NameOID(object):
+ COMMON_NAME = ObjectIdentifier("2.5.4.3")
+ COUNTRY_NAME = ObjectIdentifier("2.5.4.6")
+ LOCALITY_NAME = ObjectIdentifier("2.5.4.7")
+ STATE_OR_PROVINCE_NAME = ObjectIdentifier("2.5.4.8")
+ STREET_ADDRESS = ObjectIdentifier("2.5.4.9")
+ ORGANIZATION_NAME = ObjectIdentifier("2.5.4.10")
+ ORGANIZATIONAL_UNIT_NAME = ObjectIdentifier("2.5.4.11")
+ SERIAL_NUMBER = ObjectIdentifier("2.5.4.5")
+ SURNAME = ObjectIdentifier("2.5.4.4")
+ GIVEN_NAME = ObjectIdentifier("2.5.4.42")
+ TITLE = ObjectIdentifier("2.5.4.12")
+ GENERATION_QUALIFIER = ObjectIdentifier("2.5.4.44")
+ X500_UNIQUE_IDENTIFIER = ObjectIdentifier("2.5.4.45")
+ DN_QUALIFIER = ObjectIdentifier("2.5.4.46")
+ PSEUDONYM = ObjectIdentifier("2.5.4.65")
+ USER_ID = ObjectIdentifier("0.9.2342.19200300.100.1.1")
+ DOMAIN_COMPONENT = ObjectIdentifier("0.9.2342.19200300.100.1.25")
+ EMAIL_ADDRESS = ObjectIdentifier("1.2.840.113549.1.9.1")
+ JURISDICTION_COUNTRY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.3")
+ JURISDICTION_LOCALITY_NAME = ObjectIdentifier("1.3.6.1.4.1.311.60.2.1.1")
+ JURISDICTION_STATE_OR_PROVINCE_NAME = ObjectIdentifier(
+ "1.3.6.1.4.1.311.60.2.1.2"
+ )
+ BUSINESS_CATEGORY = ObjectIdentifier("2.5.4.15")
+ POSTAL_ADDRESS = ObjectIdentifier("2.5.4.16")
+ POSTAL_CODE = ObjectIdentifier("2.5.4.17")
+ INN = ObjectIdentifier("1.2.643.3.131.1.1")
+ OGRN = ObjectIdentifier("1.2.643.100.1")
+ SNILS = ObjectIdentifier("1.2.643.100.3")
+
+
+class SignatureAlgorithmOID(object):
+ RSA_WITH_MD5 = ObjectIdentifier("1.2.840.113549.1.1.4")
+ RSA_WITH_SHA1 = ObjectIdentifier("1.2.840.113549.1.1.5")
+ # This is an alternate OID for RSA with SHA1 that is occasionally seen
+ _RSA_WITH_SHA1 = ObjectIdentifier("1.3.14.3.2.29")
+ RSA_WITH_SHA224 = ObjectIdentifier("1.2.840.113549.1.1.14")
+ RSA_WITH_SHA256 = ObjectIdentifier("1.2.840.113549.1.1.11")
+ RSA_WITH_SHA384 = ObjectIdentifier("1.2.840.113549.1.1.12")
+ RSA_WITH_SHA512 = ObjectIdentifier("1.2.840.113549.1.1.13")
+ RSASSA_PSS = ObjectIdentifier("1.2.840.113549.1.1.10")
+ ECDSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10045.4.1")
+ ECDSA_WITH_SHA224 = ObjectIdentifier("1.2.840.10045.4.3.1")
+ ECDSA_WITH_SHA256 = ObjectIdentifier("1.2.840.10045.4.3.2")
+ ECDSA_WITH_SHA384 = ObjectIdentifier("1.2.840.10045.4.3.3")
+ ECDSA_WITH_SHA512 = ObjectIdentifier("1.2.840.10045.4.3.4")
+ DSA_WITH_SHA1 = ObjectIdentifier("1.2.840.10040.4.3")
+ DSA_WITH_SHA224 = ObjectIdentifier("2.16.840.1.101.3.4.3.1")
+ DSA_WITH_SHA256 = ObjectIdentifier("2.16.840.1.101.3.4.3.2")
+ ED25519 = ObjectIdentifier("1.3.101.112")
+ ED448 = ObjectIdentifier("1.3.101.113")
+ GOSTR3411_94_WITH_3410_2001 = ObjectIdentifier("1.2.643.2.2.3")
+ GOSTR3410_2012_WITH_3411_2012_256 = ObjectIdentifier(
+ "1.2.643.7.1.1.3.2"
+ )
+ GOSTR3410_2012_WITH_3411_2012_512 = ObjectIdentifier(
+ "1.2.643.7.1.1.3.3"
+ )
+
+
+_SIG_OIDS_TO_HASH = {
+ SignatureAlgorithmOID.RSA_WITH_MD5: hashes.MD5(),
+ SignatureAlgorithmOID.RSA_WITH_SHA1: hashes.SHA1(),
+ SignatureAlgorithmOID._RSA_WITH_SHA1: hashes.SHA1(),
+ SignatureAlgorithmOID.RSA_WITH_SHA224: hashes.SHA224(),
+ SignatureAlgorithmOID.RSA_WITH_SHA256: hashes.SHA256(),
+ SignatureAlgorithmOID.RSA_WITH_SHA384: hashes.SHA384(),
+ SignatureAlgorithmOID.RSA_WITH_SHA512: hashes.SHA512(),
+ SignatureAlgorithmOID.ECDSA_WITH_SHA1: hashes.SHA1(),
+ SignatureAlgorithmOID.ECDSA_WITH_SHA224: hashes.SHA224(),
+ SignatureAlgorithmOID.ECDSA_WITH_SHA256: hashes.SHA256(),
+ SignatureAlgorithmOID.ECDSA_WITH_SHA384: hashes.SHA384(),
+ SignatureAlgorithmOID.ECDSA_WITH_SHA512: hashes.SHA512(),
+ SignatureAlgorithmOID.DSA_WITH_SHA1: hashes.SHA1(),
+ SignatureAlgorithmOID.DSA_WITH_SHA224: hashes.SHA224(),
+ SignatureAlgorithmOID.DSA_WITH_SHA256: hashes.SHA256(),
+ SignatureAlgorithmOID.ED25519: None,
+ SignatureAlgorithmOID.ED448: None,
+ SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: None,
+ SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: None,
+ SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: None,
+}
+
+
+class ExtendedKeyUsageOID(object):
+ SERVER_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.1")
+ CLIENT_AUTH = ObjectIdentifier("1.3.6.1.5.5.7.3.2")
+ CODE_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.3")
+ EMAIL_PROTECTION = ObjectIdentifier("1.3.6.1.5.5.7.3.4")
+ TIME_STAMPING = ObjectIdentifier("1.3.6.1.5.5.7.3.8")
+ OCSP_SIGNING = ObjectIdentifier("1.3.6.1.5.5.7.3.9")
+ ANY_EXTENDED_KEY_USAGE = ObjectIdentifier("2.5.29.37.0")
+
+
+class AuthorityInformationAccessOID(object):
+ CA_ISSUERS = ObjectIdentifier("1.3.6.1.5.5.7.48.2")
+ OCSP = ObjectIdentifier("1.3.6.1.5.5.7.48.1")
+
+
+class CertificatePoliciesOID(object):
+ CPS_QUALIFIER = ObjectIdentifier("1.3.6.1.5.5.7.2.1")
+ CPS_USER_NOTICE = ObjectIdentifier("1.3.6.1.5.5.7.2.2")
+ ANY_POLICY = ObjectIdentifier("2.5.29.32.0")
+
+
+_OID_NAMES = {
+ NameOID.COMMON_NAME: "commonName",
+ NameOID.COUNTRY_NAME: "countryName",
+ NameOID.LOCALITY_NAME: "localityName",
+ NameOID.STATE_OR_PROVINCE_NAME: "stateOrProvinceName",
+ NameOID.STREET_ADDRESS: "streetAddress",
+ NameOID.ORGANIZATION_NAME: "organizationName",
+ NameOID.ORGANIZATIONAL_UNIT_NAME: "organizationalUnitName",
+ NameOID.SERIAL_NUMBER: "serialNumber",
+ NameOID.SURNAME: "surname",
+ NameOID.GIVEN_NAME: "givenName",
+ NameOID.TITLE: "title",
+ NameOID.GENERATION_QUALIFIER: "generationQualifier",
+ NameOID.X500_UNIQUE_IDENTIFIER: "x500UniqueIdentifier",
+ NameOID.DN_QUALIFIER: "dnQualifier",
+ NameOID.PSEUDONYM: "pseudonym",
+ NameOID.USER_ID: "userID",
+ NameOID.DOMAIN_COMPONENT: "domainComponent",
+ NameOID.EMAIL_ADDRESS: "emailAddress",
+ NameOID.JURISDICTION_COUNTRY_NAME: "jurisdictionCountryName",
+ NameOID.JURISDICTION_LOCALITY_NAME: "jurisdictionLocalityName",
+ NameOID.JURISDICTION_STATE_OR_PROVINCE_NAME: (
+ "jurisdictionStateOrProvinceName"
+ ),
+ NameOID.BUSINESS_CATEGORY: "businessCategory",
+ NameOID.POSTAL_ADDRESS: "postalAddress",
+ NameOID.POSTAL_CODE: "postalCode",
+ NameOID.INN: "INN",
+ NameOID.OGRN: "OGRN",
+ NameOID.SNILS: "SNILS",
+
+ SignatureAlgorithmOID.RSA_WITH_MD5: "md5WithRSAEncryption",
+ SignatureAlgorithmOID.RSA_WITH_SHA1: "sha1WithRSAEncryption",
+ SignatureAlgorithmOID.RSA_WITH_SHA224: "sha224WithRSAEncryption",
+ SignatureAlgorithmOID.RSA_WITH_SHA256: "sha256WithRSAEncryption",
+ SignatureAlgorithmOID.RSA_WITH_SHA384: "sha384WithRSAEncryption",
+ SignatureAlgorithmOID.RSA_WITH_SHA512: "sha512WithRSAEncryption",
+ SignatureAlgorithmOID.RSASSA_PSS: "RSASSA-PSS",
+ SignatureAlgorithmOID.ECDSA_WITH_SHA1: "ecdsa-with-SHA1",
+ SignatureAlgorithmOID.ECDSA_WITH_SHA224: "ecdsa-with-SHA224",
+ SignatureAlgorithmOID.ECDSA_WITH_SHA256: "ecdsa-with-SHA256",
+ SignatureAlgorithmOID.ECDSA_WITH_SHA384: "ecdsa-with-SHA384",
+ SignatureAlgorithmOID.ECDSA_WITH_SHA512: "ecdsa-with-SHA512",
+ SignatureAlgorithmOID.DSA_WITH_SHA1: "dsa-with-sha1",
+ SignatureAlgorithmOID.DSA_WITH_SHA224: "dsa-with-sha224",
+ SignatureAlgorithmOID.DSA_WITH_SHA256: "dsa-with-sha256",
+ SignatureAlgorithmOID.ED25519: "ed25519",
+ SignatureAlgorithmOID.ED448: "ed448",
+ SignatureAlgorithmOID.GOSTR3411_94_WITH_3410_2001: (
+ "GOST R 34.11-94 with GOST R 34.10-2001"
+ ),
+ SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_256: (
+ "GOST R 34.10-2012 with GOST R 34.11-2012 (256 bit)"
+ ),
+ SignatureAlgorithmOID.GOSTR3410_2012_WITH_3411_2012_512: (
+ "GOST R 34.10-2012 with GOST R 34.11-2012 (512 bit)"
+ ),
+ ExtendedKeyUsageOID.SERVER_AUTH: "serverAuth",
+ ExtendedKeyUsageOID.CLIENT_AUTH: "clientAuth",
+ ExtendedKeyUsageOID.CODE_SIGNING: "codeSigning",
+ ExtendedKeyUsageOID.EMAIL_PROTECTION: "emailProtection",
+ ExtendedKeyUsageOID.TIME_STAMPING: "timeStamping",
+ ExtendedKeyUsageOID.OCSP_SIGNING: "OCSPSigning",
+ ExtensionOID.SUBJECT_DIRECTORY_ATTRIBUTES: "subjectDirectoryAttributes",
+ ExtensionOID.SUBJECT_KEY_IDENTIFIER: "subjectKeyIdentifier",
+ ExtensionOID.KEY_USAGE: "keyUsage",
+ ExtensionOID.SUBJECT_ALTERNATIVE_NAME: "subjectAltName",
+ ExtensionOID.ISSUER_ALTERNATIVE_NAME: "issuerAltName",
+ ExtensionOID.BASIC_CONSTRAINTS: "basicConstraints",
+ ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: (
+ "signedCertificateTimestampList"
+ ),
+ ExtensionOID.PRECERT_POISON: "ctPoison",
+ CRLEntryExtensionOID.CRL_REASON: "cRLReason",
+ CRLEntryExtensionOID.INVALIDITY_DATE: "invalidityDate",
+ CRLEntryExtensionOID.CERTIFICATE_ISSUER: "certificateIssuer",
+ ExtensionOID.NAME_CONSTRAINTS: "nameConstraints",
+ ExtensionOID.CRL_DISTRIBUTION_POINTS: "cRLDistributionPoints",
+ ExtensionOID.CERTIFICATE_POLICIES: "certificatePolicies",
+ ExtensionOID.POLICY_MAPPINGS: "policyMappings",
+ ExtensionOID.AUTHORITY_KEY_IDENTIFIER: "authorityKeyIdentifier",
+ ExtensionOID.POLICY_CONSTRAINTS: "policyConstraints",
+ ExtensionOID.EXTENDED_KEY_USAGE: "extendedKeyUsage",
+ ExtensionOID.FRESHEST_CRL: "freshestCRL",
+ ExtensionOID.INHIBIT_ANY_POLICY: "inhibitAnyPolicy",
+ ExtensionOID.ISSUING_DISTRIBUTION_POINT: (
+ "issuingDistributionPoint"
+ ),
+ ExtensionOID.AUTHORITY_INFORMATION_ACCESS: "authorityInfoAccess",
+ ExtensionOID.SUBJECT_INFORMATION_ACCESS: "subjectInfoAccess",
+ ExtensionOID.OCSP_NO_CHECK: "OCSPNoCheck",
+ ExtensionOID.CRL_NUMBER: "cRLNumber",
+ ExtensionOID.DELTA_CRL_INDICATOR: "deltaCRLIndicator",
+ ExtensionOID.TLS_FEATURE: "TLSFeature",
+ AuthorityInformationAccessOID.OCSP: "OCSP",
+ AuthorityInformationAccessOID.CA_ISSUERS: "caIssuers",
+ CertificatePoliciesOID.CPS_QUALIFIER: "id-qt-cps",
+ CertificatePoliciesOID.CPS_USER_NOTICE: "id-qt-unotice",
+ OCSPExtensionOID.NONCE: "OCSPNonce",
+}