-
Notifications
You must be signed in to change notification settings - Fork 11
diff review of cryptography update from 2.6.1 to 3.2.1
rmol edited this page Nov 3, 2020
·
1 revision
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA256
Comparing cryptography-2.6.1-cp34-abi3-manylinux1_x86_64.whl & cryptography-3.2.1-cp35-abi3-manylinux2010_x86_64.whl
45a4f4cf4f4e6a55c8128f8b76b4c057027b27d4c67e3fe157fa02f27e37830d cryptography-2.6.1-cp34-abi3-manylinux1_x86_64.whl
32434673d8505b42c0de4de86da8c1620651abd24afe91ae0335597683ed1b77 cryptography-3.2.1-cp35-abi3-manylinux2010_x86_64.whl
@@ -1,89 +1,96 @@
-Zip file size: 2267787 bytes, number of entries: 87
--rw-r--r-- 2.0 unx 46 b- defN 19-Feb-27 23:31 cryptography-2.6.1.dist-info/top_level.txt
--rw-r--r-- 2.0 unx 8709 b- defN 19-Feb-27 23:32 cryptography-2.6.1.dist-info/RECORD
--rw-r--r-- 2.0 unx 108 b- defN 19-Feb-27 23:32 cryptography-2.6.1.dist-info/WHEEL
--rw-r--r-- 2.0 unx 5086 b- defN 19-Feb-27 23:32 cryptography-2.6.1.dist-info/METADATA
--rw-r--r-- 2.0 unx 816 b- defN 19-Feb-27 23:27 cryptography/__about__.py
--rw-r--r-- 2.0 unx 5220 b- defN 19-Feb-27 23:27 cryptography/fernet.py
--rw-r--r-- 2.0 unx 4962 b- defN 19-Feb-27 23:27 cryptography/utils.py
--rw-r--r-- 2.0 unx 527 b- defN 19-Feb-27 23:27 cryptography/__init__.py
--rw-r--r-- 2.0 unx 1234 b- defN 19-Feb-27 23:27 cryptography/exceptions.py
--rw-r--r-- 2.0 unx 2178 b- defN 19-Feb-27 23:27 cryptography/hazmat/_oid.py
--rw-r--r-- 2.0 unx 483 b- defN 19-Feb-27 23:27 cryptography/hazmat/__init__.py
--rw-r--r-- 2.0 unx 496 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/__init__.py
--rw-r--r-- 2.0 unx 10789 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/interfaces.py
--rw-r--r-- 2.0 unx 10228 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/dsa.py
--rw-r--r-- 2.0 unx 5679 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/aead.py
--rw-r--r-- 2.0 unx 18021 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/rsa.py
--rw-r--r-- 2.0 unx 32758 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/decode_asn1.py
--rw-r--r-- 2.0 unx 6043 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/ed448.py
--rw-r--r-- 2.0 unx 13654 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/ocsp.py
--rw-r--r-- 2.0 unx 5578 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/x25519.py
--rw-r--r-- 2.0 unx 20097 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/x509.py
--rw-r--r-- 2.0 unx 3196 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/hashes.py
--rw-r--r-- 2.0 unx 94525 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/backend.py
--rw-r--r-- 2.0 unx 6079 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/ed25519.py
--rw-r--r-- 2.0 unx 2902 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/cmac.py
--rw-r--r-- 2.0 unx 10814 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/dh.py
--rw-r--r-- 2.0 unx 2339 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/utils.py
--rw-r--r-- 2.0 unx 336 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/__init__.py
--rw-r--r-- 2.0 unx 4524 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/x448.py
--rw-r--r-- 2.0 unx 23412 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/encode_asn1.py
--rw-r--r-- 2.0 unx 12158 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/ec.py
--rw-r--r-- 2.0 unx 3045 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/hmac.py
--rw-r--r-- 2.0 unx 9314 b- defN 19-Feb-27 23:27 cryptography/hazmat/backends/openssl/ciphers.py
--rwxr-xr-x 2.0 unx 23127 b- defN 19-Feb-27 23:32 cryptography/hazmat/bindings/_padding.abi3.so
--rwxr-xr-x 2.0 unx 21048 b- defN 19-Feb-27 23:32 cryptography/hazmat/bindings/_constant_time.abi3.so
--rwxr-xr-x 2.0 unx 5703926 b- defN 19-Feb-27 23:32 cryptography/hazmat/bindings/_openssl.abi3.so
--rw-r--r-- 2.0 unx 246 b- defN 19-Feb-27 23:27 cryptography/hazmat/bindings/__init__.py
--rw-r--r-- 2.0 unx 7120 b- defN 19-Feb-27 23:27 cryptography/hazmat/bindings/openssl/binding.py
--rw-r--r-- 2.0 unx 10899 b- defN 19-Feb-27 23:27 cryptography/hazmat/bindings/openssl/_conditional.py
--rw-r--r-- 2.0 unx 246 b- defN 19-Feb-27 23:27 cryptography/hazmat/bindings/openssl/__init__.py
--rw-r--r-- 2.0 unx 6206 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/hashes.py
--rw-r--r-- 2.0 unx 1136 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/constant_time.py
--rw-r--r-- 2.0 unx 2122 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/cmac.py
--rw-r--r-- 2.0 unx 5644 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/padding.py
--rw-r--r-- 2.0 unx 246 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/__init__.py
--rw-r--r-- 2.0 unx 2243 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/hmac.py
--rw-r--r-- 2.0 unx 5462 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/keywrap.py
--rw-r--r-- 2.0 unx 884 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/mac.py
--rw-r--r-- 2.0 unx 3463 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/hkdf.py
--rw-r--r-- 2.0 unx 4905 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/kbkdf.py
--rw-r--r-- 2.0 unx 2280 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/x963kdf.py
--rw-r--r-- 2.0 unx 771 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/__init__.py
--rw-r--r-- 2.0 unx 3981 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/concatkdf.py
--rw-r--r-- 2.0 unx 2088 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/pbkdf2.py
--rw-r--r-- 2.0 unx 2155 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/kdf/scrypt.py
--rw-r--r-- 2.0 unx 6437 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/ciphers/aead.py
--rw-r--r-- 2.0 unx 4190 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/ciphers/algorithms.py
--rw-r--r-- 2.0 unx 7144 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/ciphers/base.py
--rw-r--r-- 2.0 unx 6641 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/ciphers/modes.py
--rw-r--r-- 2.0 unx 626 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/ciphers/__init__.py
--rw-r--r-- 2.0 unx 377 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/serialization/pkcs12.py
--rw-r--r-- 2.0 unx 1904 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/serialization/base.py
--rw-r--r-- 2.0 unx 1046 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/serialization/__init__.py
--rw-r--r-- 2.0 unx 4381 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/serialization/ssh.py
--rw-r--r-- 2.0 unx 954 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/twofactor/utils.py
--rw-r--r-- 2.0 unx 2589 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/twofactor/hotp.py
--rw-r--r-- 2.0 unx 1594 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/twofactor/totp.py
--rw-r--r-- 2.0 unx 288 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/twofactor/__init__.py
--rw-r--r-- 2.0 unx 6891 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/dsa.py
--rw-r--r-- 2.0 unx 10317 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/rsa.py
--rw-r--r-- 2.0 unx 2322 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/ed448.py
--rw-r--r-- 2.0 unx 2281 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/x25519.py
--rw-r--r-- 2.0 unx 2395 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/ed25519.py
--rw-r--r-- 2.0 unx 5454 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/dh.py
--rw-r--r-- 2.0 unx 1101 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/utils.py
--rw-r--r-- 2.0 unx 2261 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/padding.py
--rw-r--r-- 2.0 unx 1020 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/__init__.py
--rw-r--r-- 2.0 unx 2249 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/x448.py
--rw-r--r-- 2.0 unx 13758 b- defN 19-Feb-27 23:27 cryptography/hazmat/primitives/asymmetric/ec.py
--rw-r--r-- 2.0 unx 1000 b- defN 19-Feb-27 23:27 cryptography/x509/certificate_transparency.py
--rw-r--r-- 2.0 unx 12960 b- defN 19-Feb-27 23:27 cryptography/x509/ocsp.py
--rw-r--r-- 2.0 unx 49959 b- defN 19-Feb-27 23:27 cryptography/x509/extensions.py
--rw-r--r-- 2.0 unx 23739 b- defN 19-Feb-27 23:27 cryptography/x509/base.py
--rw-r--r-- 2.0 unx 8016 b- defN 19-Feb-27 23:27 cryptography/x509/name.py
--rw-r--r-- 2.0 unx 10462 b- defN 19-Feb-27 23:27 cryptography/x509/general_name.py
--rw-r--r-- 2.0 unx 10632 b- defN 19-Feb-27 23:27 cryptography/x509/oid.py
--rw-r--r-- 2.0 unx 7305 b- defN 19-Feb-27 23:27 cryptography/x509/__init__.py
-87 files, 6347847 bytes uncompressed, 2253731 bytes compressed: 64.5%
+Zip file size: 2606314 bytes, number of entries: 94
+-rw-r--r-- 2.0 unx 2475 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/AUTHORS.rst
+-rw-rw-r-- 2.0 unx 9397 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/RECORD
+-rw-r--r-- 2.0 unx 5176 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/METADATA
+-rw-r--r-- 2.0 unx 2415 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/LICENSE.PSF
+-rw-r--r-- 2.0 unx 31 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/top_level.txt
+-rw-r--r-- 2.0 unx 111 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/WHEEL
+-rw-r--r-- 2.0 unx 11360 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/LICENSE.APACHE
+-rw-r--r-- 2.0 unx 1532 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/LICENSE.BSD
+-rw-r--r-- 2.0 unx 352 b- defN 20-Oct-28 03:21 cryptography-3.2.1.dist-info/LICENSE
+-rw-r--r-- 2.0 unx 5980 b- defN 20-Oct-28 03:11 cryptography/fernet.py
+-rw-r--r-- 2.0 unx 1208 b- defN 20-Oct-28 03:11 cryptography/__init__.py
+-rw-r--r-- 2.0 unx 835 b- defN 20-Oct-28 03:11 cryptography/__about__.py
+-rw-r--r-- 2.0 unx 4745 b- defN 20-Oct-28 03:11 cryptography/utils.py
+-rw-r--r-- 2.0 unx 1259 b- defN 20-Oct-28 03:11 cryptography/exceptions.py
+-rw-r--r-- 2.0 unx 5205 b- defN 20-Oct-28 03:11 cryptography/hazmat/_der.py
+-rw-r--r-- 2.0 unx 483 b- defN 20-Oct-28 03:11 cryptography/hazmat/__init__.py
+-rw-r--r-- 2.0 unx 2432 b- defN 20-Oct-28 03:11 cryptography/hazmat/_oid.py
+-rw-r--r-- 2.0 unx 616 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/__init__.py
+-rw-r--r-- 2.0 unx 10770 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/interfaces.py
+-rw-r--r-- 2.0 unx 3015 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/hmac.py
+-rw-r--r-- 2.0 unx 3169 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/hashes.py
+-rw-r--r-- 2.0 unx 4011 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/x448.py
+-rw-r--r-- 2.0 unx 10239 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/dh.py
+-rw-r--r-- 2.0 unx 4488 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/x25519.py
+-rw-r--r-- 2.0 unx 5626 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/ed448.py
+-rw-r--r-- 2.0 unx 336 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/__init__.py
+-rw-r--r-- 2.0 unx 10036 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/dsa.py
+-rw-r--r-- 2.0 unx 23553 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/encode_asn1.py
+-rw-r--r-- 2.0 unx 8608 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/ciphers.py
+-rw-r--r-- 2.0 unx 106907 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/backend.py
+-rw-r--r-- 2.0 unx 17378 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/rsa.py
+-rw-r--r-- 2.0 unx 14028 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/ocsp.py
+-rw-r--r-- 2.0 unx 32345 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/decode_asn1.py
+-rw-r--r-- 2.0 unx 5765 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/aead.py
+-rw-r--r-- 2.0 unx 5670 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/ed25519.py
+-rw-r--r-- 2.0 unx 2419 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/poly1305.py
+-rw-r--r-- 2.0 unx 2304 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/utils.py
+-rw-r--r-- 2.0 unx 21620 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/x509.py
+-rw-r--r-- 2.0 unx 2855 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/cmac.py
+-rw-r--r-- 2.0 unx 12085 b- defN 20-Oct-28 03:11 cryptography/hazmat/backends/openssl/ec.py
+-rwxr-xr-x 2.0 unx 37232 b- defN 20-Oct-28 03:21 cryptography/hazmat/bindings/_padding.abi3.so
+-rw-r--r-- 2.0 unx 246 b- defN 20-Oct-28 03:11 cryptography/hazmat/bindings/__init__.py
+-rwxr-xr-x 2.0 unx 7050912 b- defN 20-Oct-28 03:21 cryptography/hazmat/bindings/_openssl.abi3.so
+-rw-r--r-- 2.0 unx 246 b- defN 20-Oct-28 03:11 cryptography/hazmat/bindings/openssl/__init__.py
+-rw-r--r-- 2.0 unx 7947 b- defN 20-Oct-28 03:11 cryptography/hazmat/bindings/openssl/binding.py
+-rw-r--r-- 2.0 unx 8762 b- defN 20-Oct-28 03:11 cryptography/hazmat/bindings/openssl/_conditional.py
+-rw-r--r-- 2.0 unx 2306 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/hmac.py
+-rw-r--r-- 2.0 unx 6315 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/hashes.py
+-rw-r--r-- 2.0 unx 430 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/constant_time.py
+-rw-r--r-- 2.0 unx 246 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/__init__.py
+-rw-r--r-- 2.0 unx 5730 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/keywrap.py
+-rw-r--r-- 2.0 unx 5743 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/padding.py
+-rw-r--r-- 2.0 unx 1679 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/poly1305.py
+-rw-r--r-- 2.0 unx 2130 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/cmac.py
+-rw-r--r-- 2.0 unx 4625 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/serialization/pkcs7.py
+-rw-r--r-- 2.0 unx 2249 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/serialization/base.py
+-rw-r--r-- 2.0 unx 1132 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/serialization/__init__.py
+-rw-r--r-- 2.0 unx 1853 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/serialization/pkcs12.py
+-rw-r--r-- 2.0 unx 21682 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/serialization/ssh.py
+-rw-r--r-- 2.0 unx 288 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/twofactor/__init__.py
+-rw-r--r-- 2.0 unx 1780 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/twofactor/totp.py
+-rw-r--r-- 2.0 unx 982 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/twofactor/utils.py
+-rw-r--r-- 2.0 unx 2679 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/twofactor/hotp.py
+-rw-r--r-- 2.0 unx 7253 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/ciphers/base.py
+-rw-r--r-- 2.0 unx 647 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/ciphers/__init__.py
+-rw-r--r-- 2.0 unx 6107 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/ciphers/aead.py
+-rw-r--r-- 2.0 unx 4225 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/ciphers/algorithms.py
+-rw-r--r-- 2.0 unx 6730 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/ciphers/modes.py
+-rw-r--r-- 2.0 unx 2255 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/x448.py
+-rw-r--r-- 2.0 unx 5661 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/dh.py
+-rw-r--r-- 2.0 unx 2277 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/x25519.py
+-rw-r--r-- 2.0 unx 2328 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/ed448.py
+-rw-r--r-- 2.0 unx 1020 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/__init__.py
+-rw-r--r-- 2.0 unx 7181 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/dsa.py
+-rw-r--r-- 2.0 unx 10494 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/rsa.py
+-rw-r--r-- 2.0 unx 2401 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/ed25519.py
+-rw-r--r-- 2.0 unx 2250 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/padding.py
+-rw-r--r-- 2.0 unx 1201 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/utils.py
+-rw-r--r-- 2.0 unx 14006 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/asymmetric/ec.py
+-rw-r--r-- 2.0 unx 771 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/__init__.py
+-rw-r--r-- 2.0 unx 2407 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/x963kdf.py
+-rw-r--r-- 2.0 unx 4095 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/concatkdf.py
+-rw-r--r-- 2.0 unx 3598 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/hkdf.py
+-rw-r--r-- 2.0 unx 2220 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/pbkdf2.py
+-rw-r--r-- 2.0 unx 2268 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/scrypt.py
+-rw-r--r-- 2.0 unx 5100 b- defN 20-Oct-28 03:11 cryptography/hazmat/primitives/kdf/kbkdf.py
+-rw-r--r-- 2.0 unx 12594 b- defN 20-Oct-28 03:11 cryptography/x509/oid.py
+-rw-r--r-- 2.0 unx 52924 b- defN 20-Oct-28 03:11 cryptography/x509/extensions.py
+-rw-r--r-- 2.0 unx 26409 b- defN 20-Oct-28 03:11 cryptography/x509/base.py
+-rw-r--r-- 2.0 unx 7699 b- defN 20-Oct-28 03:11 cryptography/x509/__init__.py
+-rw-r--r-- 2.0 unx 8291 b- defN 20-Oct-28 03:11 cryptography/x509/name.py
+-rw-r--r-- 2.0 unx 1000 b- defN 20-Oct-28 03:11 cryptography/x509/certificate_transparency.py
+-rw-r--r-- 2.0 unx 13245 b- defN 20-Oct-28 03:11 cryptography/x509/ocsp.py
+-rw-r--r-- 2.0 unx 7942 b- defN 20-Oct-28 03:11 cryptography/x509/general_name.py
+94 files, 7756632 bytes uncompressed, 2591164 bytes compressed: 66.6%
@@ -1,262 +1,283 @@
-Filename: cryptography-2.6.1.dist-info/top_level.txt
+Filename: cryptography-3.2.1.dist-info/AUTHORS.rst
Comment:
-Filename: cryptography-2.6.1.dist-info/RECORD
+Filename: cryptography-3.2.1.dist-info/RECORD
Comment:
-Filename: cryptography-2.6.1.dist-info/WHEEL
+Filename: cryptography-3.2.1.dist-info/METADATA
Comment:
-Filename: cryptography-2.6.1.dist-info/METADATA
+Filename: cryptography-3.2.1.dist-info/LICENSE.PSF
Comment:
-Filename: cryptography/__about__.py
+Filename: cryptography-3.2.1.dist-info/top_level.txt
Comment:
-Filename: cryptography/fernet.py
+Filename: cryptography-3.2.1.dist-info/WHEEL
Comment:
-Filename: cryptography/utils.py
+Filename: cryptography-3.2.1.dist-info/LICENSE.APACHE
+Comment:
+
+Filename: cryptography-3.2.1.dist-info/LICENSE.BSD
+Comment:
+
+Filename: cryptography-3.2.1.dist-info/LICENSE
+Comment:
+
+Filename: cryptography/fernet.py
Comment:
Filename: cryptography/__init__.py
Comment:
+Filename: cryptography/__about__.py
+Comment:
+
+Filename: cryptography/utils.py
+Comment:
+
Filename: cryptography/exceptions.py
Comment:
-Filename: cryptography/hazmat/_oid.py
+Filename: cryptography/hazmat/_der.py
Comment:
Filename: cryptography/hazmat/__init__.py
Comment:
+Filename: cryptography/hazmat/_oid.py
+Comment:
+
Filename: cryptography/hazmat/backends/__init__.py
Comment:
Filename: cryptography/hazmat/backends/interfaces.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/dsa.py
+Filename: cryptography/hazmat/backends/openssl/hmac.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/aead.py
+Filename: cryptography/hazmat/backends/openssl/hashes.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/rsa.py
+Filename: cryptography/hazmat/backends/openssl/x448.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/decode_asn1.py
+Filename: cryptography/hazmat/backends/openssl/dh.py
+Comment:
+
+Filename: cryptography/hazmat/backends/openssl/x25519.py
Comment:
Filename: cryptography/hazmat/backends/openssl/ed448.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/ocsp.py
+Filename: cryptography/hazmat/backends/openssl/__init__.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/x25519.py
+Filename: cryptography/hazmat/backends/openssl/dsa.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/x509.py
+Filename: cryptography/hazmat/backends/openssl/encode_asn1.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/hashes.py
+Filename: cryptography/hazmat/backends/openssl/ciphers.py
Comment:
Filename: cryptography/hazmat/backends/openssl/backend.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/ed25519.py
+Filename: cryptography/hazmat/backends/openssl/rsa.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/cmac.py
+Filename: cryptography/hazmat/backends/openssl/ocsp.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/dh.py
+Filename: cryptography/hazmat/backends/openssl/decode_asn1.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/utils.py
+Filename: cryptography/hazmat/backends/openssl/aead.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/__init__.py
+Filename: cryptography/hazmat/backends/openssl/ed25519.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/x448.py
+Filename: cryptography/hazmat/backends/openssl/poly1305.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/encode_asn1.py
+Filename: cryptography/hazmat/backends/openssl/utils.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/ec.py
+Filename: cryptography/hazmat/backends/openssl/x509.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/hmac.py
+Filename: cryptography/hazmat/backends/openssl/cmac.py
Comment:
-Filename: cryptography/hazmat/backends/openssl/ciphers.py
+Filename: cryptography/hazmat/backends/openssl/ec.py
Comment:
Filename: cryptography/hazmat/bindings/_padding.abi3.so
Comment:
-Filename: cryptography/hazmat/bindings/_constant_time.abi3.so
+Filename: cryptography/hazmat/bindings/__init__.py
Comment:
Filename: cryptography/hazmat/bindings/_openssl.abi3.so
Comment:
-Filename: cryptography/hazmat/bindings/__init__.py
+Filename: cryptography/hazmat/bindings/openssl/__init__.py
Comment:
Filename: cryptography/hazmat/bindings/openssl/binding.py
Comment:
Filename: cryptography/hazmat/bindings/openssl/_conditional.py
Comment:
-Filename: cryptography/hazmat/bindings/openssl/__init__.py
+Filename: cryptography/hazmat/primitives/hmac.py
Comment:
Filename: cryptography/hazmat/primitives/hashes.py
Comment:
Filename: cryptography/hazmat/primitives/constant_time.py
Comment:
-Filename: cryptography/hazmat/primitives/cmac.py
-Comment:
-
-Filename: cryptography/hazmat/primitives/padding.py
-Comment:
-
Filename: cryptography/hazmat/primitives/__init__.py
Comment:
-Filename: cryptography/hazmat/primitives/hmac.py
+Filename: cryptography/hazmat/primitives/keywrap.py
Comment:
-Filename: cryptography/hazmat/primitives/keywrap.py
+Filename: cryptography/hazmat/primitives/padding.py
Comment:
-Filename: cryptography/hazmat/primitives/mac.py
+Filename: cryptography/hazmat/primitives/poly1305.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/hkdf.py
+Filename: cryptography/hazmat/primitives/cmac.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/kbkdf.py
+Filename: cryptography/hazmat/primitives/serialization/pkcs7.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/x963kdf.py
+Filename: cryptography/hazmat/primitives/serialization/base.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/__init__.py
+Filename: cryptography/hazmat/primitives/serialization/__init__.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/concatkdf.py
+Filename: cryptography/hazmat/primitives/serialization/pkcs12.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/pbkdf2.py
+Filename: cryptography/hazmat/primitives/serialization/ssh.py
Comment:
-Filename: cryptography/hazmat/primitives/kdf/scrypt.py
+Filename: cryptography/hazmat/primitives/twofactor/__init__.py
Comment:
-Filename: cryptography/hazmat/primitives/ciphers/aead.py
+Filename: cryptography/hazmat/primitives/twofactor/totp.py
Comment:
-Filename: cryptography/hazmat/primitives/ciphers/algorithms.py
+Filename: cryptography/hazmat/primitives/twofactor/utils.py
Comment:
-Filename: cryptography/hazmat/primitives/ciphers/base.py
+Filename: cryptography/hazmat/primitives/twofactor/hotp.py
Comment:
-Filename: cryptography/hazmat/primitives/ciphers/modes.py
+Filename: cryptography/hazmat/primitives/ciphers/base.py
Comment:
Filename: cryptography/hazmat/primitives/ciphers/__init__.py
Comment:
-Filename: cryptography/hazmat/primitives/serialization/pkcs12.py
+Filename: cryptography/hazmat/primitives/ciphers/aead.py
Comment:
-Filename: cryptography/hazmat/primitives/serialization/base.py
+Filename: cryptography/hazmat/primitives/ciphers/algorithms.py
Comment:
-Filename: cryptography/hazmat/primitives/serialization/__init__.py
+Filename: cryptography/hazmat/primitives/ciphers/modes.py
Comment:
-Filename: cryptography/hazmat/primitives/serialization/ssh.py
+Filename: cryptography/hazmat/primitives/asymmetric/x448.py
Comment:
-Filename: cryptography/hazmat/primitives/twofactor/utils.py
+Filename: cryptography/hazmat/primitives/asymmetric/dh.py
Comment:
-Filename: cryptography/hazmat/primitives/twofactor/hotp.py
+Filename: cryptography/hazmat/primitives/asymmetric/x25519.py
Comment:
-Filename: cryptography/hazmat/primitives/twofactor/totp.py
+Filename: cryptography/hazmat/primitives/asymmetric/ed448.py
Comment:
-Filename: cryptography/hazmat/primitives/twofactor/__init__.py
+Filename: cryptography/hazmat/primitives/asymmetric/__init__.py
Comment:
Filename: cryptography/hazmat/primitives/asymmetric/dsa.py
Comment:
Filename: cryptography/hazmat/primitives/asymmetric/rsa.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/ed448.py
+Filename: cryptography/hazmat/primitives/asymmetric/ed25519.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/x25519.py
+Filename: cryptography/hazmat/primitives/asymmetric/padding.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/ed25519.py
+Filename: cryptography/hazmat/primitives/asymmetric/utils.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/dh.py
+Filename: cryptography/hazmat/primitives/asymmetric/ec.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/utils.py
+Filename: cryptography/hazmat/primitives/kdf/__init__.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/padding.py
+Filename: cryptography/hazmat/primitives/kdf/x963kdf.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/__init__.py
+Filename: cryptography/hazmat/primitives/kdf/concatkdf.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/x448.py
+Filename: cryptography/hazmat/primitives/kdf/hkdf.py
Comment:
-Filename: cryptography/hazmat/primitives/asymmetric/ec.py
+Filename: cryptography/hazmat/primitives/kdf/pbkdf2.py
Comment:
-Filename: cryptography/x509/certificate_transparency.py
+Filename: cryptography/hazmat/primitives/kdf/scrypt.py
Comment:
-Filename: cryptography/x509/ocsp.py
+Filename: cryptography/hazmat/primitives/kdf/kbkdf.py
+Comment:
+
+Filename: cryptography/x509/oid.py
Comment:
Filename: cryptography/x509/extensions.py
Comment:
Filename: cryptography/x509/base.py
Comment:
+Filename: cryptography/x509/__init__.py
+Comment:
+
Filename: cryptography/x509/name.py
Comment:
-Filename: cryptography/x509/general_name.py
+Filename: cryptography/x509/certificate_transparency.py
Comment:
-Filename: cryptography/x509/oid.py
+Filename: cryptography/x509/ocsp.py
Comment:
-Filename: cryptography/x509/__init__.py
+Filename: cryptography/x509/general_name.py
Comment:
Zip file comment:
@@ -1,23 +1,31 @@
# 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
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
__title__ = "cryptography"
-__summary__ = ("cryptography is a package which provides cryptographic recipes"
- " and primitives to Python developers.")
+__summary__ = (
+ "cryptography is a package which provides cryptographic recipes"
+ " and primitives to Python developers."
+)
__uri__ = "https://github.com/pyca/cryptography"
-__version__ = "2.6.1"
+__version__ = "3.2.1"
__author__ = "The cryptography developers"
__email__ = "[email protected]"
__license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2013-2017 {}".format(__author__)
+__copyright__ = "Copyright 2013-2020 {}".format(__author__)
@@ -10,31 +10,30 @@
import struct
import time
import six
from cryptography import utils
from cryptography.exceptions import InvalidSignature
-from cryptography.hazmat.backends import default_backend
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.primitives import hashes, padding
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.hmac import HMAC
class InvalidToken(Exception):
pass
_MAX_CLOCK_SKEW = 60
class Fernet(object):
def __init__(self, key, backend=None):
- if backend is None:
- backend = default_backend()
+ backend = _get_backend(backend)
key = base64.urlsafe_b64decode(key)
if len(key) != 32:
raise ValueError(
"Fernet key must be 32 url-safe base64-encoded bytes."
)
@@ -43,15 +42,17 @@
self._backend = backend
@classmethod
def generate_key(cls):
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):
utils._check_bytes("data", data)
padder = padding.PKCS7(algorithms.AES.block_size).padder()
@@ -68,15 +69,23 @@
h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend)
h.update(basic_parts)
hmac = h.finalize()
return base64.urlsafe_b64encode(basic_parts + hmac)
def decrypt(self, token, ttl=None):
timestamp, data = Fernet._get_unverified_token_data(token)
- return self._decrypt_data(data, timestamp, ttl)
+ return self._decrypt_data(data, timestamp, ttl, int(time.time()))
+
+ def decrypt_at_time(self, token, ttl, current_time):
+ if ttl is None:
+ raise ValueError(
+ "decrypt_at_time() can only be used with a non-None ttl"
+ )
+ timestamp, data = Fernet._get_unverified_token_data(token)
+ return self._decrypt_data(data, timestamp, ttl, current_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
@@ -88,29 +97,28 @@
except (TypeError, binascii.Error):
raise InvalidToken
if not data or six.indexbytes(data, 0) != 0x80:
raise InvalidToken
try:
- timestamp, = struct.unpack(">Q", data[1:9])
+ (timestamp,) = struct.unpack(">Q", data[1:9])
except struct.error:
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:
h.verify(data[-32:])
except InvalidSignature:
raise InvalidToken
- def _decrypt_data(self, data, timestamp, ttl):
- current_time = int(time.time())
+ 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
@@ -142,21 +150,24 @@
if not fernets:
raise ValueError(
"MultiFernet requires at least one Fernet instance"
)
self._fernets = fernets
def encrypt(self, msg):
- return self._fernets[0].encrypt(msg)
+ 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)
+ p = f._decrypt_data(data, timestamp, None, None)
break
except InvalidToken:
pass
else:
raise InvalidToken
iv = os.urandom(16)
@@ -165,7 +176,15 @@
def decrypt(self, msg, ttl=None):
for f in self._fernets:
try:
return f.decrypt(msg, ttl)
except InvalidToken:
pass
raise InvalidToken
+
+ def decrypt_at_time(self, msg, ttl, current_time):
+ for f in self._fernets:
+ try:
+ return f.decrypt_at_time(msg, ttl, current_time)
+ except InvalidToken:
+ pass
+ raise InvalidToken
@@ -17,16 +17,15 @@
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
-PersistentlyDeprecated2018 = CryptographyDeprecationWarning
-DeprecatedIn25 = CryptographyDeprecationWarning
+PersistentlyDeprecated2019 = CryptographyDeprecationWarning
def _check_bytes(name, value):
if not isinstance(value, bytes):
raise TypeError("{} must be bytes".format(name))
@@ -42,44 +41,51 @@
def register_interface(iface):
def register_decorator(klass):
verify_interface(iface, klass)
iface.register(klass)
return klass
+
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 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'
+ length or (integer.bit_length() + 7) // 8 or 1, "big"
)
+
+
else:
+
def int_to_bytes(integer, length=None):
- hex_string = '%x' % integer
+ 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)))
@@ -103,26 +109,18 @@
# Can't properly verify these yet.
continue
sig = signature(getattr(iface, method))
actual = signature(getattr(klass, method))
if sig != actual:
raise InterfaceNotImplemented(
"{}.{}'s signature differs from the expected. Expected: "
- "{!r}. Received: {!r}".format(
- klass, method, sig, actual
- )
+ "{!r}. Received: {!r}".format(klass, method, sig, actual)
)
-# 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):
def __init__(self, value, message, warning_class):
self.value = value
self.message = message
self.warning_class = warning_class
@@ -165,8 +163,9 @@
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)
@@ -1,16 +1,48 @@
# 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
+import warnings
+
from cryptography.__about__ import (
- __author__, __copyright__, __email__, __license__, __summary__, __title__,
- __uri__, __version__
+ __author__,
+ __copyright__,
+ __email__,
+ __license__,
+ __summary__,
+ __title__,
+ __uri__,
+ __version__,
)
+from cryptography.utils import CryptographyDeprecationWarning
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
+
+if sys.version_info[0] == 2:
+ warnings.warn(
+ "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,
+ stacklevel=2,
+ )
+if sys.version_info[:2] == (3, 5):
+ warnings.warn(
+ "Python 3.5 support will be dropped in the next release of "
+ "cryptography. Please upgrade your Python.",
+ CryptographyDeprecationWarning,
+ stacklevel=2,
+ )
@@ -15,14 +15,15 @@
UNSUPPORTED_MGF = 4
UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5
UNSUPPORTED_ELLIPTIC_CURVE = 6
UNSUPPORTED_SERIALIZATION = 7
UNSUPPORTED_X509 = 8
UNSUPPORTED_EXCHANGE_ALGORITHM = 9
UNSUPPORTED_DIFFIE_HELLMAN = 10
+ UNSUPPORTED_MAC = 11
class UnsupportedAlgorithm(Exception):
def __init__(self, message, reason=None):
super(UnsupportedAlgorithm, self).__init__(message)
self._reason = reason
@@ -15,53 +15,63 @@
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:
- intnodes.append(int(node, 0))
+ node_value = int(node, 10)
except ValueError:
raise ValueError(
- "Malformed OID: %s (non-integer nodes)" % (
- self._dotted_string))
+ "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))
+ "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))
+ "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))
+ "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
+ 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")
@@ -9,10 +9,18 @@
def default_backend():
global _default_backend
if _default_backend is None:
from cryptography.hazmat.backends.openssl.backend import backend
+
_default_backend = backend
return _default_backend
+
+
+def _get_backend(backend):
+ if backend is None:
+ return default_backend()
+ else:
+ return backend
@@ -53,45 +53,46 @@
Return True if the hash algorithm is supported for HMAC by this
backend.
"""
@abc.abstractmethod
def create_hmac_ctx(self, key, algorithm):
"""
- Create a MACContext for calculating a message authentication code.
+ Create a context for calculating a message authentication code.
"""
@six.add_metaclass(abc.ABCMeta)
class CMACBackend(object):
@abc.abstractmethod
def cmac_algorithm_supported(self, algorithm):
"""
Returns True if the block cipher is supported for CMAC by this backend
"""
@abc.abstractmethod
def create_cmac_ctx(self, algorithm):
"""
- Create a MACContext for calculating a message authentication code.
+ Create a context for calculating a message authentication code.
"""
@six.add_metaclass(abc.ABCMeta)
class PBKDF2HMACBackend(object):
@abc.abstractmethod
def pbkdf2_hmac_supported(self, algorithm):
"""
Return True if the hash algorithm is supported for PBKDF2 by this
backend.
"""
@abc.abstractmethod
- def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
- key_material):
+ def derive_pbkdf2_hmac(
+ self, algorithm, length, salt, iterations, key_material
+ ):
"""
Return length bytes derived from provided PBKDF2 parameters.
"""
@six.add_metaclass(abc.ABCMeta)
class RSABackend(object):
@@ -3,20 +3,23 @@
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.backends.openssl.utils import (
- _calculate_digest_and_algorithm, _check_not_prehashed,
- _warn_sign_verify_deprecated
+ _calculate_digest_and_algorithm,
+ _check_not_prehashed,
+ _warn_sign_verify_deprecated,
)
-from cryptography.hazmat.primitives import hashes, serialization
+from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import (
- AsymmetricSignatureContext, AsymmetricVerificationContext, dsa
+ AsymmetricSignatureContext,
+ AsymmetricVerificationContext,
+ dsa,
)
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 *")
@@ -25,15 +28,15 @@
# 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]]
+ return backend._ffi.buffer(sig_buf)[: buflen[0]]
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
@@ -94,15 +97,15 @@
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(p[0]),
q=self._backend._bn_to_int(q[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
)
def generate_private_key(self):
return self._backend.generate_dsa_private_key(self)
@utils.register_interface(dsa.DSAPrivateKeyWithSerialization)
@@ -140,19 +143,19 @@
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(p[0]),
q=self._backend._bn_to_int(q[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
),
- y=self._backend._bn_to_int(pub_key[0])
+ y=self._backend._bn_to_int(pub_key[0]),
),
- x=self._backend._bn_to_int(priv_key[0])
+ x=self._backend._bn_to_int(priv_key[0]),
)
def public_key(self):
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
@@ -179,16 +182,17 @@
return _DSAParameters(self._backend, dsa_cdata)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
- self._dsa_cdata
+ 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)
@@ -231,38 +235,29 @@
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(p[0]),
q=self._backend._bn_to_int(q[0]),
- g=self._backend._bn_to_int(g[0])
+ g=self._backend._bn_to_int(g[0]),
),
- y=self._backend._bn_to_int(pub_key[0])
+ y=self._backend._bn_to_int(pub_key[0]),
)
def parameters(self):
dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata)
dsa_cdata = self._backend._ffi.gc(
dsa_cdata, self._backend._lib.DSA_free
)
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
+ 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)
@@ -9,16 +9,19 @@
_ENCRYPT = 1
_DECRYPT = 0
def _aead_cipher_name(cipher):
from cryptography.hazmat.primitives.ciphers.aead import (
- AESCCM, AESGCM, ChaCha20Poly1305
+ 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")
@@ -26,60 +29,60 @@
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,
+ ctx,
+ evp_cipher,
backend._ffi.NULL,
backend._ffi.NULL,
backend._ffi.NULL,
- int(operation == _ENCRYPT)
+ 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
+ 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)
- else:
+ 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)
+ 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
+ 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(
@@ -94,14 +97,15 @@
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):
@@ -121,14 +125,15 @@
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
@@ -1,32 +1,41 @@
# 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 math
-
from cryptography import utils
from cryptography.exceptions import (
- InvalidSignature, UnsupportedAlgorithm, _Reasons
+ InvalidSignature,
+ UnsupportedAlgorithm,
+ _Reasons,
)
from cryptography.hazmat.backends.openssl.utils import (
- _calculate_digest_and_algorithm, _check_not_prehashed,
- _warn_sign_verify_deprecated
+ _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
+ AsymmetricSignatureContext,
+ AsymmetricVerificationContext,
+ rsa,
)
from cryptography.hazmat.primitives.asymmetric.padding import (
- AsymmetricPadding, MGF1, OAEP, PKCS1v15, PSS, calculate_max_pss_salt_length
+ AsymmetricPadding,
+ MGF1,
+ OAEP,
+ PKCS1v15,
+ PSS,
+ calculate_max_pss_salt_length,
)
from cryptography.hazmat.primitives.asymmetric.rsa import (
- RSAPrivateKeyWithSerialization, RSAPublicKeyWithSerialization
+ RSAPrivateKeyWithSerialization,
+ RSAPublicKeyWithSerialization,
)
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:
@@ -43,118 +52,90 @@
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
+ _Reasons.UNSUPPORTED_MGF,
)
if not backend.rsa_padding_supported(padding):
raise UnsupportedAlgorithm(
"This combination of padding and hash algorithm is not "
"supported by this backend.",
- _Reasons.UNSUPPORTED_PADDING
+ _Reasons.UNSUPPORTED_PADDING,
)
else:
raise UnsupportedAlgorithm(
- "{} is not supported by this backend.".format(
- padding.name
- ),
- _Reasons.UNSUPPORTED_PADDING
+ "{} is not supported by this backend.".format(padding.name),
+ _Reasons.UNSUPPORTED_PADDING,
)
return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding)
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.EVP_PKEY_encrypt
else:
init = backend._lib.EVP_PKEY_decrypt_init
crypt = backend._lib.EVP_PKEY_decrypt
- pkey_ctx = backend._lib.EVP_PKEY_CTX_new(
- key._evp_pkey, backend._ffi.NULL
- )
+ 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(pkey_ctx)
backend.openssl_assert(res == 1)
- res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(
- pkey_ctx, padding_enum)
+ res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum)
backend.openssl_assert(res > 0)
buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey)
backend.openssl_assert(buf_size > 0)
- if (
- isinstance(padding, OAEP) and
- backend._lib.Cryptography_HAS_RSA_OAEP_MD
- ):
+ if isinstance(padding, OAEP) and backend._lib.Cryptography_HAS_RSA_OAEP_MD:
mgf1_md = backend._evp_md_non_null_from_algorithm(
- padding._mgf._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
+ 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("unsigned char[]", buf_size)
+ # Everything from this line onwards is written with the goal of being as
+ # constant-time as is practical given the constraints of Python and our
+ # API. See Bleichenbacher's '98 attack on RSA, and its many many variants.
+ # As such, you should not attempt to change this (particularly to "clean it
+ # up") without understanding why it was written this way (see
+ # Chesterton's Fence), and without measuring to verify you have not
+ # introduced observable time differences.
res = crypt(pkey_ctx, buf, outlen, data, len(data))
+ resbuf = backend._ffi.buffer(buf)[: outlen[0]]
+ backend._lib.ERR_clear_error()
if res <= 0:
- _handle_rsa_enc_dec_error(backend, key)
-
- return backend._ffi.buffer(buf)[:outlen[0]]
-
-
-def _handle_rsa_enc_dec_error(backend, key):
- errors = backend._consume_errors()
- backend.openssl_assert(errors)
- backend.openssl_assert(errors[0].lib == backend._lib.ERR_LIB_RSA)
- if isinstance(key, _RSAPublicKey):
- 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_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)
-
- backend.openssl_assert(errors[0].reason in decoding_errors)
- raise ValueError("Decryption failed.")
+ raise ValueError("Encryption/decryption failed.")
+ return resbuf
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)
@@ -162,28 +143,30 @@
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
+ _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.")
+ 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
+ _Reasons.UNSUPPORTED_PADDING,
)
return padding_enum
def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func):
padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm)
@@ -196,73 +179,68 @@
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
+ _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)
+ padding._mgf._algorithm
+ )
res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md)
backend.openssl_assert(res > 0)
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
+ 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)
+ 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))
+ 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:
- 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)
+ errors = backend._consume_errors_with_text()
+ raise ValueError(
+ "Digest or salt length too long for key size. Use a larger key "
+ "or shorter salt length if you are specifying a PSS salt",
+ errors,
+ )
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
+ 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.
@@ -291,15 +269,15 @@
def finalize(self):
return _rsa_sig_sign(
self._backend,
self._padding,
self._algorithm,
self._private_key,
- self._hash_ctx.finalize()
+ self._hash_ctx.finalize(),
)
@utils.register_interface(AsymmetricVerificationContext)
class _RSAVerificationContext(object):
def __init__(self, backend, public_key, signature, padding, algorithm):
self._backend = backend
@@ -321,53 +299,63 @@
def verify(self):
return _rsa_sig_verify(
self._backend,
self._padding,
self._algorithm,
self._public_key,
self._signature,
- self._hash_ctx.finalize()
+ self._hash_ctx.finalize(),
)
@utils.register_interface(RSAPrivateKeyWithSerialization)
class _RSAPrivateKey(object):
def __init__(self, backend, rsa_cdata, evp_pkey):
+ res = backend._lib.RSA_check_key(rsa_cdata)
+ if res != 1:
+ errors = backend._consume_errors_with_text()
+ raise ValueError("Invalid private key", errors)
+
+ # Blinding is on by default in many versions of OpenSSL, but let's
+ # just be conservative here.
+ res = backend._lib.RSA_blinding_on(rsa_cdata, backend._ffi.NULL)
+ backend.openssl_assert(res == 1)
+
self._backend = backend
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
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._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.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)
- res = self._backend._lib.RSA_blinding_on(ctx, self._backend._ffi.NULL)
- 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 **")
@@ -395,24 +383,25 @@
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(e[0]),
n=self._backend._bn_to_int(n[0]),
- )
+ ),
)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
- self._rsa_cdata
+ 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)
@@ -423,16 +412,18 @@
def __init__(self, backend, rsa_cdata, evp_pkey):
self._backend = backend
self._rsa_cdata = rsa_cdata
self._evp_pkey = evp_pkey
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._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):
@@ -458,19 +449,15 @@
return rsa.RSAPublicNumbers(
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
+ 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(
@@ -3,31 +3,28 @@
# for complete details.
from __future__ import absolute_import, division, print_function
import datetime
import ipaddress
-import asn1crypto.core
-
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,
+ CRLEntryExtensionOID,
+ CertificatePoliciesOID,
+ ExtensionOID,
OCSPExtensionOID,
)
-class _Integers(asn1crypto.core.SequenceOf):
- _child_spec = asn1crypto.core.Integer
-
-
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
@@ -65,15 +62,15 @@
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(set([attribute]))
+ 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)
@@ -120,18 +117,18 @@
# 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:])
+ 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')
+ 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")
@@ -159,15 +156,15 @@
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
+ gn.type,
)
def _decode_ocsp_no_check(backend, ext):
return x509.OCSPNoCheck()
@@ -180,80 +177,87 @@
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):
+ def __init__(self, backend, ext_count, get_ext, handlers):
self.ext_count = ext_count
self.get_ext = get_ext
self.handlers = handlers
+ self._backend = backend
- def parse(self, backend, x509_obj):
+ def parse(self, 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)
+ for i in range(self.ext_count(x509_obj)):
+ ext = self.get_ext(x509_obj, i)
+ self._backend.openssl_assert(ext != self._backend._ffi.NULL)
+ crit = self._backend._lib.X509_EXTENSION_get_critical(ext)
critical = crit == 1
oid = x509.ObjectIdentifier(
- _obj2txt(backend, backend._lib.X509_EXTENSION_get_object(ext))
+ _obj2txt(
+ self._backend,
+ self._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:
- data = backend._lib.X509_EXTENSION_get_data(ext)
- parsed = _Integers.load(_asn1_string_to_bytes(backend, data))
+ # The extension contents are a SEQUENCE OF INTEGERs.
+ data = self._backend._lib.X509_EXTENSION_get_data(ext)
+ data_bytes = _asn1_string_to_bytes(self._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.native] for x in parsed]
+ [_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)
- parsed = asn1crypto.core.Null.load(
- _asn1_string_to_bytes(backend, data)
+ data = self._backend._lib.X509_EXTENSION_get_data(ext)
+ # The contents of the extension must be an ASN.1 NULL.
+ reader = DERReader(_asn1_string_to_bytes(self._backend, data))
+ reader.read_single_element(NULL).check_empty()
+ extensions.append(
+ x509.Extension(oid, critical, x509.PrecertPoison())
)
- assert parsed == asn1crypto.core.Null()
- 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)[:]
+ data = self._backend._lib.X509_EXTENSION_get_data(ext)
+ self._backend.openssl_assert(data != self._backend._ffi.NULL)
+ der = self._backend._ffi.buffer(data.data, data.length)[:]
unrecognized = x509.UnrecognizedExtension(oid, der)
- extensions.append(
- x509.Extension(oid, critical, unrecognized)
- )
+ 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()
+ ext_data = self._backend._lib.X509V3_EXT_d2i(ext)
+ if ext_data == self._backend._ffi.NULL:
+ self._backend._consume_errors()
raise ValueError(
"The {} extension is invalid and can't be "
"parsed".format(oid)
)
- value = handler(backend, ext_data)
+ value = handler(self._backend, ext_data)
extensions.append(x509.Extension(oid, critical, value))
seen_oids.add(oid)
return x509.Extensions(extensions)
@@ -267,65 +271,53 @@
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)
- )
+ 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')
+ )[:].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)
- )
+ 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
- )
+ organization = _asn1_string_to_utf8(backend, un.noticeref.organization)
- num = backend._lib.sk_ASN1_INTEGER_num(
- un.noticeref.noticenos
- )
+ 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
- )
+ 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(
@@ -360,43 +352,59 @@
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_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, backend._lib.sk_ACCESS_DESCRIPTION_free)
- num = backend._lib.sk_ACCESS_DESCRIPTION_num(aia)
+def _decode_information_access(backend, ia):
+ ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia)
+ ia = backend._ffi.gc(
+ ia,
+ 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(ia)
access_descriptions = []
for i in range(num):
- ad = backend._lib.sk_ACCESS_DESCRIPTION_value(aia, i)
+ ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, 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 access_descriptions
+
+
+def _decode_authority_information_access(backend, aia):
+ access_descriptions = _decode_information_access(backend, aia)
return x509.AuthorityInformationAccess(access_descriptions)
+def _decode_subject_information_access(backend, aia):
+ access_descriptions = _decode_information_access(backend, aia)
+ return x509.SubjectInformationAccess(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
@@ -411,15 +419,15 @@
content_commitment,
key_encipherment,
data_encipherment,
key_agreement,
key_cert_sign,
crl_sign,
encipher_only,
- decipher_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)
@@ -479,16 +487,21 @@
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
+ 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)
@@ -601,21 +614,17 @@
# 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
- )
+ 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)
- )
+ attributes.add(_decode_x509_name_entry(backend, rn))
relative_name = x509.RelativeDistinguishedName(attributes)
return None, relative_name
def _decode_crl_distribution_points(backend, cdps):
@@ -631,27 +640,38 @@
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):
+def _decode_scts(backend, asn1_scts):
from cryptography.hazmat.backends.openssl.x509 import (
- _SignedCertificateTimestamp
+ _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)
+ return scts
+
+
+def _decode_precert_signed_certificate_timestamps(backend, asn1_scts):
+ return x509.PrecertificateSignedCertificateTimestamps(
+ _decode_scts(backend, asn1_scts)
+ )
+
+
+def _decode_signed_certificate_timestamps(backend, asn1_scts):
+ return x509.SignedCertificateTimestamps(_decode_scts(backend, asn1_scts))
# CRLReason ::= ENUMERATED {
# unspecified (0),
# keyCompromise (1),
# cACompromise (2),
# affiliationChanged (3),
@@ -682,15 +702,15 @@
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
+ 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)
@@ -698,17 +718,15 @@
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.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)
)
@@ -761,15 +779,15 @@
"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')
+ 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
)
@@ -795,38 +813,41 @@
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 = {
+_EXTENSION_HANDLERS_BASE = {
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.SUBJECT_INFORMATION_ACCESS: (
+ _decode_subject_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
-
+_EXTENSION_HANDLERS_SCT = {
+ 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,
}
@@ -835,58 +856,23 @@
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,
}
-_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_EXTENSION_HANDLERS_SCT = {
+ ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: (
+ _decode_signed_certificate_timestamps
+ )
+}
@@ -3,51 +3,43 @@
# 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
+ 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
+ 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
+ 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()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PublicFormat.SubjectPublicKeyInfo
- ):
- raise ValueError(
- "format must be SubjectPublicKeyInfo when encoding is PEM or "
- "DER"
- )
-
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)
@@ -61,16 +53,19 @@
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
+ 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()
@@ -97,54 +92,51 @@
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
+ 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
+ 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)
+ 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"
+ "and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PrivateFormat.PKCS8
- ):
- raise ValueError(
- "format must be PKCS8 when encoding is PEM or DER"
- )
-
return self._backend._private_key_bytes(
- encoding, format, encryption_algorithm, self._evp_pkey, None
+ 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
@@ -5,24 +5,31 @@
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, _asn1_integer_to_int,
- _asn1_string_to_bytes, _decode_x509_name, _obj2txt,
+ _CRL_ENTRY_REASON_CODE_TO_ENUM,
+ _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,
+ 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:
@@ -35,49 +42,57 @@
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._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
+ 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._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._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:
@@ -98,17 +113,21 @@
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
- )
+ num_resp = self._backend._lib.OCSP_resp_count(self._basic)
+ if num_resp != 1:
+ raise ValueError(
+ "OCSP response contains more than one SINGLERESP structure"
+ ", which this library does not support. "
+ "{} found".format(num_resp)
+ )
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
)
@@ -313,36 +332,39 @@
@_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)
+ return self._backend._ocsp_basicresp_ext_parser.parse(self._basic)
+
+ @utils.cached_property
+ @_requires_successful_response
+ def single_extensions(self):
+ return self._backend._ocsp_singleresp_ext_parser.parse(self._single)
def public_bytes(self, encoding):
if encoding is not serialization.Encoding.DER:
- raise ValueError(
- "The only allowed encoding value is 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'
+ "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)
@@ -363,19 +385,17 @@
@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)
+ return self._backend._ocsp_req_ext_parser.parse(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"
- )
+ 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)
@@ -1,68 +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 warnings
-
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
+ 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=None, format=None):
- if encoding is None or format is None:
- if encoding is not None or format is not None:
- raise ValueError("Both encoding and format are required")
- else:
- warnings.warn(
- "public_bytes now requires encoding and format arguments. "
- "Support for calling without arguments will be removed in "
- "cryptography 2.7",
- utils.DeprecatedIn25,
- )
- encoding = serialization.Encoding.Raw
- format = serialization.PublicFormat.Raw
+ def public_bytes(self, encoding, format):
if (
- encoding is serialization.Encoding.Raw or
- format is serialization.PublicFormat.Raw
+ 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
+ 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()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PublicFormat.SubjectPublicKeyInfo
- ):
- raise ValueError(
- "format must be SubjectPublicKeyInfo when encoding is PEM or "
- "DER"
- )
-
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(
@@ -95,55 +73,51 @@
)
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
- )
+ 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
+ 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)
+ 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"
+ "and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PrivateFormat.PKCS8
- ):
- raise ValueError(
- "format must be PKCS8 when encoding is PEM or DER"
- )
-
return self._backend._private_key_bytes(
- encoding, format, encryption_algorithm, self._evp_pkey, None
+ 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
+ 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:]
@@ -6,31 +6,44 @@
import datetime
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
+ _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
+ _encode_asn1_int_gc,
+ _txt2obj_gc,
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
+from cryptography.x509.name import _ASN1Type
@utils.register_interface(x509.Certificate)
class _Certificate(object):
- def __init__(self, backend, x509):
+ def __init__(self, backend, x509_cert):
self._backend = backend
- self._x509 = x509
+ self._x509 = x509_cert
+
+ version = self._backend._lib.X509_get_version(self._x509)
+ if version == 0:
+ self._version = x509.Version.v1
+ elif version == 2:
+ self._version = x509.Version.v3
+ else:
+ raise x509.InvalidVersion(
+ "{} is not a valid X509 version".format(version), version
+ )
def __repr__(self):
return "<Certificate(subject={}, ...)>".format(self.subject)
def __eq__(self, other):
if not isinstance(other, x509.Certificate):
return NotImplemented
@@ -40,30 +53,23 @@
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(self.public_bytes(serialization.Encoding.DER))
+ def __deepcopy__(self, memo):
+ return self
+
def fingerprint(self, algorithm):
h = hashes.Hash(algorithm, self._backend)
h.update(self.public_bytes(serialization.Encoding.DER))
return h.finalize()
- @property
- def version(self):
- version = self._backend._lib.X509_get_version(self._x509)
- if version == 0:
- return x509.Version.v1
- elif version == 2:
- return x509.Version.v3
- else:
- raise x509.InvalidVersion(
- "{} is not a valid X509 version".format(version), version
- )
+ version = utils.read_only_property("_version")
@property
def serial_number(self):
asn1_int = self._backend._lib.X509_get_serialNumber(self._x509)
self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL)
return _asn1_integer_to_int(self._backend, asn1_int)
@@ -76,20 +82,20 @@
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)
+ 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)
+ 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)
self._backend.openssl_assert(issuer != self._backend._ffi.NULL)
return _decode_x509_name(self._backend, issuer)
@@ -118,22 +124,15 @@
)
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):
- 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
- )
+ return self._backend._certificate_extension_parser.parse(self._x509)
@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
)
@@ -187,21 +186,21 @@
@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
+ return self._backend._revoked_cert_extension_parser.parse(
+ self._x509_revoked
)
@utils.register_interface(x509.CertificateRevocationList)
class _CertificateRevocationList(object):
def __init__(self, backend, x509_crl):
self._backend = backend
@@ -216,17 +215,15 @@
def __ne__(self, other):
return not self == other
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
- )
+ 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()
@utils.cached_property
def _sorted_crl(self):
@@ -243,17 +240,15 @@
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
)
if res == 0:
return None
else:
- self._backend.openssl_assert(
- revoked[0] != self._backend._ffi.NULL
- )
+ self._backend.openssl_assert(revoked[0] != self._backend._ffi.NULL)
return _RevokedCertificate(
self._backend, self._sorted_crl, revoked[0]
)
@property
def signature_hash_algorithm(self):
oid = self.signature_algorithm_oid
@@ -352,21 +347,25 @@
if revoked == self._backend._ffi.NULL:
return 0
else:
return self._backend._lib.sk_X509_REVOKED_num(revoked)
@utils.cached_property
def extensions(self):
- return _CRL_EXTENSION_PARSER.parse(self._backend, self._x509_crl)
+ return self._backend._crl_extension_parser.parse(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.')
+ 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
@@ -428,20 +427,21 @@
@utils.cached_property
def extensions(self):
x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req)
x509_exts = self._backend._ffi.gc(
x509_exts,
lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free(
- x, self._backend._ffi.addressof(
+ x,
+ self._backend._ffi.addressof(
self._backend._lib._original_lib, "X509_EXTENSION_free"
- )
- )
+ ),
+ ),
)
- return _CSR_EXTENSION_PARSER.parse(self._backend, x509_exts)
+ return self._backend._csr_extension_parser.parse(x509_exts)
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_REQ(
bio, self._x509_req
)
@@ -481,14 +481,55 @@
if res != 1:
self._backend._consume_errors()
return False
return True
+ def get_attribute_for_oid(self, oid):
+ obj = _txt2obj_gc(self._backend, oid.dotted_string)
+ pos = self._backend._lib.X509_REQ_get_attr_by_OBJ(
+ self._x509_req, obj, -1
+ )
+ if pos == -1:
+ raise x509.AttributeNotFound(
+ "No {} attribute was found".format(oid), oid
+ )
+
+ attr = self._backend._lib.X509_REQ_get_attr(self._x509_req, pos)
+ self._backend.openssl_assert(attr != self._backend._ffi.NULL)
+ # We don't support multiple valued attributes for now.
+ self._backend.openssl_assert(
+ self._backend._lib.X509_ATTRIBUTE_count(attr) == 1
+ )
+ asn1_type = self._backend._lib.X509_ATTRIBUTE_get0_type(attr, 0)
+ self._backend.openssl_assert(asn1_type != self._backend._ffi.NULL)
+ # We need this to ensure that our C type cast is safe.
+ # Also this should always be a sane string type, but we'll see if
+ # that is true in the real world...
+ if asn1_type.type not in (
+ _ASN1Type.UTF8String.value,
+ _ASN1Type.PrintableString.value,
+ _ASN1Type.IA5String.value,
+ ):
+ raise ValueError(
+ "OID {} has a disallowed ASN.1 type: {}".format(
+ oid, asn1_type.type
+ )
+ )
+
+ data = self._backend._lib.X509_ATTRIBUTE_get0_data(
+ attr, 0, asn1_type.type, self._backend._ffi.NULL
+ )
+ self._backend.openssl_assert(data != self._backend._ffi.NULL)
+ # This cast is safe iff we assert on the type above to ensure
+ # that it is always a type of ASN1_STRING
+ data = self._backend._ffi.cast("ASN1_STRING *", data)
+ return _asn1_string_to_bytes(self._backend, data)
+
@utils.register_interface(
x509.certificate_transparency.SignedCertificateTimestamp
)
class _SignedCertificateTimestamp(object):
def __init__(self, backend, sct_list, sct):
self._backend = backend
@@ -509,17 +550,17 @@
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)
+ 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
@@ -22,19 +22,21 @@
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(
"{} is not a supported hash on this backend.".format(
- algorithm.name),
- _Reasons.UNSUPPORTED_HASH
+ algorithm.name
+ ),
+ _Reasons.UNSUPPORTED_HASH,
)
- res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
- self._backend._ffi.NULL)
+ res = self._backend._lib.EVP_DigestInit_ex(
+ ctx, evp_md, self._backend._ffi.NULL
+ )
self._backend.openssl_assert(res != 0)
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def copy(self):
@@ -54,25 +56,27 @@
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)
+ 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]]
+ return self._backend._ffi.buffer(buf)[: outlen[0]]
def _finalize_xof(self):
- buf = self._backend._ffi.new("unsigned char[]",
- self.algorithm.digest_size)
+ buf = self._backend._ffi.new(
+ "unsigned char[]", 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]
+ return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size]
@@ -1,97 +1,172 @@
# 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 collections
import contextlib
import itertools
+import warnings
from contextlib import contextmanager
-import asn1crypto.core
-
import six
from six.moves import range
from cryptography import utils, x509
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, DHBackend, DSABackend,
- EllipticCurveBackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
- PEMSerializationBackend, RSABackend, ScryptBackend, X509Backend
+ CMACBackend,
+ CipherBackend,
+ DERSerializationBackend,
+ DHBackend,
+ DSABackend,
+ EllipticCurveBackend,
+ HMACBackend,
+ HashBackend,
+ PBKDF2HMACBackend,
+ 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, _Integers
+ _CRL_ENTRY_REASON_ENUM_TO_CODE,
+ _CRL_EXTENSION_HANDLERS,
+ _EXTENSION_HANDLERS_BASE,
+ _EXTENSION_HANDLERS_SCT,
+ _OCSP_BASICRESP_EXTENSION_HANDLERS,
+ _OCSP_REQ_EXTENSION_HANDLERS,
+ _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT,
+ _REVOKED_EXTENSION_HANDLERS,
+ _X509ExtensionParser,
)
from cryptography.hazmat.backends.openssl.dh import (
- _DHParameters, _DHPrivateKey, _DHPublicKey, _dh_params_dup
+ _DHParameters,
+ _DHPrivateKey,
+ _DHPublicKey,
+ _dh_params_dup,
)
from cryptography.hazmat.backends.openssl.dsa import (
- _DSAParameters, _DSAPrivateKey, _DSAPublicKey
+ _DSAParameters,
+ _DSAPrivateKey,
+ _DSAPublicKey,
)
from cryptography.hazmat.backends.openssl.ec import (
- _EllipticCurvePrivateKey, _EllipticCurvePublicKey
+ _EllipticCurvePrivateKey,
+ _EllipticCurvePublicKey,
)
from cryptography.hazmat.backends.openssl.ed25519 import (
- _Ed25519PrivateKey, _Ed25519PublicKey
+ _Ed25519PrivateKey,
+ _Ed25519PublicKey,
)
from cryptography.hazmat.backends.openssl.ed448 import (
- _ED448_KEY_SIZE, _Ed448PrivateKey, _Ed448PublicKey
+ _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,
+ _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,
+ _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
+ _OCSPRequest,
+ _OCSPResponse,
+)
+from cryptography.hazmat.backends.openssl.poly1305 import (
+ _POLY1305_KEY_SIZE,
+ _Poly1305Context,
)
from cryptography.hazmat.backends.openssl.rsa import (
- _RSAPrivateKey, _RSAPublicKey
+ _RSAPrivateKey,
+ _RSAPublicKey,
)
from cryptography.hazmat.backends.openssl.x25519 import (
- _X25519PrivateKey, _X25519PublicKey
+ _X25519PrivateKey,
+ _X25519PublicKey,
)
from cryptography.hazmat.backends.openssl.x448 import (
- _X448PrivateKey, _X448PublicKey
+ _X448PrivateKey,
+ _X448PublicKey,
)
from cryptography.hazmat.backends.openssl.x509 import (
- _Certificate, _CertificateRevocationList,
- _CertificateSigningRequest, _RevokedCertificate
+ _Certificate,
+ _CertificateRevocationList,
+ _CertificateSigningRequest,
+ _RevokedCertificate,
)
from cryptography.hazmat.bindings.openssl import binding
from cryptography.hazmat.primitives import hashes, serialization
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, ed25519, rsa
+from cryptography.hazmat.primitives.asymmetric import (
+ dsa,
+ ec,
+ ed25519,
+ ed448,
+ rsa,
+)
from cryptography.hazmat.primitives.asymmetric.padding import (
- MGF1, OAEP, PKCS1v15, PSS
+ MGF1,
+ OAEP,
+ PKCS1v15,
+ PSS,
)
from cryptography.hazmat.primitives.ciphers.algorithms import (
- AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, 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, XTS
+ CBC,
+ CFB,
+ CFB8,
+ CTR,
+ ECB,
+ GCM,
+ OFB,
+ XTS,
)
from cryptography.hazmat.primitives.kdf import scrypt
-from cryptography.hazmat.primitives.serialization import ssh
+from cryptography.hazmat.primitives.serialization import pkcs7, ssh
from cryptography.x509 import ocsp
_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"])
+# 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)
@@ -103,39 +178,92 @@
@utils.register_interface_if(
binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend
)
class Backend(object):
"""
OpenSSL API binding interfaces.
"""
+
name = "openssl"
+ # FIPS has opinions about acceptable algorithms and key sizes, but the
+ # disallowed algorithms are still present in OpenSSL. They just error if
+ # you try to use them. To avoid that we allowlist the algorithms in
+ # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are.
+ _fips_aead = {
+ b"aes-128-ccm",
+ b"aes-192-ccm",
+ b"aes-256-ccm",
+ b"aes-128-gcm",
+ b"aes-192-gcm",
+ b"aes-256-gcm",
+ }
+ _fips_ciphers = (AES, TripleDES)
+ _fips_hashes = (
+ hashes.SHA1,
+ hashes.SHA224,
+ hashes.SHA256,
+ hashes.SHA384,
+ hashes.SHA512,
+ hashes.SHA512_224,
+ hashes.SHA512_256,
+ hashes.SHA3_224,
+ hashes.SHA3_256,
+ hashes.SHA3_384,
+ hashes.SHA3_512,
+ hashes.SHAKE128,
+ hashes.SHAKE256,
+ )
+ _fips_rsa_min_key_size = 2048
+ _fips_rsa_min_public_exponent = 65537
+ _fips_dsa_min_modulus = 1 << 2048
+ _fips_dh_min_key_size = 2048
+ _fips_dh_min_modulus = 1 << _fips_dh_min_key_size
+
def __init__(self):
self._binding = binding.Binding()
self._ffi = self._binding.ffi
self._lib = self._binding.lib
+ self._fips_enabled = self._is_fips_enabled()
self._cipher_registry = {}
self._register_default_ciphers()
- self.activate_osrandom_engine()
+ self._register_x509_ext_parsers()
+ self._register_x509_encoders()
+ if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE:
+ warnings.warn(
+ "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.",
+ UserWarning,
+ )
+ else:
+ 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 openssl_assert(self, ok):
- return binding._openssl_assert(self._lib, ok)
+ def openssl_assert(self, ok, errors=None):
+ return binding._openssl_assert(self._lib, ok, errors=errors)
+
+ def _is_fips_enabled(self):
+ fips_mode = getattr(self._lib, "FIPS_mode", lambda: 0)
+ mode = fips_mode()
+ if mode == 0:
+ # OpenSSL without FIPS pushes an error on the error stack
+ self._lib.ERR_clear_error()
+ return bool(mode)
def activate_builtin_random(self):
- if self._lib.Cryptography_HAS_ENGINE:
+ if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_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 new engine.
- self._lib.RAND_cleanup()
+ # 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
@@ -153,39 +281,40 @@
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:
+ if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_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 new engine.
- self._lib.RAND_cleanup()
+ # 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)
+ 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')
+ 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.OpenSSL_version(self._lib.OPENSSL_VERSION)
).decode("ascii")
def openssl_version_number(self):
return self._lib.OpenSSL_version_num()
@@ -206,136 +335,206 @@
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):
+ if self._fips_enabled and not isinstance(algorithm, self._fips_hashes):
+ return False
+
evp_md = self._evp_md_from_algorithm(algorithm)
return evp_md != self._ffi.NULL
def hmac_supported(self, algorithm):
return self.hash_supported(algorithm)
def create_hash_ctx(self, algorithm):
return _HashContext(self, algorithm)
def cipher_supported(self, cipher, mode):
+ if self._fips_enabled and not isinstance(cipher, self._fips_ciphers):
+ return False
try:
adapter = self._cipher_registry[type(cipher), type(mode)]
except KeyError:
return False
evp_cipher = adapter(self, cipher, mode)
return self._ffi.NULL != evp_cipher
def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
if (cipher_cls, mode_cls) in self._cipher_registry:
- raise ValueError("Duplicate registration for: {} {}.".format(
- cipher_cls, mode_cls)
+ 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, GCM]:
self.register_cipher_adapter(
AES,
mode_cls,
- GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"),
)
for mode_cls in [CBC, CTR, ECB, OFB, CFB]:
self.register_cipher_adapter(
Camellia,
mode_cls,
- GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"),
)
for mode_cls in [CBC, CFB, CFB8, OFB]:
self.register_cipher_adapter(
- TripleDES,
- mode_cls,
- GetCipherByName("des-ede3-{mode.name}")
+ TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}")
)
self.register_cipher_adapter(
- TripleDES,
- ECB,
- GetCipherByName("des-ede3")
+ TripleDES, ECB, GetCipherByName("des-ede3")
)
for mode_cls in [CBC, CFB, OFB, ECB]:
self.register_cipher_adapter(
- Blowfish,
- mode_cls,
- GetCipherByName("bf-{mode.name}")
+ Blowfish, mode_cls, GetCipherByName("bf-{mode.name}")
)
for mode_cls in [CBC, CFB, OFB, ECB]:
self.register_cipher_adapter(
- SEED,
- mode_cls,
- GetCipherByName("seed-{mode.name}")
+ SEED, mode_cls, GetCipherByName("seed-{mode.name}")
)
for cipher_cls, mode_cls in itertools.product(
[CAST5, IDEA],
[CBC, OFB, CFB, ECB],
):
self.register_cipher_adapter(
cipher_cls,
mode_cls,
- GetCipherByName("{cipher.name}-{mode.name}")
+ GetCipherByName("{cipher.name}-{mode.name}"),
)
+ self.register_cipher_adapter(ARC4, type(None), GetCipherByName("rc4"))
+ # We don't actually support RC2, this is just used by some tests.
+ self.register_cipher_adapter(_RC2, type(None), GetCipherByName("rc2"))
self.register_cipher_adapter(
- ARC4,
- type(None),
- GetCipherByName("rc4")
- )
- self.register_cipher_adapter(
- ChaCha20,
- type(None),
- GetCipherByName("chacha20")
+ ChaCha20, type(None), GetCipherByName("chacha20")
)
self.register_cipher_adapter(AES, XTS, _get_xts_cipher)
+ def _register_x509_ext_parsers(self):
+ ext_handlers = _EXTENSION_HANDLERS_BASE.copy()
+ # All revoked extensions are valid single response extensions, see:
+ # https://tools.ietf.org/html/rfc6960#section-4.4.5
+ singleresp_handlers = _REVOKED_EXTENSION_HANDLERS.copy()
+
+ if self._lib.Cryptography_HAS_SCT:
+ ext_handlers.update(_EXTENSION_HANDLERS_SCT)
+ singleresp_handlers.update(_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT)
+
+ self._certificate_extension_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.X509_get_ext_count,
+ get_ext=self._lib.X509_get_ext,
+ handlers=ext_handlers,
+ )
+ self._csr_extension_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.sk_X509_EXTENSION_num,
+ get_ext=self._lib.sk_X509_EXTENSION_value,
+ handlers=ext_handlers,
+ )
+ self._revoked_cert_extension_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.X509_REVOKED_get_ext_count,
+ get_ext=self._lib.X509_REVOKED_get_ext,
+ handlers=_REVOKED_EXTENSION_HANDLERS,
+ )
+ self._crl_extension_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.X509_CRL_get_ext_count,
+ get_ext=self._lib.X509_CRL_get_ext,
+ handlers=_CRL_EXTENSION_HANDLERS,
+ )
+ self._ocsp_req_ext_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.OCSP_REQUEST_get_ext_count,
+ get_ext=self._lib.OCSP_REQUEST_get_ext,
+ handlers=_OCSP_REQ_EXTENSION_HANDLERS,
+ )
+ self._ocsp_basicresp_ext_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.OCSP_BASICRESP_get_ext_count,
+ get_ext=self._lib.OCSP_BASICRESP_get_ext,
+ handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS,
+ )
+ self._ocsp_singleresp_ext_parser = _X509ExtensionParser(
+ self,
+ ext_count=self._lib.OCSP_SINGLERESP_get_ext_count,
+ get_ext=self._lib.OCSP_SINGLERESP_get_ext,
+ handlers=singleresp_handlers,
+ )
+
+ def _register_x509_encoders(self):
+ self._extension_encode_handlers = _EXTENSION_ENCODE_HANDLERS.copy()
+ self._crl_extension_encode_handlers = (
+ _CRL_EXTENSION_ENCODE_HANDLERS.copy()
+ )
+ self._crl_entry_extension_encode_handlers = (
+ _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS.copy()
+ )
+ self._ocsp_request_extension_encode_handlers = (
+ _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS.copy()
+ )
+ self._ocsp_basicresp_extension_encode_handlers = (
+ _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS.copy()
+ )
+
def create_symmetric_encryption_ctx(self, cipher, mode):
return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
def create_symmetric_decryption_ctx(self, cipher, mode):
return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
def pbkdf2_hmac_supported(self, algorithm):
return self.hmac_supported(algorithm)
- def derive_pbkdf2_hmac(self, algorithm, length, salt, iterations,
- key_material):
+ def derive_pbkdf2_hmac(
+ self, algorithm, length, salt, iterations, key_material
+ ):
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
+ buf,
)
self.openssl_assert(res == 1)
return self._ffi.buffer(buf)[:]
def _consume_errors(self):
return binding._consume_errors(self._lib)
+ def _consume_errors_with_text(self):
+ return binding._consume_errors_with_text(self._lib)
+
def _bn_to_int(self, bn):
assert bn != self._ffi.NULL
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
self.openssl_assert(bin_len >= 0)
- return int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big")
+ 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)
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)
@@ -386,27 +585,30 @@
)
self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
def generate_rsa_parameters_supported(self, public_exponent, key_size):
- return (public_exponent >= 3 and public_exponent & 1 != 0 and
- key_size >= 512)
+ return (
+ public_exponent >= 3
+ and public_exponent & 1 != 0
+ and key_size >= 512
+ )
def load_rsa_private_numbers(self, numbers):
rsa._check_private_key_components(
numbers.p,
numbers.q,
numbers.d,
numbers.dmp1,
numbers.dmq1,
numbers.iqmp,
numbers.public_numbers.e,
- numbers.public_numbers.n
+ numbers.public_numbers.n,
)
rsa_cdata = self._lib.RSA_new()
self.openssl_assert(rsa_cdata != self._ffi.NULL)
rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free)
p = self._int_to_bn(numbers.p)
q = self._int_to_bn(numbers.q)
d = self._int_to_bn(numbers.d)
@@ -417,16 +619,14 @@
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)
- self.openssl_assert(res == 1)
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPrivateKey(self, rsa_cdata, evp_pkey)
def load_rsa_public_numbers(self, numbers):
rsa._check_public_key_components(numbers.e, numbers.n)
rsa_cdata = self._lib.RSA_new()
@@ -456,17 +656,15 @@
"""
Return a _MemoryBIO namedtuple of (BIO, char*).
The char* is the storage for the BIO and it must stay alive until the
BIO is finished with.
"""
data_ptr = self._ffi.from_buffer(data)
- bio = self._lib.BIO_new_mem_buf(
- data_ptr, len(data)
- )
+ bio = self._lib.BIO_new_mem_buf(data_ptr, len(data))
self.openssl_assert(bio != self._ffi.NULL)
return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr)
def _create_mem_bio_gc(self):
"""
Creates an empty memory BIO.
@@ -574,53 +772,61 @@
return _Ed448PublicKey(self, evp_pkey)
else:
raise UnsupportedAlgorithm("Unsupported key type.")
def _oaep_hash_supported(self, algorithm):
if self._lib.Cryptography_HAS_RSA_OAEP_MD:
return isinstance(
- algorithm, (
+ algorithm,
+ (
hashes.SHA1,
hashes.SHA224,
hashes.SHA256,
hashes.SHA384,
hashes.SHA512,
- )
+ ),
)
else:
return isinstance(algorithm, hashes.SHA1)
def rsa_padding_supported(self, padding):
if isinstance(padding, PKCS1v15):
return True
elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1):
return self.hash_supported(padding._mgf._algorithm)
elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1):
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
+ 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 key_size not in (1024, 2048, 3072, 4096):
+ raise ValueError(
+ "Key size must be 1024, 2048, 3072, or 4096 bits."
+ )
ctx = self._lib.DSA_new()
self.openssl_assert(ctx != self._ffi.NULL)
ctx = self._ffi.gc(ctx, self._lib.DSA_free)
res = self._lib.DSA_generate_parameters_ex(
- ctx, key_size, self._ffi.NULL, 0,
- self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+ ctx,
+ key_size,
+ self._ffi.NULL,
+ 0,
+ self._ffi.NULL,
+ self._ffi.NULL,
+ self._ffi.NULL,
)
self.openssl_assert(res == 1)
return _DSAParameters(self, ctx)
def generate_dsa_private_key(self, parameters):
@@ -708,28 +914,45 @@
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 (
- isinstance(algorithm, hashes.MD5) and not
- isinstance(private_key, rsa.RSAPrivateKey)
+ 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 an 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 is not a supported hash algorithm for EC/DSA CSRs"
+ "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._evp_md_non_null_from_algorithm(algorithm)
+ evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm)
# Create an empty request.
x509_req = self._lib.X509_REQ_new()
self.openssl_assert(x509_req != self._ffi.NULL)
x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free)
# Set x509 version.
@@ -740,79 +963,72 @@
res = self._lib.X509_REQ_set_subject_name(
x509_req, _encode_name_gc(self, builder._subject_name)
)
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
- )
+ res = self._lib.X509_REQ_set_pubkey(x509_req, public_key._evp_pkey)
self.openssl_assert(res == 1)
# Add extensions.
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(
+ x,
+ self._ffi.addressof(
self._lib._original_lib, "X509_EXTENSION_free"
- )
- )
+ ),
+ ),
)
# 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,
+ handlers=self._extension_encode_handlers,
x509_obj=sk_extension,
add_func=self._lib.sk_X509_EXTENSION_insert,
- gc=False
+ 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
- )
- 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
- )
+ # Add attributes (all bytes encoded as ASN1 UTF8_STRING)
+ for attr_oid, attr_val in builder._attributes:
+ obj = _txt2obj_gc(self, attr_oid.dotted_string)
+ res = self._lib.X509_REQ_add1_attr_by_OBJ(
+ x509_req,
+ obj,
+ x509.name._ASN1Type.UTF8String.value,
+ attr_val,
+ len(attr_val),
)
+ self.openssl_assert(res == 1)
- raise ValueError("Digest too big for RSA key")
+ # Sign the request using the requester's private key.
+ res = self._lib.X509_REQ_sign(x509_req, private_key._evp_pkey, evp_md)
+ if res == 0:
+ errors = self._consume_errors_with_text()
+ raise ValueError("Signing failed", errors)
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.')
- if not isinstance(algorithm, hashes.HashAlgorithm):
- raise TypeError('Algorithm must be a registered hash algorithm.')
-
- if (
- isinstance(algorithm, hashes.MD5) and not
- isinstance(private_key, rsa.RSAPrivateKey)
- ):
- raise ValueError(
- "MD5 is not a supported hash algorithm for EC/DSA certificates"
- )
+ raise TypeError("Builder type mismatch.")
+ self._x509_check_signature_params(private_key, algorithm)
# Resolve the signature algorithm.
- evp_md = self._evp_md_non_null_from_algorithm(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, backend._lib.X509_free)
+ 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(
@@ -829,87 +1045,79 @@
# 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_get_notBefore(x509_cert), builder._not_valid_before
+ self._lib.X509_getm_notBefore(x509_cert), builder._not_valid_before
)
# Set the "not after" time.
self._set_asn1_time(
- self._lib.X509_get_notAfter(x509_cert), builder._not_valid_after
+ self._lib.X509_getm_notAfter(x509_cert), builder._not_valid_after
)
# Add extensions.
self._create_x509_extensions(
extensions=builder._extensions,
- handlers=_EXTENSION_ENCODE_HANDLERS,
+ handlers=self._extension_encode_handlers,
x509_obj=x509_cert,
add_func=self._lib.X509_add_ext,
- gc=True
+ 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
- )
+ 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")
+ errors = self._consume_errors_with_text()
+ raise ValueError("Signing failed", errors)
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')
+ 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')
+ 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.')
- if not isinstance(algorithm, hashes.HashAlgorithm):
- raise TypeError('Algorithm must be a registered hash algorithm.')
-
- if (
- isinstance(algorithm, hashes.MD5) and not
- isinstance(private_key, rsa.RSAPrivateKey)
- ):
- raise ValueError(
- "MD5 is not a supported hash algorithm for EC/DSA CRLs"
- )
+ raise TypeError("Builder type mismatch.")
+ self._x509_check_signature_params(private_key, algorithm)
- evp_md = self._evp_md_non_null_from_algorithm(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, backend._lib.X509_CRL_free)
+ 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(
@@ -926,52 +1134,41 @@
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,
+ handlers=self._crl_extension_encode_handlers,
x509_obj=x509_crl,
add_func=self._lib.X509_CRL_add_ext,
- gc=True
+ 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.Cryptography_X509_REVOKED_dup(
- revoked_cert._x509_revoked
- )
+ 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
- )
+ 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")
+ errors = self._consume_errors_with_text()
+ raise ValueError("Signing failed", errors)
return _CertificateRevocationList(self, x509_crl)
- def _create_x509_extensions(self, extensions, handlers, x509_obj,
- add_func, gc):
+ 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
- )
+ 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)
@@ -984,41 +1181,46 @@
)
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 = _Integers([x.value for x in extension.value]).dump()
+ 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):
- asn1 = asn1crypto.core.Null().dump()
- value = _encode_asn1_str_gc(self, asn1)
+ 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)
+ "Extension not supported: {}".format(extension.oid)
)
ext_struct = encode(self, extension.value)
nid = self._lib.OBJ_txt2nid(
extension.oid.dotted_string.encode("ascii")
)
- backend.openssl_assert(nid != self._lib.NID_undef)
+ 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.')
+ 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
@@ -1026,18 +1228,18 @@
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,
+ handlers=self._crl_entry_extension_encode_handlers,
x509_obj=x509_revoked,
add_func=self._lib.X509_REVOKED_add_ext,
- gc=True
+ 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,
self._evp_pkey_to_private_key,
@@ -1070,15 +1272,16 @@
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)
+ 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):
@@ -1135,17 +1338,15 @@
evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata)
return _RSAPublicKey(self, rsa_cdata, evp_pkey)
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
- )
+ 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)
@@ -1270,55 +1471,51 @@
else:
self._handle_key_loading_error()
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)
if password is not None and userdata.called == 0:
raise TypeError(
- "Password was given but private key is not encrypted.")
+ "Password was given but private key is not encrypted."
+ )
assert (
- (password is not None and userdata.called == 1) or
- password is None
- )
+ password is not None and userdata.called == 1
+ ) or password is None
return convert_func(evp_pkey)
def _handle_key_loading_error(self):
errors = self._consume_errors()
if not errors:
raise ValueError("Could not deserialize key data.")
- 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_R_PKCS12_CIPHERFINAL_ERROR
- )
+ 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_R_PKCS12_CIPHERFINAL_ERROR,
):
raise ValueError("Bad decrypt. Incorrect password?")
- 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
- )
+ 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(
"PEM data is encrypted with an unsupported cipher",
- _Reasons.UNSUPPORTED_CIPHER
+ _Reasons.UNSUPPORTED_CIPHER,
)
elif any(
error._lib_reason_match(
self._lib.ERR_LIB_EVP,
- self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM
+ self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM,
)
for error in errors
):
raise ValueError("Unsupported public key algorithm.")
else:
assert errors[0].lib in (
@@ -1333,22 +1530,15 @@
curve_nid = self._elliptic_curve_to_nid(curve)
except UnsupportedAlgorithm:
curve_nid = self._lib.NID_undef
group = self._lib.EC_GROUP_new_by_curve_name(curve_nid)
if group == self._ffi.NULL:
- errors = self._consume_errors()
- self.openssl_assert(
- curve_nid == self._lib.NID_undef or
- errors[0]._lib_reason_match(
- self._lib.ERR_LIB_EC,
- self._lib.EC_R_UNKNOWN_GROUP
- )
- )
+ self._consume_errors()
return False
else:
self.openssl_assert(curve_nid != self._lib.NID_undef)
self._lib.EC_GROUP_free(group)
return True
def elliptic_curve_signature_algorithm_supported(
@@ -1373,39 +1563,41 @@
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 {}.".format(curve.name),
- _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE,
)
def load_elliptic_curve_private_numbers(self, numbers):
public = numbers.public_numbers
ec_cdata = self._ec_key_new_by_curve(public.curve)
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)
+ ec_cdata, public.x, public.y
+ )
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):
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)
+ 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)
@@ -1435,16 +1627,17 @@
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)
+ 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)
@@ -1458,16 +1651,27 @@
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)
+ return self._ec_key_new_by_curve_nid(curve_nid)
+
+ def _ec_key_new_by_curve_nid(self, curve_nid):
ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid)
self.openssl_assert(ec_cdata != self._ffi.NULL)
+ # Setting the ASN.1 flag to OPENSSL_EC_NAMED_CURVE is
+ # only necessary on OpenSSL 1.0.2t/u. Once we drop support for 1.0.2
+ # we can remove this as it's done automatically when getting an EC_KEY
+ # from new_by_curve_name
+ # CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER
+ self._lib.EC_KEY_set_asn1_flag(
+ ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE
+ )
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()
@@ -1488,39 +1692,40 @@
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
- )
+ 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,
+ handlers=self._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
+ 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[
@@ -1544,55 +1749,58 @@
res = self._lib.OCSP_basic_add1_status(
basic,
certid,
builder._response._cert_status.value,
reason,
rev_time,
this_update,
- next_update
+ next_update,
)
self.openssl_assert(res != self._ffi.NULL)
# okay, now sign the basic structure
- evp_md = self._evp_md_non_null_from_algorithm(algorithm)
+ 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,
+ handlers=self._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
+ 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
- )
+ errors = self._consume_errors_with_text()
+ raise ValueError(
+ "Error while signing. responder_cert must be signed "
+ "by private_key",
+ errors,
)
- raise ValueError("responder_cert must be signed by private_key")
return basic
- def create_ocsp_response(self, response_status, builder, private_key,
- algorithm):
+ 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
@@ -1600,42 +1808,38 @@
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)
+ return self.elliptic_curve_supported(curve) and isinstance(
+ algorithm, ec.ECDH
)
def _ec_cdata_to_evp_pkey(self, ec_cdata):
evp_pkey = self._create_evp_pkey_gc()
res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata)
self.openssl_assert(res == 1)
return evp_pkey
def _elliptic_curve_to_nid(self, curve):
"""
Get the NID for a curve name.
"""
- curve_aliases = {
- "secp192r1": "prime192v1",
- "secp256r1": "prime256v1"
- }
+ curve_aliases = {"secp192r1": "prime192v1", "secp256r1": "prime256v1"}
curve_name = curve_aliases.get(curve.name, curve.name)
curve_nid = self._lib.OBJ_sn2nid(curve_name.encode())
if curve_nid == self._lib.NID_undef:
raise UnsupportedAlgorithm(
"{} is not a supported elliptic curve".format(curve.name),
- _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ _Reasons.UNSUPPORTED_ELLIPTIC_CURVE,
)
return curve_nid
@contextmanager
def _tmp_bn_ctx(self):
bn_ctx = self._lib.BN_CTX_new()
self.openssl_assert(bn_ctx != self._ffi.NULL)
@@ -1690,239 +1894,197 @@
res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y)
if res != 1:
self._consume_errors()
raise ValueError("Invalid EC key.")
return ctx
- def _private_key_bytes(self, encoding, format, encryption_algorithm,
- evp_pkey, cdata):
+ def _private_key_bytes(
+ self, encoding, format, encryption_algorithm, 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"
)
-
- # X9.62 encoding is only valid for EC public keys
- if encoding is serialization.Encoding.X962:
- raise ValueError("X9.62 format is only valid for EC public keys")
-
- # Raw format and encoding are only valid for X25519, Ed25519, X448, and
- # Ed448 keys. We capture those cases before this method is called so if
- # we see those enum values here it means the caller has passed them to
- # a key that doesn't support raw type
- if format is serialization.PrivateFormat.Raw:
- raise ValueError("raw format is invalid with this key or encoding")
-
- if encoding is serialization.Encoding.Raw:
- raise ValueError("raw encoding is invalid with this key or format")
-
- if not isinstance(encryption_algorithm,
- serialization.KeySerializationEncryption):
+ if not isinstance(
+ encryption_algorithm, serialization.KeySerializationEncryption
+ ):
raise TypeError(
"Encryption algorithm must be a KeySerializationEncryption "
"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"
- )
+ elif isinstance(
+ encryption_algorithm, serialization.BestAvailableEncryption
+ ):
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"
)
else:
raise ValueError("Unsupported encryption type")
- key_type = self._lib.EVP_PKEY_id(evp_pkey)
- 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 encoding is serialization.Encoding.DER:
+ write_bio = self._lib.i2d_PKCS8PrivateKey_bio
else:
- assert format is serialization.PrivateFormat.TraditionalOpenSSL
+ 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:
+ if self._fips_enabled and not isinstance(
+ encryption_algorithm, serialization.NoEncryption
+ ):
+ raise ValueError(
+ "Encrypted traditional OpenSSL format is not "
+ "supported in FIPS mode."
+ )
+ 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 key_type == self._lib.EVP_PKEY_DSA:
write_bio = self._lib.PEM_write_bio_DSAPrivateKey
- else:
- assert key_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(key_type, cdata)
- else:
- assert format is serialization.PrivateFormat.PKCS8
- write_bio = self._lib.i2d_PKCS8PrivateKey_bio
- key = evp_pkey
+ raise ValueError("Unsupported encoding for TraditionalOpenSSL")
+
+ # OpenSSH + PEM
+ if format is serialization.PrivateFormat.OpenSSH:
+ if encoding is serialization.Encoding.PEM:
+ return ssh.serialize_ssh_private_key(key, password)
+
+ raise ValueError(
+ "OpenSSH private key format can only be used"
+ " with PEM encoding"
+ )
+
+ # 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:
- raise TypeError("encoding must be Encoding.PEM or Encoding.DER")
+ # 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_gc()
- 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,
- self._ffi.NULL
)
- self.openssl_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 key_type == self._lib.EVP_PKEY_EC:
- write_bio = self._lib.i2d_ECPrivateKey_bio
- else:
- self.openssl_assert(key_type == self._lib.EVP_PKEY_DSA)
- write_bio = self._lib.i2d_DSAPrivateKey_bio
+ def _bio_func_output(self, write_bio, *args):
bio = self._create_mem_bio_gc()
- res = write_bio(bio, cdata)
+ res = write_bio(bio, *args)
self.openssl_assert(res == 1)
return self._read_mem_bio(bio)
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"
+ )
- # Compressed/UncompressedPoint are only valid for EC keys and those
- # cases are handled by the ECPublicKey public_bytes method before this
- # method is called
- if format in (serialization.PublicFormat.UncompressedPoint,
- serialization.PublicFormat.CompressedPoint):
- raise ValueError("Point formats are not valid for this key type")
-
- # Raw format and encoding are only valid for X25519, Ed25519, X448, and
- # Ed448 keys. We capture those cases before this method is called so if
- # we see those enum values here it means the caller has passed them to
- # a key that doesn't support raw type
- if format is serialization.PublicFormat.Raw:
- raise ValueError("raw format is invalid with this key or encoding")
-
- if encoding is serialization.Encoding.Raw:
- raise ValueError("raw encoding is invalid with this key or format")
-
- if (
- format is serialization.PublicFormat.OpenSSH or
- encoding is serialization.Encoding.OpenSSH
- ):
- if (
- format is not serialization.PublicFormat.OpenSSH or
- encoding is not serialization.Encoding.OpenSSH
- ):
- raise ValueError(
- "OpenSSH format must be used with OpenSSH encoding"
- )
- return self._openssh_public_key_bytes(key)
- elif format is serialization.PublicFormat.SubjectPublicKeyInfo:
+ # SubjectPublicKeyInfo + PEM/DER
+ if format is serialization.PublicFormat.SubjectPublicKeyInfo:
if encoding is serialization.Encoding.PEM:
write_bio = self._lib.PEM_write_bio_PUBKEY
- else:
- assert encoding is serialization.Encoding.DER
+ 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 self._lib.EVP_PKEY_id(evp_pkey) == 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
- else:
- assert encoding is serialization.Encoding.DER
+ 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)
- key = cdata
- else:
- raise TypeError(
- "format must be an item from the PublicFormat enum"
- )
+ # OpenSSH + OpenSSH
+ if format is serialization.PublicFormat.OpenSSH:
+ if encoding is serialization.Encoding.OpenSSH:
+ return ssh.serialize_ssh_public_key(key)
- bio = self._create_mem_bio_gc()
- res = write_bio(bio, key)
- self.openssl_assert(res == 1)
- return self._read_mem_bio(bio)
-
- 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)
+ raise ValueError(
+ "OpenSSH format must be used with OpenSSH encoding"
)
- else:
- assert 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)
- )
+ # Anything that key-specific code was supposed to handle earlier,
+ # like Raw, CompressedPoint, UncompressedPoint
+ raise ValueError("format is invalid with this key")
def _parameter_bytes(self, encoding, format, cdata):
if encoding is serialization.Encoding.OpenSSH:
- raise TypeError(
- "OpenSSH encoding is not supported"
- )
+ 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)
+ 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:
@@ -1945,18 +2107,15 @@
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
+ 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()
@@ -1972,15 +2131,16 @@
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))
+ 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)
@@ -2011,20 +2171,18 @@
# 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
+ parameter_numbers.g == 2
+ and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0
):
- raise ValueError(
- "DH private numbers did not pass safety checks."
- )
+ 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()
@@ -2111,19 +2269,19 @@
# 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)
- backend.openssl_assert(res == 1)
+ self.openssl_assert(res == 1)
res = self._lib.EVP_PKEY_set1_tls_encodedpoint(
evp_pkey, data, len(data)
)
- backend.openssl_assert(res == 1)
+ 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
@@ -2143,15 +2301,15 @@
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 = backend._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL)
+ 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)
@@ -2170,14 +2328,16 @@
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):
+ if self._fips_enabled:
+ return False
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(
@@ -2200,17 +2360,21 @@
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):
+ if self._fips_enabled:
+ return False
return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111
def ed25519_supported(self):
+ if self._fips_enabled:
+ return False
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")
@@ -2238,14 +2402,16 @@
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):
+ if self._fips_enabled:
+ return False
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")
@@ -2275,46 +2441,42 @@
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
+ 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
- )
- )
-
+ errors = self._consume_errors_with_text()
# memory required formula explained here:
# https://blog.filippo.io/the-scrypt-parameters/
- min_memory = 128 * n * r // (1024**2)
+ min_memory = 128 * n * r // (1024 ** 2)
raise MemoryError(
"Not enough memory to derive key. These parameters require"
- " {} MB of memory.".format(min_memory)
+ " {} MB of memory.".format(min_memory),
+ errors,
)
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
- )
+ if self._fips_enabled and cipher_name not in self._fips_aead:
+ return False
+ 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.
@@ -2391,20 +2553,224 @@
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)
+ x509 = self._ffi.gc(x509, self._lib.X509_free)
additional_certificates.append(_Certificate(self, x509))
return (key, cert, additional_certificates)
+ def serialize_key_and_certificates_to_pkcs12(
+ self, name, key, cert, cas, encryption_algorithm
+ ):
+ password = None
+ if name is not None:
+ utils._check_bytes("name", name)
+
+ if isinstance(encryption_algorithm, serialization.NoEncryption):
+ nid_cert = -1
+ nid_key = -1
+ pkcs12_iter = 0
+ mac_iter = 0
+ elif isinstance(
+ encryption_algorithm, serialization.BestAvailableEncryption
+ ):
+ # PKCS12 encryption is hopeless trash and can never be fixed.
+ # This is the least terrible option.
+ nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
+ nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
+ # At least we can set this higher than OpenSSL's default
+ pkcs12_iter = 20000
+ # mac_iter chosen for compatibility reasons, see:
+ # https://www.openssl.org/docs/man1.1.1/man3/PKCS12_create.html
+ # Did we mention how lousy PKCS12 encryption is?
+ mac_iter = 1
+ password = encryption_algorithm.password
+ else:
+ raise ValueError("Unsupported key encryption type")
+
+ if cas is None or len(cas) == 0:
+ sk_x509 = self._ffi.NULL
+ else:
+ sk_x509 = self._lib.sk_X509_new_null()
+ sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free)
+
+ # reverse the list when building the stack so that they're encoded
+ # in the order they were originally provided. it is a mystery
+ for ca in reversed(cas):
+ res = self._lib.sk_X509_push(sk_x509, ca._x509)
+ backend.openssl_assert(res >= 1)
+
+ with self._zeroed_null_terminated_buf(password) as password_buf:
+ with self._zeroed_null_terminated_buf(name) as name_buf:
+ p12 = self._lib.PKCS12_create(
+ password_buf,
+ name_buf,
+ key._evp_pkey if key else self._ffi.NULL,
+ cert._x509 if cert else self._ffi.NULL,
+ sk_x509,
+ nid_key,
+ nid_cert,
+ pkcs12_iter,
+ mac_iter,
+ 0,
+ )
+
+ self.openssl_assert(p12 != self._ffi.NULL)
+ p12 = self._ffi.gc(p12, self._lib.PKCS12_free)
+
+ bio = self._create_mem_bio_gc()
+ res = self._lib.i2d_PKCS12_bio(bio, p12)
+ self.openssl_assert(res > 0)
+ return self._read_mem_bio(bio)
+
+ def poly1305_supported(self):
+ if self._fips_enabled:
+ return False
+ 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)
+
+ def load_pem_pkcs7_certificates(self, data):
+ utils._check_bytes("data", data)
+ bio = self._bytes_to_bio(data)
+ p7 = self._lib.PEM_read_bio_PKCS7(
+ bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL
+ )
+ if p7 == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Unable to parse PKCS7 data")
+
+ p7 = self._ffi.gc(p7, self._lib.PKCS7_free)
+ return self._load_pkcs7_certificates(p7)
+
+ def load_der_pkcs7_certificates(self, data):
+ utils._check_bytes("data", data)
+ bio = self._bytes_to_bio(data)
+ p7 = self._lib.d2i_PKCS7_bio(bio.bio, self._ffi.NULL)
+ if p7 == self._ffi.NULL:
+ self._consume_errors()
+ raise ValueError("Unable to parse PKCS7 data")
+
+ p7 = self._ffi.gc(p7, self._lib.PKCS7_free)
+ return self._load_pkcs7_certificates(p7)
+
+ def _load_pkcs7_certificates(self, p7):
+ nid = self._lib.OBJ_obj2nid(p7.type)
+ self.openssl_assert(nid != self._lib.NID_undef)
+ if nid != self._lib.NID_pkcs7_signed:
+ raise UnsupportedAlgorithm(
+ "Only basic signed structures are currently supported. NID"
+ " for this data was {}".format(nid),
+ _Reasons.UNSUPPORTED_SERIALIZATION,
+ )
+
+ sk_x509 = p7.d.sign.cert
+ num = self._lib.sk_X509_num(sk_x509)
+ certs = []
+ for i in range(num):
+ x509 = self._lib.sk_X509_value(sk_x509, i)
+ self.openssl_assert(x509 != self._ffi.NULL)
+ res = self._lib.X509_up_ref(x509)
+ # When OpenSSL is less than 1.1.0 up_ref returns the current
+ # refcount. On 1.1.0+ it returns 1 for success.
+ self.openssl_assert(res >= 1)
+ x509 = self._ffi.gc(x509, self._lib.X509_free)
+ certs.append(_Certificate(self, x509))
+
+ return certs
+
+ def pkcs7_sign(self, builder, encoding, options):
+ bio = self._bytes_to_bio(builder._data)
+ init_flags = self._lib.PKCS7_PARTIAL
+ final_flags = 0
+
+ if len(builder._additional_certs) == 0:
+ certs = self._ffi.NULL
+ else:
+ certs = self._lib.sk_X509_new_null()
+ certs = self._ffi.gc(certs, self._lib.sk_X509_free)
+ for cert in builder._additional_certs:
+ res = self._lib.sk_X509_push(certs, cert._x509)
+ self.openssl_assert(res >= 1)
+
+ if pkcs7.PKCS7Options.DetachedSignature in options:
+ # Don't embed the data in the PKCS7 structure
+ init_flags |= self._lib.PKCS7_DETACHED
+ final_flags |= self._lib.PKCS7_DETACHED
+
+ # This just inits a structure for us. However, there
+ # are flags we need to set, joy.
+ p7 = self._lib.PKCS7_sign(
+ self._ffi.NULL,
+ self._ffi.NULL,
+ certs,
+ self._ffi.NULL,
+ init_flags,
+ )
+ self.openssl_assert(p7 != self._ffi.NULL)
+ p7 = self._ffi.gc(p7, self._lib.PKCS7_free)
+ signer_flags = 0
+ # These flags are configurable on a per-signature basis
+ # but we've deliberately chosen to make the API only allow
+ # setting it across all signatures for now.
+ if pkcs7.PKCS7Options.NoCapabilities in options:
+ signer_flags |= self._lib.PKCS7_NOSMIMECAP
+ elif pkcs7.PKCS7Options.NoAttributes in options:
+ signer_flags |= self._lib.PKCS7_NOATTR
+
+ if pkcs7.PKCS7Options.NoCerts in options:
+ signer_flags |= self._lib.PKCS7_NOCERTS
+
+ for certificate, private_key, hash_algorithm in builder._signers:
+ md = self._evp_md_non_null_from_algorithm(hash_algorithm)
+ p7signerinfo = self._lib.PKCS7_sign_add_signer(
+ p7, certificate._x509, private_key._evp_pkey, md, signer_flags
+ )
+ self.openssl_assert(p7signerinfo != self._ffi.NULL)
+
+ for option in options:
+ # DetachedSignature, NoCapabilities, and NoAttributes are already
+ # handled so we just need to check these last two options.
+ if option is pkcs7.PKCS7Options.Text:
+ final_flags |= self._lib.PKCS7_TEXT
+ elif option is pkcs7.PKCS7Options.Binary:
+ final_flags |= self._lib.PKCS7_BINARY
+
+ bio_out = self._create_mem_bio_gc()
+ if encoding is serialization.Encoding.SMIME:
+ # This finalizes the structure
+ res = self._lib.SMIME_write_PKCS7(
+ bio_out, p7, bio.bio, final_flags
+ )
+ elif encoding is serialization.Encoding.PEM:
+ res = self._lib.PKCS7_final(p7, bio.bio, final_flags)
+ self.openssl_assert(res == 1)
+ res = self._lib.PEM_write_bio_PKCS7_stream(
+ bio_out, p7, bio.bio, final_flags
+ )
+ else:
+ assert encoding is serialization.Encoding.DER
+ # We need to call finalize here becauase i2d_PKCS7_bio does not
+ # finalize.
+ res = self._lib.PKCS7_final(p7, bio.bio, final_flags)
+ self.openssl_assert(res == 1)
+ res = self._lib.i2d_PKCS7_bio(bio_out, p7)
+ self.openssl_assert(res == 1)
+ return self._read_mem_bio(bio_out)
+
class GetCipherByName(object):
def __init__(self, fmt):
self._fmt = fmt
def __call__(self, backend, cipher, mode):
cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower()
@@ -3,48 +3,42 @@
# 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
+ 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
+ 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
+ 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()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PublicFormat.SubjectPublicKeyInfo
- ):
- raise ValueError(
- "format must be SubjectPublicKeyInfo when encoding is PEM or "
- "DER"
- )
-
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)
@@ -58,16 +52,19 @@
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
+ 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()
@@ -94,54 +91,51 @@
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
+ 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
+ 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)
+ 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"
+ "and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PrivateFormat.PKCS8
- ):
- raise ValueError(
- "format must be PKCS8 when encoding is PEM or DER"
- )
-
return self._backend._private_key_bytes(
- encoding, format, encryption_algorithm, self._evp_pkey, None
+ 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
@@ -3,26 +3,29 @@
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
- InvalidSignature, UnsupportedAlgorithm, _Reasons
+ InvalidSignature,
+ UnsupportedAlgorithm,
+ _Reasons,
)
-from cryptography.hazmat.primitives import constant_time, mac
+from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.ciphers.modes import CBC
[email protected]_interface(mac.MACContext)
class _CMACContext(object):
def __init__(self, backend, algorithm, ctx=None):
if not backend.cmac_algorithm_supported(algorithm):
- raise UnsupportedAlgorithm("This backend does not support CMAC.",
- _Reasons.UNSUPPORTED_CIPHER)
+ raise UnsupportedAlgorithm(
+ "This backend does not support CMAC.",
+ _Reasons.UNSUPPORTED_CIPHER,
+ )
self._backend = backend
self._key = algorithm.key
self._algorithm = algorithm
self._output_length = algorithm.block_size // 8
if ctx is None:
@@ -34,49 +37,46 @@
ctx = self._backend._lib.CMAC_CTX_new()
self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
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
+ ctx,
+ key_ptr,
+ len(self._key),
+ evp_cipher,
+ self._backend._ffi.NULL,
)
self._backend.openssl_assert(res == 1)
self._ctx = ctx
algorithm = utils.read_only_property("_algorithm")
def update(self, data):
res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
self._backend.openssl_assert(res == 1)
def finalize(self):
buf = self._backend._ffi.new("unsigned char[]", self._output_length)
length = self._backend._ffi.new("size_t *", self._output_length)
- res = self._backend._lib.CMAC_Final(
- self._ctx, buf, length
- )
+ res = self._backend._lib.CMAC_Final(self._ctx, buf, length)
self._backend.openssl_assert(res == 1)
self._ctx = None
return self._backend._ffi.buffer(buf)[:]
def copy(self):
copied_ctx = self._backend._lib.CMAC_CTX_new()
copied_ctx = self._backend._ffi.gc(
copied_ctx, self._backend._lib.CMAC_CTX_free
)
- res = self._backend._lib.CMAC_CTX_copy(
- copied_ctx, self._ctx
- )
+ res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx)
self._backend.openssl_assert(res == 1)
- return _CMACContext(
- self._backend, self._algorithm, ctx=copied_ctx
- )
+ return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx)
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
@@ -13,16 +13,16 @@
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_OPENSSL_LESS_THAN_102:
- # In OpenSSL versions < 1.0.2 or libressl DHparams_dup don't copy q
+ 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
@@ -49,60 +49,43 @@
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
+ 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"
- )
+ 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)
+ 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)
+ _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.")
+ return self._backend._parameter_bytes(encoding, format, self._dh_cdata)
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._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):
@@ -132,89 +115,97 @@
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
+ q=q_val,
),
- y=self._backend._bn_to_int(pub_key[0])
+ y=self._backend._bn_to_int(pub_key[0]),
),
- x=self._backend._bn_to_int(priv_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._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
+ buf, pub_key[0], self._dh_cdata
)
if res == -1:
- errors = self._backend._consume_errors()
- return _handle_dh_compute_key_error(errors, self._backend)
+ errors_with_text = self._backend._consume_errors_with_text()
+ raise ValueError(
+ "Error computing shared key. Public key is likely invalid "
+ "for this exchange.",
+ errors_with_text,
+ )
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._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)
+ 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)
+ 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)
+ _Reasons.UNSUPPORTED_SERIALIZATION,
+ )
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
- self._dh_cdata
+ self._dh_cdata,
)
@utils.register_interface(dh.DHPublicKeyWithSerialization)
class _DHPublicKey(object):
def __init__(self, backend, dh_cdata, evp_pkey):
self._backend = backend
@@ -234,47 +225,47 @@
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._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
+ q=q_val,
),
- y=self._backend._bn_to_int(pub_key[0])
+ 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)
+ 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)
+ _Reasons.UNSUPPORTED_SERIALIZATION,
+ )
return self._backend._public_key_bytes(
- encoding,
- format,
- self,
- self._evp_pkey,
- None
+ encoding, format, self, self._evp_pkey, None
)
@@ -13,28 +13,24 @@
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
- )
+ 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."
- )
+ raise ValueError("Null shared key derived from public/private pair.")
return backend._ffi.buffer(buf, keylen[0])[:]
def _calculate_digest_and_algorithm(backend, data, algorithm):
if not isinstance(algorithm, Prehashed):
hash_ctx = hashes.Hash(algorithm, backend)
@@ -61,9 +57,9 @@
def _warn_sign_verify_deprecated():
warnings.warn(
"signer and verifier have been deprecated. Please use sign "
"and verify instead.",
utils.PersistentlyDeprecated2017,
- stacklevel=3
+ stacklevel=3,
)
@@ -4,50 +4,42 @@
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
+ 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
+ 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
+ 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()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PublicFormat.SubjectPublicKeyInfo
- ):
- raise ValueError(
- "format must be SubjectPublicKeyInfo when encoding is PEM or "
- "DER"
- )
-
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)
@@ -75,45 +67,37 @@
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
- )
+ 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
+ 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)
+ 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"
+ "and encryption_algorithm must be NoEncryption()"
)
return self._raw_private_bytes()
- if (
- encoding in serialization._PEM_DER and
- format is not serialization.PrivateFormat.PKCS8
- ):
- raise ValueError(
- "format must be PKCS8 when encoding is PEM or DER"
- )
-
return self._backend._private_key_bytes(
- encoding, format, encryption_algorithm, self._evp_pkey, None
+ 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
@@ -7,20 +7,23 @@
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
+ _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,
+ 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
@@ -90,15 +93,16 @@
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)
+ 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)
@@ -116,17 +120,19 @@
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')
+ 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')
+ 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
@@ -168,17 +174,16 @@
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._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
@@ -251,15 +256,15 @@
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')
+ 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)
@@ -337,28 +342,35 @@
constraints.pathlen = _encode_asn1_int(
backend, basic_constraints.path_length
)
return constraints
-def _encode_authority_information_access(backend, authority_info_access):
+def _encode_information_access(backend, info_access):
aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null()
backend.openssl_assert(aia != backend._ffi.NULL)
aia = backend._ffi.gc(
- aia, backend._lib.sk_ACCESS_DESCRIPTION_free
+ 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:
+ for access_description in info_access:
ad = backend._lib.ACCESS_DESCRIPTION_new()
method = _txt2obj(
backend, access_description.access_method.dotted_string
)
- gn = _encode_general_name(backend, access_description.access_location)
+ _encode_general_name_preallocated(
+ backend, access_description.access_location, ad.location
+ )
ad.method = method
- ad.location = gn
res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad)
backend.openssl_assert(res >= 1)
return aia
def _encode_general_names(backend, names):
@@ -381,69 +393,68 @@
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):
- gn = backend._lib.GENERAL_NAME_new()
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):
- gn = backend._lib.GENERAL_NAME_new()
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
+ name.value.dotted_string.encode("ascii"), 1
)
backend.openssl_assert(obj != backend._ffi.NULL)
gn.d.registeredID = obj
elif isinstance(name, x509.DirectoryName):
- gn = backend._lib.GENERAL_NAME_new()
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):
- gn = backend._lib.GENERAL_NAME_new()
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)
+ 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)
+ 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):
- gn = backend._lib.GENERAL_NAME_new()
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
+ 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)
@@ -452,37 +463,31 @@
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):
- gn = backend._lib.GENERAL_NAME_new()
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):
- gn = backend._lib.GENERAL_NAME_new()
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)
- )
-
- return gn
+ 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)
@@ -613,34 +618,32 @@
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.AUTHORITY_INFORMATION_ACCESS: _encode_information_access,
+ ExtensionOID.SUBJECT_INFORMATION_ACCESS: _encode_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.AUTHORITY_INFORMATION_ACCESS: _encode_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,
}
@@ -2,50 +2,66 @@
# 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
+ InvalidSignature,
+ UnsupportedAlgorithm,
+ _Reasons,
)
from cryptography.hazmat.backends.openssl.utils import (
- _calculate_digest_and_algorithm, _check_not_prehashed,
- _warn_sign_verify_deprecated
+ _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
+ AsymmetricSignatureContext,
+ AsymmetricVerificationContext,
+ ec,
)
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)
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
+ )
def _ec_key_curve_sn(backend, ec_key):
group = backend._lib.EC_KEY_get0_group(ec_key)
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 "
- "at this time"
+ "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_102U_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)
backend.openssl_assert(curve_name != backend._ffi.NULL)
- sn = backend._ffi.string(curve_name).decode('ascii')
+ sn = backend._ffi.string(curve_name).decode("ascii")
return sn
def _mark_asn1_named_ec_curve(backend, ec_cdata):
"""
Set the named curve flag on the EC_KEY. This causes OpenSSL to
serialize EC keys along with their curve OID which makes
@@ -59,29 +75,29 @@
def _sn_to_elliptic_curve(backend, sn):
try:
return ec._CURVE_TYPES[sn]()
except KeyError:
raise UnsupportedAlgorithm(
"{} is not a supported elliptic curve".format(sn),
- _Reasons.UNSUPPORTED_ELLIPTIC_CURVE
+ _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]]
+ 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:
@@ -123,20 +139,20 @@
)
@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
@@ -152,15 +168,15 @@
if not (
self._backend.elliptic_curve_exchange_algorithm_supported(
algorithm, self.curve
)
):
raise UnsupportedAlgorithm(
"This backend does not support the ECDH algorithm.",
- _Reasons.UNSUPPORTED_EXCHANGE_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"
)
@@ -179,20 +195,15 @@
return self._backend._ffi.buffer(z_buf)[:z_len]
def public_key(self):
group = self._backend._lib.EC_KEY_get0_group(self._ec_key)
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)
- 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
- )
+ public_ec_key = self._backend._ec_key_new_by_curve_nid(curve_nid)
point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key)
self._backend.openssl_assert(point != self._backend._ffi.NULL)
res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point)
self._backend.openssl_assert(res == 1)
@@ -201,44 +212,45 @@
return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey)
def private_numbers(self):
bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key)
private_value = self._backend._bn_to_int(bn)
return ec.EllipticCurvePrivateNumbers(
private_value=private_value,
- public_numbers=self.public_key().public_numbers()
+ public_numbers=self.public_key().public_numbers(),
)
def private_bytes(self, encoding, format, encryption_algorithm):
return self._backend._private_key_bytes(
encoding,
format,
encryption_algorithm,
+ self,
self._evp_pkey,
- self._ec_key
+ 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
@@ -249,35 +261,31 @@
_check_signature_algorithm(signature_algorithm)
_check_not_prehashed(signature_algorithm.algorithm)
return _ECDSAVerificationContext(
self._backend, self, signature, signature_algorithm.algorithm
)
def public_numbers(self):
- get_func, group = (
- self._backend._ec_key_determine_group_get_func(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)
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)
self._backend.openssl_assert(res == 1)
x = self._backend._bn_to_int(bn_x)
y = self._backend._bn_to_int(bn_y)
- return ec.EllipticCurvePublicNumbers(
- x=x,
- y=y,
- curve=self._curve
- )
+ return ec.EllipticCurvePublicNumbers(x=x, y=y, 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
@@ -296,44 +304,33 @@
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
+ 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
- )
+ 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
+ encoding, format, self, 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
)
@@ -3,20 +3,21 @@
# for complete details.
from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import (
- InvalidSignature, UnsupportedAlgorithm, _Reasons
+ InvalidSignature,
+ UnsupportedAlgorithm,
+ _Reasons,
)
-from cryptography.hazmat.primitives import constant_time, hashes, mac
+from cryptography.hazmat.primitives import constant_time, hashes
[email protected]_interface(mac.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:
@@ -25,16 +26,17 @@
ctx = self._backend._ffi.gc(
ctx, self._backend._lib.Cryptography_HMAC_CTX_free
)
evp_md = self._backend._evp_md_from_algorithm(algorithm)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"{} is not a supported hash on this backend".format(
- algorithm.name),
- _Reasons.UNSUPPORTED_HASH
+ algorithm.name
+ ),
+ _Reasons.UNSUPPORTED_HASH,
)
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
)
self._backend.openssl_assert(res != 0)
@@ -57,19 +59,20 @@
def update(self, data):
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)
+ 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.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]]
+ return self._backend._ffi.buffer(buf)[: outlen[0]]
def verify(self, signature):
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
@@ -13,14 +13,15 @@
@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
+ _MAX_CHUNK_SIZE = 2 ** 31 - 1
def __init__(self, backend, cipher, mode, operation):
self._backend = backend
self._cipher = cipher
self._mode = mode
self._operation = operation
self._tag = None
@@ -38,16 +39,17 @@
registry = self._backend._cipher_registry
try:
adapter = registry[type(cipher), type(mode)]
except KeyError:
raise UnsupportedAlgorithm(
"cipher {} in {} mode is not supported "
"by this backend.".format(
- cipher.name, mode.name if mode else mode),
- _Reasons.UNSUPPORTED_CIPHER
+ cipher.name, mode.name if mode else mode
+ ),
+ _Reasons.UNSUPPORTED_CIPHER,
)
evp_cipher = adapter(self._backend, cipher, mode)
if evp_cipher == self._backend._ffi.NULL:
msg = "cipher {0.name} ".format(cipher)
if mode is not None:
msg += "in {0.name} mode ".format(mode)
@@ -66,99 +68,99 @@
elif isinstance(mode, modes.ModeWithNonce):
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
- res = self._backend._lib.EVP_CipherInit_ex(ctx, evp_cipher,
- self._backend._ffi.NULL,
- self._backend._ffi.NULL,
- self._backend._ffi.NULL,
- operation)
+ res = self._backend._lib.EVP_CipherInit_ex(
+ ctx,
+ evp_cipher,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ self._backend._ffi.NULL,
+ operation,
+ )
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)
)
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_AEAD_SET_IVLEN,
- len(iv_nonce), self._backend._ffi.NULL
+ ctx,
+ self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN,
+ len(iv_nonce),
+ self._backend._ffi.NULL,
)
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_AEAD_SET_TAG,
- len(mode.tag), mode.tag
+ ctx,
+ self._backend._lib.EVP_CTRL_AEAD_SET_TAG,
+ len(mode.tag),
+ mode.tag,
)
self._backend.openssl_assert(res != 0)
self._tag = mode.tag
- elif (
- self._operation == self._DECRYPT and
- self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
- not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
- ):
- raise NotImplementedError(
- "delayed passing of GCM tag requires OpenSSL >= 1.0.2."
- " To use this feature please update OpenSSL"
- )
# pass key/iv
res = self._backend._lib.EVP_CipherInit_ex(
ctx,
self._backend._ffi.NULL,
self._backend._ffi.NULL,
self._backend._ffi.from_buffer(cipher.key),
iv_nonce,
- operation
+ operation,
)
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):
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):
+ total_data_len = len(data)
+ if len(buf) < (total_data_len + 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)
- )
+ data_processed = 0
+ total_out = 0
outlen = self._backend._ffi.new("int *")
- 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]
+ baseoutbuf = self._backend._ffi.from_buffer(buf)
+ baseinbuf = self._backend._ffi.from_buffer(data)
- 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"")
+ while data_processed != total_data_len:
+ outbuf = baseoutbuf + total_out
+ inbuf = baseinbuf + data_processed
+ inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed)
+ res = self._backend._lib.EVP_CipherUpdate(
+ self._ctx, outbuf, outlen, inbuf, inlen
+ )
+ self._backend.openssl_assert(res != 0)
+ data_processed += inlen
+ total_out += outlen[0]
+
+ return total_out
+
+ def finalize(self):
if (
- self._operation == self._DECRYPT and
- isinstance(self._mode, modes.ModeWithAuthenticationTag) and
- self.tag is None
+ 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 *")
@@ -168,62 +170,62 @@
if not errors and isinstance(self._mode, modes.GCM):
raise InvalidTag
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
- )
+ self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH,
+ ),
+ errors=errors,
)
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):
+ if (
+ isinstance(self._mode, modes.GCM)
+ and self._operation == self._ENCRYPT
+ ):
tag_buf = self._backend._ffi.new(
"unsigned char[]", self._block_size_bytes
)
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
- self._ctx, self._backend._lib.EVP_CTRL_AEAD_GET_TAG,
- self._block_size_bytes, tag_buf
+ self._ctx,
+ self._backend._lib.EVP_CTRL_AEAD_GET_TAG,
+ self._block_size_bytes,
+ tag_buf,
)
self._backend.openssl_assert(res != 0)
self._tag = self._backend._ffi.buffer(tag_buf)[:]
res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx)
self._backend.openssl_assert(res == 1)
- return self._backend._ffi.buffer(buf)[:outlen[0]]
+ return self._backend._ffi.buffer(buf)[: outlen[0]]
def finalize_with_tag(self, tag):
- if (
- self._backend._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
- not self._backend._lib.CRYPTOGRAPHY_IS_LIBRESSL
- ):
- raise NotImplementedError(
- "finalize_with_tag requires OpenSSL >= 1.0.2. To use this "
- "method please update OpenSSL"
- )
if len(tag) < self._mode._min_tag_length:
raise ValueError(
"Authentication tag must be {} bytes or longer.".format(
- self._mode._min_tag_length)
+ 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._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,
- self._backend._ffi.from_buffer(data), len(data)
+ self._ctx,
+ self._backend._ffi.NULL,
+ outlen,
+ self._backend._ffi.from_buffer(data),
+ len(data),
)
self._backend.openssl_assert(res != 0)
tag = utils.read_only_property("_tag")
@@ -1,14 +1,15 @@
# 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 collections
+import os
import threading
import types
import warnings
import cryptography
from cryptography import utils
from cryptography.exceptions import InternalError
@@ -48,38 +49,49 @@
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
- )
+def _errors_with_text(errors):
+ 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
)
+ )
+
+ return errors_with_text
+
+
+def _consume_errors_with_text(lib):
+ return _errors_with_text(_consume_errors(lib))
+
+
+def _openssl_assert(lib, ok, errors=None):
+ if not ok:
+ if errors is None:
+ errors = _consume_errors(lib)
+ errors_with_text = _errors_with_text(errors)
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
+ errors_with_text,
)
def build_conditional_library(lib, conditional_names):
conditional_lib = types.ModuleType("lib")
conditional_lib._original_lib = lib
excluded_names = set()
@@ -94,14 +106,15 @@
return conditional_lib
class Binding(object):
"""
OpenSSL API wrapper.
"""
+
lib = None
ffi = ffi
_lib_loaded = False
_init_lock = threading.Lock()
_lock_init_lock = threading.Lock()
def __init__(self):
@@ -111,15 +124,15 @@
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:
+ if cls.lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_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:
@@ -137,35 +150,47 @@
def init_static_locks(cls):
with cls._lock_init_lock:
cls._ensure_ffi_initialized()
# Use Python's implementation if available, importing _ssl triggers
# the setup for this.
__import__("_ssl")
- if (not cls.lib.Cryptography_HAS_LOCKING_CALLBACKS or
- 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
res = lib.Cryptography_setup_ssl_threads()
_openssl_assert(cls.lib, res == 1)
def _verify_openssl_version(lib):
if (
- lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_102 and
- not lib.CRYPTOGRAPHY_IS_LIBRESSL
+ lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_110
+ and not lib.CRYPTOGRAPHY_IS_LIBRESSL
):
- warnings.warn(
- "OpenSSL version 1.0.1 is no longer supported by the OpenSSL "
- "project, please upgrade. A future version of cryptography will "
- "drop support for it.",
- utils.CryptographyDeprecationWarning
- )
+ if os.environ.get("CRYPTOGRAPHY_ALLOW_OPENSSL_102"):
+ warnings.warn(
+ "OpenSSL version 1.0.2 is no longer supported by the OpenSSL "
+ "project, please upgrade. The next version of cryptography "
+ "will completely remove support for it.",
+ utils.CryptographyDeprecationWarning,
+ )
+ else:
+ raise RuntimeError(
+ "You are linking against OpenSSL 1.0.2, which is no longer "
+ "supported by the OpenSSL project. To use this version of "
+ "cryptography you need to upgrade to a newer version of "
+ "OpenSSL. For this version only you can also set the "
+ "environment variable CRYPTOGRAPHY_ALLOW_OPENSSL_102 to "
+ "allow OpenSSL 1.0.2."
+ )
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
@@ -9,32 +9,14 @@
return [
"EC_POINT_set_affine_coordinates_GF2m",
"EC_POINT_get_affine_coordinates_GF2m",
"EC_POINT_set_compressed_coordinates_GF2m",
]
-def cryptography_has_ec_1_0_2():
- return [
- "EC_curve_nid2nist",
- ]
-
-
-def cryptography_has_set_ecdh_auto():
- return [
- "SSL_CTX_set_ecdh_auto",
- ]
-
-
-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():
@@ -47,86 +29,30 @@
return [
"SSLv3_method",
"SSLv3_client_method",
"SSLv3_server_method",
]
-def cryptography_has_alpn():
- return [
- "SSL_CTX_set_alpn_protos",
- "SSL_set_alpn_protos",
- "SSL_CTX_set_alpn_select_cb",
- "SSL_get0_alpn_selected",
- ]
-
-
-def cryptography_has_compression():
- return [
- "SSL_get_current_compression",
- "SSL_get_current_expansion",
- "SSL_COMP_get_name",
- ]
-
-
-def cryptography_has_get_server_tmp_key():
- return [
- "SSL_get_server_tmp_key",
- ]
-
-
-def cryptography_has_102_verification_error_codes():
- 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_ERR_HOSTNAME_MISMATCH',
- 'X509_V_ERR_EMAIL_MISMATCH',
- 'X509_V_ERR_IP_ADDRESS_MISMATCH'
- ]
-
-
-def cryptography_has_102_verification_params():
+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",
- "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",
- "SSL_get0_param",
- "X509_CHECK_FLAG_ALWAYS_CHECK_SUBJECT",
- "X509_CHECK_FLAG_NO_WILDCARDS",
- "X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS",
- "X509_CHECK_FLAG_MULTI_LABEL_WILDCARDS",
- "X509_CHECK_FLAG_SINGLE_LABEL_SUBDOMAINS"
]
def cryptography_has_110_verification_params():
- return [
- "X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"
- ]
-
-
-def cryptography_has_x509_v_flag_trusted_first():
- return [
- "X509_V_FLAG_TRUSTED_FIRST",
- ]
-
-
-def cryptography_has_x509_v_flag_partial_chain():
- return [
- "X509_V_FLAG_PARTIAL_CHAIN",
- ]
+ return ["X509_CHECK_FLAG_NEVER_CHECK_SUBJECT"]
def cryptography_has_set_cert_cb():
return [
"SSL_CTX_set_cert_cb",
"SSL_set_cert_cb",
]
@@ -156,26 +82,14 @@
def cryptography_has_scrypt():
return [
"EVP_PBE_scrypt",
]
-def cryptography_has_generic_dtls_method():
- return [
- "DTLS_method",
- "DTLS_server_method",
- "DTLS_client_method",
- "SSL_OP_NO_DTLSv1",
- "SSL_OP_NO_DTLSv1_2",
- "DTLS_set_link_mtu",
- "DTLS_get_link_min_mtu",
- ]
-
-
def cryptography_has_evp_pkey_dhx():
return [
"EVP_PKEY_DHX",
]
def cryptography_has_mem_functions():
@@ -236,14 +150,21 @@
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",
]
@@ -258,15 +179,15 @@
"EVP_PKEY_get1_tls_encodedpoint",
"EVP_PKEY_set1_tls_encodedpoint",
]
def cryptography_has_fips():
return [
- "FIPS_set_mode",
+ "FIPS_mode_set",
"FIPS_mode",
]
def cryptography_has_ssl_sigalgs():
return [
"SSL_CTX_set1_sigalgs_list",
@@ -317,110 +238,108 @@
"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",
+ "ENGINE_ctrl_cmd_string",
+ "ENGINE_load_builtin_engines",
+ "ENGINE_load_private_key",
+ "ENGINE_load_public_key",
+ ]
+
+
+def cryptography_has_verified_chain():
+ return [
+ "SSL_get0_verified_chain",
+ ]
+
+
+def cryptography_has_srtp():
+ return [
+ "SSL_CTX_set_tlsext_use_srtp",
+ "SSL_set_tlsext_use_srtp",
+ "SSL_get_selected_srtp_profile",
]
# 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_EC_1_0_2": cryptography_has_ec_1_0_2,
- "Cryptography_HAS_SET_ECDH_AUTO": cryptography_has_set_ecdh_auto,
- "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_ALPN": cryptography_has_alpn,
- "Cryptography_HAS_COMPRESSION": cryptography_has_compression,
- "Cryptography_HAS_GET_SERVER_TMP_KEY": cryptography_has_get_server_tmp_key,
- "Cryptography_HAS_102_VERIFICATION_ERROR_CODES": (
- cryptography_has_102_verification_error_codes
- ),
- "Cryptography_HAS_102_VERIFICATION_PARAMS": (
- cryptography_has_102_verification_params
- ),
+ "Cryptography_HAS_102_VERIFICATION": cryptography_has_102_verification,
"Cryptography_HAS_110_VERIFICATION_PARAMS": (
cryptography_has_110_verification_params
),
- "Cryptography_HAS_X509_V_FLAG_TRUSTED_FIRST": (
- cryptography_has_x509_v_flag_trusted_first
- ),
- "Cryptography_HAS_X509_V_FLAG_PARTIAL_CHAIN": (
- cryptography_has_x509_v_flag_partial_chain
- ),
"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_GENERIC_DTLS_METHOD": (
- cryptography_has_generic_dtls_method
- ),
"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,
+ "Cryptography_HAS_SRTP": cryptography_has_srtp,
}
@@ -6,16 +6,19 @@
import abc
import six
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HashBackend
@six.add_metaclass(abc.ABCMeta)
class HashAlgorithm(object):
@abc.abstractproperty
def name(self):
@@ -62,19 +65,20 @@
"""
An interface for extendable output functions.
"""
@utils.register_interface(HashContext)
class Hash(object):
- def __init__(self, algorithm, backend, ctx=None):
+ def __init__(self, algorithm, backend=None, ctx=None):
+ backend = _get_backend(backend)
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HashBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not isinstance(algorithm, HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
self._backend = backend
@@ -1,35 +1,14 @@
# 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 hmac
-import warnings
-from cryptography import utils
-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:
- warnings.warn(
- "Support for your Python version is deprecated. The next version of "
- "cryptography will remove support. Please upgrade to a 2.7.x "
- "release that supports hmac.compare_digest as soon as possible.",
- utils.PersistentlyDeprecated2018,
- )
-
- 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)
@@ -2,33 +2,34 @@
# 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
+ AlreadyFinalized,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import CMACBackend
-from cryptography.hazmat.primitives import ciphers, mac
+from cryptography.hazmat.primitives import ciphers
[email protected]_interface(mac.MACContext)
class CMAC(object):
- def __init__(self, algorithm, backend, ctx=None):
+ def __init__(self, algorithm, backend=None, ctx=None):
+ backend = _get_backend(backend)
if not isinstance(backend, CMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement CMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not isinstance(algorithm, ciphers.BlockCipherAlgorithm):
- raise TypeError(
- "Expected instance of BlockCipherAlgorithm."
- )
+ raise TypeError("Expected instance of BlockCipherAlgorithm.")
self._algorithm = algorithm
self._backend = backend
if ctx is None:
self._ctx = self._backend.create_cmac_ctx(self._algorithm)
else:
self._ctx = ctx
@@ -55,11 +56,9 @@
ctx, self._ctx = self._ctx, None
ctx.verify(signature)
def copy(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return CMAC(
- self._algorithm,
- backend=self._backend,
- ctx=self._ctx.copy()
+ self._algorithm, backend=self._backend, ctx=self._ctx.copy()
)
@@ -36,22 +36,22 @@
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)
+ utils._check_byteslike("data", data)
- buffer_ += data
+ buffer_ += bytes(data)
finished_blocks = len(buffer_) // (block_size // 8)
- result = buffer_[:finished_blocks * (block_size // 8)]
- buffer_ = buffer_[finished_blocks * (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.")
@@ -60,22 +60,22 @@
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)
+ utils._check_byteslike("data", data)
- buffer_ += data
+ buffer_ += bytes(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):]
+ 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.")
@@ -109,43 +109,46 @@
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)
+ self._buffer, data, self.block_size
+ )
return result
def _padding(self, size):
return six.int2byte(size) * size
def finalize(self):
result = _byte_padding_pad(
- self._buffer, self.block_size, self._padding)
+ self._buffer, self.block_size, self._padding
+ )
self._buffer = None
return result
@utils.register_interface(PaddingContext)
class _PKCS7UnpaddingContext(object):
def __init__(self, block_size):
self.block_size = block_size
# TODO: more copies than necessary, we should use zero-buffer (#193)
self._buffer = b""
def update(self, data):
self._buffer, result = _byte_unpadding_update(
- self._buffer, data, self.block_size)
+ 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, self.block_size, lib.Cryptography_check_pkcs7_padding
+ )
self._buffer = None
return result
class ANSIX923(object):
def __init__(self, block_size):
_byte_padding_check(block_size)
@@ -163,38 +166,43 @@
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)
+ self._buffer, data, self.block_size
+ )
return result
def _padding(self, size):
return six.int2byte(0) * (size - 1) + six.int2byte(size)
def finalize(self):
result = _byte_padding_pad(
- self._buffer, self.block_size, self._padding)
+ self._buffer, self.block_size, self._padding
+ )
self._buffer = None
return result
@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""
def update(self, data):
self._buffer, result = _byte_unpadding_update(
- self._buffer, data, self.block_size)
+ self._buffer, data, self.block_size
+ )
return result
def finalize(self):
result = _byte_unpadding_check(
- self._buffer, self.block_size,
- lib.Cryptography_check_ansix923_padding)
+ self._buffer,
+ self.block_size,
+ lib.Cryptography_check_ansix923_padding,
+ )
self._buffer = None
return result
@@ -2,28 +2,31 @@
# 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
+ AlreadyFinalized,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HMACBackend
-from cryptography.hazmat.primitives import hashes, mac
+from cryptography.hazmat.primitives import hashes
[email protected]_interface(mac.MACContext)
@utils.register_interface(hashes.HashContext)
class HMAC(object):
- def __init__(self, key, algorithm, backend, ctx=None):
+ def __init__(self, key, algorithm, backend=None, ctx=None):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of hashes.HashAlgorithm.")
self._algorithm = algorithm
self._backend = backend
@@ -44,15 +47,15 @@
def copy(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
return HMAC(
self._key,
self.algorithm,
backend=self._backend,
- ctx=self._ctx.copy()
+ ctx=self._ctx.copy(),
)
def finalize(self):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
@@ -2,14 +2,15 @@
# 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.backends import _get_backend
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):
@@ -29,69 +30,75 @@
r[i] = b[-8:]
assert encryptor.finalize() == b""
return a + b"".join(r)
-def aes_key_wrap(wrapping_key, key_to_wrap, backend):
+def aes_key_wrap(wrapping_key, key_to_wrap, backend=None):
+ backend = _get_backend(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)]
+ 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]
+ 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):
+def aes_key_wrap_with_padding(wrapping_key, key_to_wrap, backend=None):
+ backend = _get_backend(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)]
+ 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):
+def aes_key_unwrap_with_padding(wrapping_key, wrapped_key, backend=None):
+ backend = _get_backend(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:
@@ -99,53 +106,53 @@
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)]
+ 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)
- )
+ 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):
+def aes_key_unwrap(wrapping_key, wrapped_key, backend=None):
+ backend = _get_backend(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)]
+ 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)
@@ -4,28 +4,33 @@
from __future__ import absolute_import, division, print_function
import six
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time, hmac
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
@utils.register_interface(KeyDerivationFunction)
class HKDF(object):
- def __init__(self, algorithm, length, salt, info, backend):
+ def __init__(self, algorithm, length, salt, info, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._algorithm = algorithm
if salt is None:
salt = b"\x00" * self._algorithm.digest_size
else:
@@ -49,32 +54,32 @@
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
@utils.register_interface(KeyDerivationFunction)
class HKDFExpand(object):
- def __init__(self, algorithm, length, info, backend):
+ def __init__(self, algorithm, length, info, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._algorithm = algorithm
self._backend = backend
max_length = 255 * algorithm.digest_size
if length > max_length:
raise ValueError(
- "Can not derive keys larger than {} octets.".format(
- max_length
- ))
+ "Can not derive keys larger than {} octets.".format(max_length)
+ )
self._length = length
if info is None:
info = b""
else:
utils._check_bytes("info", info)
@@ -91,15 +96,15 @@
h = hmac.HMAC(key_material, self._algorithm, backend=self._backend)
h.update(output[-1])
h.update(self._info)
h.update(six.int2byte(counter))
output.append(h.finalize())
counter += 1
- return b"".join(output)[:self._length]
+ return b"".join(output)[: self._length]
def derive(self, key_material):
utils._check_byteslike("key_material", key_material)
if self._used:
raise AlreadyFinalized
self._used = True
@@ -6,16 +6,20 @@
from enum import Enum
from six.moves import range
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
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"
@@ -24,58 +28,71 @@
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):
+ def __init__(
+ self,
+ algorithm,
+ mode,
+ length,
+ rlen,
+ llen,
+ location,
+ label,
+ context,
+ fixed,
+ backend=None,
+ ):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not isinstance(algorithm, hashes.HashAlgorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hash algorithm.",
- _Reasons.UNSUPPORTED_HASH
+ _Reasons.UNSUPPORTED_HASH,
)
if not backend.hmac_supported(algorithm):
raise UnsupportedAlgorithm(
"Algorithm supplied is not a supported hmac algorithm.",
- _Reasons.UNSUPPORTED_HASH
+ _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.")
+ 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''
+ label = b""
if context is None:
- context = b''
+ context = b""
utils._check_bytes("label", label)
utils._check_bytes("context", context)
self._algorithm = algorithm
self._mode = mode
self._length = length
self._rlen = rlen
@@ -85,15 +102,15 @@
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')
+ 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):
@@ -102,23 +119,23 @@
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'']
+ 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.')
+ 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)
@@ -126,15 +143,15 @@
h.update(self._generate_fixed_input())
if self._location == CounterLocation.AfterFixed:
h.update(counter)
output.append(h.finalize())
- return b''.join(output)[:self._length]
+ 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)
@@ -4,44 +4,50 @@
from __future__ import absolute_import, division, print_function
import struct
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
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)
+ return struct.pack(">I", n)
@utils.register_interface(KeyDerivationFunction)
class X963KDF(object):
- def __init__(self, algorithm, length, sharedinfo, backend):
+ def __init__(self, algorithm, length, sharedinfo, backend=None):
+ backend = _get_backend(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))
+ "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
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._backend = backend
self._used = False
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
@@ -57,12 +63,12 @@
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]
+ 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
@@ -4,92 +4,98 @@
from __future__ import absolute_import, division, print_function
import struct
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.backends.interfaces import HashBackend
from cryptography.hazmat.primitives import constant_time, hashes, hmac
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
def _int_to_u32be(n):
- return struct.pack('>I', n)
+ return struct.pack(">I", n)
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 {} bits.".format(
- max_length
- ))
+ "Can not derive keys larger than {} bits.".format(max_length)
+ )
if otherinfo is not None:
utils._check_bytes("otherinfo", otherinfo)
def _concatkdf_derive(key_material, length, auxfn, otherinfo):
utils._check_byteslike("key_material", key_material)
output = [b""]
outlen = 0
counter = 1
- while (length > outlen):
+ while length > outlen:
h = auxfn()
h.update(_int_to_u32be(counter))
h.update(key_material)
h.update(otherinfo)
output.append(h.finalize())
outlen += len(output[-1])
counter += 1
return b"".join(output)[:length]
@utils.register_interface(KeyDerivationFunction)
class ConcatKDFHash(object):
- def __init__(self, algorithm, length, otherinfo, backend):
+ def __init__(self, algorithm, length, otherinfo, backend=None):
+ backend = _get_backend(backend)
_common_args_checks(algorithm, length, otherinfo)
self._algorithm = algorithm
self._length = length
self._otherinfo = otherinfo
if self._otherinfo is None:
self._otherinfo = b""
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HashBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._backend = backend
self._used = False
def _hash(self):
return hashes.Hash(self._algorithm, self._backend)
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
self._used = True
- return _concatkdf_derive(key_material, self._length,
- self._hash, self._otherinfo)
+ return _concatkdf_derive(
+ key_material, self._length, self._hash, self._otherinfo
+ )
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
@utils.register_interface(KeyDerivationFunction)
class ConcatKDFHMAC(object):
- def __init__(self, algorithm, length, salt, otherinfo, backend):
+ def __init__(self, algorithm, length, salt, otherinfo, backend=None):
+ backend = _get_backend(backend)
_common_args_checks(algorithm, length, otherinfo)
self._algorithm = algorithm
self._length = length
self._otherinfo = otherinfo
if self._otherinfo is None:
self._otherinfo = b""
@@ -100,25 +106,26 @@
utils._check_bytes("salt", salt)
self._salt = salt
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._backend = backend
self._used = False
def _hmac(self):
return hmac.HMAC(self._salt, self._algorithm, self._backend)
def derive(self, key_material):
if self._used:
raise AlreadyFinalized
self._used = True
- return _concatkdf_derive(key_material, self._length,
- self._hmac, self._otherinfo)
+ return _concatkdf_derive(
+ key_material, self._length, self._hmac, self._otherinfo
+ )
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
raise InvalidKey
@@ -2,35 +2,41 @@
# 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, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import PBKDF2HMACBackend
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.kdf import KeyDerivationFunction
@utils.register_interface(KeyDerivationFunction)
class PBKDF2HMAC(object):
- def __init__(self, algorithm, length, salt, iterations, backend):
+ def __init__(self, algorithm, length, salt, iterations, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, PBKDF2HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement PBKDF2HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not backend.pbkdf2_hmac_supported(algorithm):
raise UnsupportedAlgorithm(
"{} is not supported for PBKDF2 by this backend.".format(
- algorithm.name),
- _Reasons.UNSUPPORTED_HASH
+ algorithm.name
+ ),
+ _Reasons.UNSUPPORTED_HASH,
)
self._used = False
self._algorithm = algorithm
self._length = length
utils._check_bytes("salt", salt)
self._salt = salt
self._iterations = iterations
@@ -43,14 +49,14 @@
utils._check_byteslike("key_material", key_material)
return self._backend.derive_pbkdf2_hmac(
self._algorithm,
self._length,
self._salt,
self._iterations,
- key_material
+ key_material,
)
def verify(self, key_material, expected_key):
derived_key = self.derive(key_material)
if not constant_time.bytes_eq(derived_key, expected_key):
raise InvalidKey("Keys do not match.")
@@ -4,33 +4,38 @@
from __future__ import absolute_import, division, print_function
import sys
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
+ AlreadyFinalized,
+ InvalidKey,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
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):
+ def __init__(self, salt, length, n, r, p, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, ScryptBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement ScryptBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _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.")
@@ -14,15 +14,15 @@
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
+ exceptions._Reasons.UNSUPPORTED_CIPHER,
)
utils._check_byteslike("key", key)
if len(key) != 32:
raise ValueError("ChaCha20Poly1305 key must be 32 bytes.")
self._key = key
@@ -38,26 +38,22 @@
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
- )
+ 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
- )
+ 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")
@@ -76,20 +72,14 @@
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
- if not backend.aead_cipher_supported(self):
- raise exceptions.UnsupportedAlgorithm(
- "AESCCM is not supported by this version of OpenSSL",
- exceptions._Reasons.UNSUPPORTED_CIPHER
- )
-
@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")
@@ -122,15 +112,15 @@
)
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("Nonce too long for data")
+ 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")
@@ -163,26 +153,22 @@
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
- )
+ 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
- )
+ 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")
@@ -2,28 +2,31 @@
# 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.primitives.ciphers import (
- BlockCipherAlgorithm, CipherAlgorithm
+ 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 ({}) for {}.".format(
- len(key) * 8, algorithm.name
- ))
+ raise ValueError(
+ "Invalid key size ({}) for {}.".format(
+ len(key) * 8, algorithm.name
+ )
+ )
return key
@utils.register_interface(BlockCipherAlgorithm)
@utils.register_interface(CipherAlgorithm)
class AES(object):
name = "AES"
@@ -6,17 +6,21 @@
import abc
import six
from cryptography import utils
from cryptography.exceptions import (
- AlreadyFinalized, AlreadyUpdated, NotYetFinalized, UnsupportedAlgorithm,
- _Reasons
+ AlreadyFinalized,
+ AlreadyUpdated,
+ NotYetFinalized,
+ UnsupportedAlgorithm,
+ _Reasons,
)
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import CipherBackend
from cryptography.hazmat.primitives.ciphers import modes
@six.add_metaclass(abc.ABCMeta)
class CipherAlgorithm(object):
@abc.abstractproperty
@@ -90,19 +94,20 @@
"""
Returns tag bytes. This is only available after encryption is
finalized.
"""
class Cipher(object):
- def __init__(self, algorithm, mode, backend):
+ def __init__(self, algorithm, mode, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, CipherBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement CipherBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
if not isinstance(algorithm, CipherAlgorithm):
raise TypeError("Expected interface of CipherAlgorithm.")
if mode is not None:
mode.validate_for_algorithm(algorithm)
@@ -226,10 +231,11 @@
@utils.register_interface(AEADEncryptionContext)
class _AEADEncryptionContext(_AEADCipherContext):
@property
def tag(self):
if self._ctx is not None:
- raise NotYetFinalized("You must finalize encryption before "
- "getting the tag.")
+ raise NotYetFinalized(
+ "You must finalize encryption before " "getting the tag."
+ )
return self._tag
@@ -68,17 +68,19 @@
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 ({}) for {}.".format(
- len(self.initialization_vector), self.name
- ))
+ 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)
@@ -174,17 +176,19 @@
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 ({}) for {}.".format(
- len(self.nonce), self.name
- ))
+ raise ValueError(
+ "Invalid nonce size ({}) for {}.".format(
+ len(self.nonce), self.name
+ )
+ )
@utils.register_interface(Mode)
@utils.register_interface(ModeWithInitializationVector)
@utils.register_interface(ModeWithAuthenticationTag)
class GCM(object):
name = "GCM"
@@ -202,15 +206,16 @@
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)
+ 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")
@@ -1,16 +1,21 @@
# 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.ciphers.base import (
- AEADCipherContext, AEADDecryptionContext, AEADEncryptionContext,
- BlockCipherAlgorithm, Cipher, CipherAlgorithm, CipherContext
+ AEADCipherContext,
+ AEADDecryptionContext,
+ AEADEncryptionContext,
+ BlockCipherAlgorithm,
+ Cipher,
+ CipherAlgorithm,
+ CipherContext,
)
__all__ = [
"Cipher",
"CipherAlgorithm",
"BlockCipherAlgorithm",
@@ -1,9 +1,50 @@
# 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 x509
+from cryptography.hazmat.backends import _get_backend
+from cryptography.hazmat.primitives import serialization
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
-def load_key_and_certificates(data, password, backend):
+
+def load_key_and_certificates(data, password, backend=None):
+ backend = _get_backend(backend)
return backend.load_key_and_certificates_from_pkcs12(data, password)
+
+
+def serialize_key_and_certificates(name, key, cert, cas, encryption_algorithm):
+ if key is not None and not isinstance(
+ key,
+ (
+ rsa.RSAPrivateKeyWithSerialization,
+ dsa.DSAPrivateKeyWithSerialization,
+ ec.EllipticCurvePrivateKeyWithSerialization,
+ ),
+ ):
+ raise TypeError("Key must be RSA, DSA, or EllipticCurve private key.")
+ if cert is not None and not isinstance(cert, x509.Certificate):
+ raise TypeError("cert must be a certificate")
+
+ if cas is not None:
+ cas = list(cas)
+ if not all(isinstance(val, x509.Certificate) for val in cas):
+ raise TypeError("all values in cas must be certificates")
+
+ if not isinstance(
+ encryption_algorithm, serialization.KeySerializationEncryption
+ ):
+ raise TypeError(
+ "Key encryption algorithm must be a "
+ "KeySerializationEncryption instance"
+ )
+
+ if key is None and cert is None and not cas:
+ raise ValueError("You must supply at least one of key, cert, or cas")
+
+ backend = _get_backend(None)
+ return backend.serialize_key_and_certificates_to_pkcs12(
+ name, key, cert, cas, encryption_algorithm
+ )
@@ -6,52 +6,61 @@
import abc
from enum import Enum
import six
from cryptography import utils
+from cryptography.hazmat.backends import _get_backend
-def load_pem_private_key(data, password, backend):
+def load_pem_private_key(data, password, backend=None):
+ backend = _get_backend(backend)
return backend.load_pem_private_key(data, password)
-def load_pem_public_key(data, backend):
+def load_pem_public_key(data, backend=None):
+ backend = _get_backend(backend)
return backend.load_pem_public_key(data)
-def load_pem_parameters(data, backend):
+def load_pem_parameters(data, backend=None):
+ backend = _get_backend(backend)
return backend.load_pem_parameters(data)
-def load_der_private_key(data, password, backend):
+def load_der_private_key(data, password, backend=None):
+ backend = _get_backend(backend)
return backend.load_der_private_key(data, password)
-def load_der_public_key(data, backend):
+def load_der_public_key(data, backend=None):
+ backend = _get_backend(backend)
return backend.load_der_public_key(data)
-def load_der_parameters(data, backend):
+def load_der_parameters(data, backend=None):
+ backend = _get_backend(backend)
return backend.load_der_parameters(data)
class Encoding(Enum):
PEM = "PEM"
DER = "DER"
OpenSSH = "OpenSSH"
Raw = "Raw"
X962 = "ANSI X9.62"
+ SMIME = "S/MIME"
class PrivateFormat(Enum):
PKCS8 = "PKCS8"
TraditionalOpenSSL = "TraditionalOpenSSL"
Raw = "Raw"
+ OpenSSH = "OpenSSH"
class PublicFormat(Enum):
SubjectPublicKeyInfo = "X.509 subjectPublicKeyInfo with PKCS#1"
PKCS1 = "Raw PKCS#1"
OpenSSH = "OpenSSH"
Raw = "Raw"
@@ -1,26 +1,44 @@
# 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,
+ 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
+ load_ssh_private_key,
+ load_ssh_public_key,
)
-_PEM_DER = (Encoding.PEM, Encoding.DER)
-
__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",
+ "load_der_parameters",
+ "load_der_private_key",
+ "load_der_public_key",
+ "load_pem_parameters",
+ "load_pem_private_key",
+ "load_pem_public_key",
+ "load_ssh_private_key",
+ "load_ssh_public_key",
+ "Encoding",
+ "PrivateFormat",
+ "PublicFormat",
+ "ParameterFormat",
+ "KeySerializationEncryption",
+ "BestAvailableEncryption",
"NoEncryption",
]
@@ -1,153 +1,683 @@
# 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 binascii
+import os
+import re
import struct
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.backends import _get_backend
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:
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.primitives.serialization import (
+ Encoding,
+ NoEncryption,
+ PrivateFormat,
+ PublicFormat,
+)
+
+try:
+ from bcrypt import kdf as _bcrypt_kdf
+
+ _bcrypt_supported = True
+except ImportError:
+ _bcrypt_supported = False
+
+ def _bcrypt_kdf(*args, **kwargs):
+ raise UnsupportedAlgorithm("Need bcrypt module")
+
+
+try:
+ from base64 import encodebytes as _base64_encode
+except ImportError:
+ from base64 import encodestring as _base64_encode
+
+_SSH_ED25519 = b"ssh-ed25519"
+_SSH_RSA = b"ssh-rsa"
+_SSH_DSA = b"ssh-dss"
+_ECDSA_NISTP256 = b"ecdsa-sha2-nistp256"
+_ECDSA_NISTP384 = b"ecdsa-sha2-nistp384"
+_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521"
+_CERT_SUFFIX = b"[email protected]"
+
+_SSH_PUBKEY_RC = re.compile(br"\A(\S+)[ \t]+(\S+)")
+_SK_MAGIC = b"openssh-key-v1\0"
+_SK_START = b"-----BEGIN OPENSSH PRIVATE KEY-----"
+_SK_END = b"-----END OPENSSH PRIVATE KEY-----"
+_BCRYPT = b"bcrypt"
+_NONE = b"none"
+_DEFAULT_CIPHER = b"aes256-ctr"
+_DEFAULT_ROUNDS = 16
+_MAX_PASSWORD = 72
+
+# re is only way to work on bytes-like data
+_PEM_RC = re.compile(_SK_START + b"(.*?)" + _SK_END, re.DOTALL)
+
+# padding for max blocksize
+_PADDING = memoryview(bytearray(range(1, 1 + 16)))
+
+# ciphers that are actually used in key wrapping
+_SSH_CIPHERS = {
+ b"aes256-ctr": (algorithms.AES, 32, modes.CTR, 16),
+ b"aes256-cbc": (algorithms.AES, 32, modes.CBC, 16),
+}
+
+# map local curve name to key type
+_ECDSA_KEY_TYPE = {
+ "secp256r1": _ECDSA_NISTP256,
+ "secp384r1": _ECDSA_NISTP384,
+ "secp521r1": _ECDSA_NISTP521,
+}
+
+_U32 = struct.Struct(b">I")
+_U64 = struct.Struct(b">Q")
+
+
+def _ecdsa_key_type(public_key):
+ """Return SSH key_type and curve_name for private key."""
+ curve = public_key.curve
+ if curve.name not in _ECDSA_KEY_TYPE:
raise ValueError(
- 'Key header and key body contain different key type values.'
+ "Unsupported curve for ssh private key: %r" % curve.name
)
-
- return loader(key_type, rest, backend)
+ return _ECDSA_KEY_TYPE[curve.name]
-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)
+def _ssh_pem_encode(data, prefix=_SK_START + b"\n", suffix=_SK_END + b"\n"):
+ return b"".join([prefix, _base64_encode(data), suffix])
- if rest:
- raise ValueError('Key body contains extra bytes.')
- return rsa.RSAPublicNumbers(e, n).public_key(backend)
+def _check_block_size(data, block_len):
+ """Require data to be full blocks"""
+ if not data or len(data) % block_len != 0:
+ raise ValueError("Corrupt data: missing padding")
-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)
+def _check_empty(data):
+ """All data should have been parsed."""
+ if data:
+ raise ValueError("Corrupt data: unparsed data")
- if rest:
- raise ValueError('Key body contains extra bytes.')
- parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
- public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
+def _init_cipher(ciphername, password, salt, rounds, backend):
+ """Generate key + iv and return cipher."""
+ if not password:
+ raise ValueError("Key is password-protected.")
- return public_numbers.public_key(backend)
+ algo, key_len, mode, iv_len = _SSH_CIPHERS[ciphername]
+ seed = _bcrypt_kdf(password, salt, key_len + iv_len, rounds, True)
+ return Cipher(algo(seed[:key_len]), mode(seed[key_len:]), 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.'
- )
+def _get_u32(data):
+ """Uint32"""
+ if len(data) < 4:
+ raise ValueError("Invalid data")
+ return _U32.unpack(data[:4])[0], data[4:]
- if rest:
- raise ValueError('Key body contains extra bytes.')
- curve = {
- b"nistp256": ec.SECP256R1,
- b"nistp384": ec.SECP384R1,
- b"nistp521": ec.SECP521R1,
- }[curve_name]()
+def _get_u64(data):
+ """Uint64"""
+ if len(data) < 8:
+ raise ValueError("Invalid data")
+ return _U64.unpack(data[:8])[0], data[8:]
+
+
+def _get_sshstr(data):
+ """Bytes with u32 length prefix"""
+ n, data = _get_u32(data)
+ if n > len(data):
+ raise ValueError("Invalid data")
+ return data[:n], data[n:]
+
+
+def _get_mpint(data):
+ """Big integer."""
+ val, data = _get_sshstr(data)
+ if val and six.indexbytes(val, 0) > 0x7F:
+ raise ValueError("Invalid data")
+ return utils.int_from_bytes(val, "big"), data
+
+
+def _to_mpint(val):
+ """Storage format for signed bigint."""
+ if val < 0:
+ raise ValueError("negative mpint not allowed")
+ if not val:
+ return b""
+ nbytes = (val.bit_length() + 8) // 8
+ return utils.int_to_bytes(val, nbytes)
+
+
+class _FragList(object):
+ """Build recursive structure without data copy."""
+
+ def __init__(self, init=None):
+ self.flist = []
+ if init:
+ self.flist.extend(init)
+
+ def put_raw(self, val):
+ """Add plain bytes"""
+ self.flist.append(val)
+
+ def put_u32(self, val):
+ """Big-endian uint32"""
+ self.flist.append(_U32.pack(val))
+
+ def put_sshstr(self, val):
+ """Bytes prefixed with u32 length"""
+ if isinstance(val, (bytes, memoryview, bytearray)):
+ self.put_u32(len(val))
+ self.flist.append(val)
+ else:
+ self.put_u32(val.size())
+ self.flist.extend(val.flist)
+
+ def put_mpint(self, val):
+ """Big-endian bigint prefixed with u32 length"""
+ self.put_sshstr(_to_mpint(val))
+
+ def size(self):
+ """Current number of bytes"""
+ return sum(map(len, self.flist))
+
+ def render(self, dstbuf, pos=0):
+ """Write into bytearray"""
+ for frag in self.flist:
+ flen = len(frag)
+ start, pos = pos, pos + flen
+ dstbuf[start:pos] = frag
+ return pos
+
+ def tobytes(self):
+ """Return as bytes"""
+ buf = memoryview(bytearray(self.size()))
+ self.render(buf)
+ return buf.tobytes()
+
+
+class _SSHFormatRSA(object):
+ """Format for RSA keys.
+
+ Public:
+ mpint e, n
+ Private:
+ mpint n, e, d, iqmp, p, q
+ """
- if six.indexbytes(data, 0) != 4:
- raise NotImplementedError(
- "Compressed elliptic curve points are not supported"
+ def get_public(self, data):
+ """RSA public fields"""
+ e, data = _get_mpint(data)
+ n, data = _get_mpint(data)
+ return (e, n), data
+
+ def load_public(self, key_type, data, backend):
+ """Make RSA public key from data."""
+ (e, n), data = self.get_public(data)
+ public_numbers = rsa.RSAPublicNumbers(e, n)
+ public_key = public_numbers.public_key(backend)
+ return public_key, data
+
+ def load_private(self, data, pubfields, backend):
+ """Make RSA private key from data."""
+ n, data = _get_mpint(data)
+ e, data = _get_mpint(data)
+ d, data = _get_mpint(data)
+ iqmp, data = _get_mpint(data)
+ p, data = _get_mpint(data)
+ q, data = _get_mpint(data)
+
+ if (e, n) != pubfields:
+ raise ValueError("Corrupt data: rsa field mismatch")
+ dmp1 = rsa.rsa_crt_dmp1(d, p)
+ dmq1 = rsa.rsa_crt_dmq1(d, q)
+ public_numbers = rsa.RSAPublicNumbers(e, n)
+ private_numbers = rsa.RSAPrivateNumbers(
+ p, q, d, dmp1, dmq1, iqmp, public_numbers
)
+ private_key = private_numbers.private_key(backend)
+ return private_key, data
- 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)
+ def encode_public(self, public_key, f_pub):
+ """Write RSA public key"""
+ pubn = public_key.public_numbers()
+ f_pub.put_mpint(pubn.e)
+ f_pub.put_mpint(pubn.n)
+
+ def encode_private(self, private_key, f_priv):
+ """Write RSA private key"""
+ private_numbers = private_key.private_numbers()
+ public_numbers = private_numbers.public_numbers
+
+ f_priv.put_mpint(public_numbers.n)
+ f_priv.put_mpint(public_numbers.e)
+
+ f_priv.put_mpint(private_numbers.d)
+ f_priv.put_mpint(private_numbers.iqmp)
+ f_priv.put_mpint(private_numbers.p)
+ f_priv.put_mpint(private_numbers.q)
+
+
+class _SSHFormatDSA(object):
+ """Format for DSA keys.
+
+ Public:
+ mpint p, q, g, y
+ Private:
+ mpint p, q, g, y, x
+ """
- if rest:
- raise ValueError('Key body contains extra bytes.')
+ def get_public(self, data):
+ """DSA public fields"""
+ p, data = _get_mpint(data)
+ q, data = _get_mpint(data)
+ g, data = _get_mpint(data)
+ y, data = _get_mpint(data)
+ return (p, q, g, y), data
+
+ def load_public(self, key_type, data, backend):
+ """Make DSA public key from data."""
+ (p, q, g, y), data = self.get_public(data)
+ parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
+ public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
+ self._validate(public_numbers)
+ public_key = public_numbers.public_key(backend)
+ return public_key, data
+
+ def load_private(self, data, pubfields, backend):
+ """Make DSA private key from data."""
+ (p, q, g, y), data = self.get_public(data)
+ x, data = _get_mpint(data)
+
+ if (p, q, g, y) != pubfields:
+ raise ValueError("Corrupt data: dsa field mismatch")
+ parameter_numbers = dsa.DSAParameterNumbers(p, q, g)
+ public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers)
+ self._validate(public_numbers)
+ private_numbers = dsa.DSAPrivateNumbers(x, public_numbers)
+ private_key = private_numbers.private_key(backend)
+ return private_key, data
+
+ def encode_public(self, public_key, f_pub):
+ """Write DSA public key"""
+ public_numbers = public_key.public_numbers()
+ parameter_numbers = public_numbers.parameter_numbers
+ self._validate(public_numbers)
+
+ f_pub.put_mpint(parameter_numbers.p)
+ f_pub.put_mpint(parameter_numbers.q)
+ f_pub.put_mpint(parameter_numbers.g)
+ f_pub.put_mpint(public_numbers.y)
+
+ def encode_private(self, private_key, f_priv):
+ """Write DSA private key"""
+ self.encode_public(private_key.public_key(), f_priv)
+ f_priv.put_mpint(private_key.private_numbers().x)
+
+ def _validate(self, public_numbers):
+ parameter_numbers = public_numbers.parameter_numbers
+ if parameter_numbers.p.bit_length() != 1024:
+ raise ValueError("SSH supports only 1024 bit DSA keys")
+
+
+class _SSHFormatECDSA(object):
+ """Format for ECDSA keys.
+
+ Public:
+ str curve
+ bytes point
+ Private:
+ str curve
+ bytes point
+ mpint secret
+ """
- return ed25519.Ed25519PublicKey.from_public_bytes(data)
+ def __init__(self, ssh_curve_name, curve):
+ self.ssh_curve_name = ssh_curve_name
+ self.curve = curve
+
+ def get_public(self, data):
+ """ECDSA public fields"""
+ curve, data = _get_sshstr(data)
+ point, data = _get_sshstr(data)
+ if curve != self.ssh_curve_name:
+ raise ValueError("Curve name mismatch")
+ if six.indexbytes(point, 0) != 4:
+ raise NotImplementedError("Need uncompressed point")
+ return (curve, point), data
+
+ def load_public(self, key_type, data, backend):
+ """Make ECDSA public key from data."""
+ (curve_name, point), data = self.get_public(data)
+ public_key = ec.EllipticCurvePublicKey.from_encoded_point(
+ self.curve, point.tobytes()
+ )
+ return public_key, data
+ def load_private(self, data, pubfields, backend):
+ """Make ECDSA private key from data."""
+ (curve_name, point), data = self.get_public(data)
+ secret, data = _get_mpint(data)
+
+ if (curve_name, point) != pubfields:
+ raise ValueError("Corrupt data: ecdsa field mismatch")
+ private_key = ec.derive_private_key(secret, self.curve, backend)
+ return private_key, data
+
+ def encode_public(self, public_key, f_pub):
+ """Write ECDSA public key"""
+ point = public_key.public_bytes(
+ Encoding.X962, PublicFormat.UncompressedPoint
+ )
+ f_pub.put_sshstr(self.ssh_curve_name)
+ f_pub.put_sshstr(point)
-def _ssh_read_next_string(data):
+ def encode_private(self, private_key, f_priv):
+ """Write ECDSA private key"""
+ public_key = private_key.public_key()
+ private_numbers = private_key.private_numbers()
+
+ self.encode_public(public_key, f_priv)
+ f_priv.put_mpint(private_numbers.private_value)
+
+
+class _SSHFormatEd25519(object):
+ """Format for Ed25519 keys.
+
+ Public:
+ bytes point
+ Private:
+ bytes point
+ bytes secret_and_point
"""
- 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")
+ def get_public(self, data):
+ """Ed25519 public fields"""
+ point, data = _get_sshstr(data)
+ return (point,), data
+
+ def load_public(self, key_type, data, backend):
+ """Make Ed25519 public key from data."""
+ (point,), data = self.get_public(data)
+ public_key = ed25519.Ed25519PublicKey.from_public_bytes(
+ point.tobytes()
+ )
+ return public_key, data
- str_len, = struct.unpack('>I', data[:4])
- if len(data) < str_len + 4:
- raise ValueError("Key is not in the proper format")
+ def load_private(self, data, pubfields, backend):
+ """Make Ed25519 private key from data."""
+ (point,), data = self.get_public(data)
+ keypair, data = _get_sshstr(data)
+
+ secret = keypair[:32]
+ point2 = keypair[32:]
+ if point != point2 or (point,) != pubfields:
+ raise ValueError("Corrupt data: ed25519 field mismatch")
+ private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret)
+ return private_key, data
+
+ def encode_public(self, public_key, f_pub):
+ """Write Ed25519 public key"""
+ raw_public_key = public_key.public_bytes(
+ Encoding.Raw, PublicFormat.Raw
+ )
+ f_pub.put_sshstr(raw_public_key)
- return data[4:4 + str_len], data[4 + str_len:]
+ def encode_private(self, private_key, f_priv):
+ """Write Ed25519 private key"""
+ public_key = private_key.public_key()
+ raw_private_key = private_key.private_bytes(
+ Encoding.Raw, PrivateFormat.Raw, NoEncryption()
+ )
+ raw_public_key = public_key.public_bytes(
+ Encoding.Raw, PublicFormat.Raw
+ )
+ f_keypair = _FragList([raw_private_key, raw_public_key])
+ self.encode_public(public_key, f_priv)
+ f_priv.put_sshstr(f_keypair)
-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)
+_KEY_FORMATS = {
+ _SSH_RSA: _SSHFormatRSA(),
+ _SSH_DSA: _SSHFormatDSA(),
+ _SSH_ED25519: _SSHFormatEd25519(),
+ _ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()),
+ _ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()),
+ _ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()),
+}
+
+
+def _lookup_kformat(key_type):
+ """Return valid format or throw error"""
+ if not isinstance(key_type, bytes):
+ key_type = memoryview(key_type).tobytes()
+ if key_type in _KEY_FORMATS:
+ return _KEY_FORMATS[key_type]
+ raise UnsupportedAlgorithm("Unsupported key type: %r" % key_type)
+
+
+def load_ssh_private_key(data, password, backend=None):
+ """Load private key from OpenSSH custom encoding."""
+ utils._check_byteslike("data", data)
+ backend = _get_backend(backend)
+ if password is not None:
+ utils._check_bytes("password", password)
+
+ m = _PEM_RC.search(data)
+ if not m:
+ raise ValueError("Not OpenSSH private key format")
+ p1 = m.start(1)
+ p2 = m.end(1)
+ data = binascii.a2b_base64(memoryview(data)[p1:p2])
+ if not data.startswith(_SK_MAGIC):
+ raise ValueError("Not OpenSSH private key format")
+ data = memoryview(data)[len(_SK_MAGIC) :]
+
+ # parse header
+ ciphername, data = _get_sshstr(data)
+ kdfname, data = _get_sshstr(data)
+ kdfoptions, data = _get_sshstr(data)
+ nkeys, data = _get_u32(data)
+ if nkeys != 1:
+ raise ValueError("Only one key supported")
+
+ # load public key data
+ pubdata, data = _get_sshstr(data)
+ pub_key_type, pubdata = _get_sshstr(pubdata)
+ kformat = _lookup_kformat(pub_key_type)
+ pubfields, pubdata = kformat.get_public(pubdata)
+ _check_empty(pubdata)
+
+ # load secret data
+ edata, data = _get_sshstr(data)
+ _check_empty(data)
+
+ if (ciphername, kdfname) != (_NONE, _NONE):
+ ciphername = ciphername.tobytes()
+ if ciphername not in _SSH_CIPHERS:
+ raise UnsupportedAlgorithm("Unsupported cipher: %r" % ciphername)
+ if kdfname != _BCRYPT:
+ raise UnsupportedAlgorithm("Unsupported KDF: %r" % kdfname)
+ blklen = _SSH_CIPHERS[ciphername][3]
+ _check_block_size(edata, blklen)
+ salt, kbuf = _get_sshstr(kdfoptions)
+ rounds, kbuf = _get_u32(kbuf)
+ _check_empty(kbuf)
+ ciph = _init_cipher(
+ ciphername, password, salt.tobytes(), rounds, backend
+ )
+ edata = memoryview(ciph.decryptor().update(edata))
+ else:
+ blklen = 8
+ _check_block_size(edata, blklen)
+ ck1, edata = _get_u32(edata)
+ ck2, edata = _get_u32(edata)
+ if ck1 != ck2:
+ raise ValueError("Corrupt data: broken checksum")
+
+ # load per-key struct
+ key_type, edata = _get_sshstr(edata)
+ if key_type != pub_key_type:
+ raise ValueError("Corrupt data: key type mismatch")
+ private_key, edata = kformat.load_private(edata, pubfields, backend)
+ comment, edata = _get_sshstr(edata)
+
+ # yes, SSH does padding check *after* all other parsing is done.
+ # need to follow as it writes zero-byte padding too.
+ if edata != _PADDING[: len(edata)]:
+ raise ValueError("Corrupt data: invalid padding")
+
+ return private_key
+
+
+def serialize_ssh_private_key(private_key, password=None):
+ """Serialize private key with OpenSSH custom encoding."""
+ if password is not None:
+ utils._check_bytes("password", password)
+ if password and len(password) > _MAX_PASSWORD:
+ raise ValueError(
+ "Passwords longer than 72 bytes are not supported by "
+ "OpenSSH private key format"
+ )
- return (
- utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
- )
+ if isinstance(private_key, ec.EllipticCurvePrivateKey):
+ key_type = _ecdsa_key_type(private_key.public_key())
+ elif isinstance(private_key, rsa.RSAPrivateKey):
+ key_type = _SSH_RSA
+ elif isinstance(private_key, dsa.DSAPrivateKey):
+ key_type = _SSH_DSA
+ elif isinstance(private_key, ed25519.Ed25519PrivateKey):
+ key_type = _SSH_ED25519
+ else:
+ raise ValueError("Unsupported key type")
+ kformat = _lookup_kformat(key_type)
+ # setup parameters
+ f_kdfoptions = _FragList()
+ if password:
+ ciphername = _DEFAULT_CIPHER
+ blklen = _SSH_CIPHERS[ciphername][3]
+ kdfname = _BCRYPT
+ rounds = _DEFAULT_ROUNDS
+ salt = os.urandom(16)
+ f_kdfoptions.put_sshstr(salt)
+ f_kdfoptions.put_u32(rounds)
+ backend = _get_backend(None)
+ ciph = _init_cipher(ciphername, password, salt, rounds, backend)
+ else:
+ ciphername = kdfname = _NONE
+ blklen = 8
+ ciph = None
+ nkeys = 1
+ checkval = os.urandom(4)
+ comment = b""
+
+ # encode public and private parts together
+ f_public_key = _FragList()
+ f_public_key.put_sshstr(key_type)
+ kformat.encode_public(private_key.public_key(), f_public_key)
+
+ f_secrets = _FragList([checkval, checkval])
+ f_secrets.put_sshstr(key_type)
+ kformat.encode_private(private_key, f_secrets)
+ f_secrets.put_sshstr(comment)
+ f_secrets.put_raw(_PADDING[: blklen - (f_secrets.size() % blklen)])
+
+ # top-level structure
+ f_main = _FragList()
+ f_main.put_raw(_SK_MAGIC)
+ f_main.put_sshstr(ciphername)
+ f_main.put_sshstr(kdfname)
+ f_main.put_sshstr(f_kdfoptions)
+ f_main.put_u32(nkeys)
+ f_main.put_sshstr(f_public_key)
+ f_main.put_sshstr(f_secrets)
+
+ # copy result info bytearray
+ slen = f_secrets.size()
+ mlen = f_main.size()
+ buf = memoryview(bytearray(mlen + blklen))
+ f_main.render(buf)
+ ofs = mlen - slen
+
+ # encrypt in-place
+ if ciph is not None:
+ ciph.encryptor().update_into(buf[ofs:mlen], buf[ofs:])
+
+ txt = _ssh_pem_encode(buf[:mlen])
+ buf[ofs:mlen] = bytearray(slen)
+ return txt
+
+
+def load_ssh_public_key(data, backend=None):
+ """Load public key from OpenSSH one-line format."""
+ backend = _get_backend(backend)
+ utils._check_byteslike("data", data)
+
+ m = _SSH_PUBKEY_RC.match(data)
+ if not m:
+ raise ValueError("Invalid line format")
+ key_type = orig_key_type = m.group(1)
+ key_body = m.group(2)
+ with_cert = False
+ if _CERT_SUFFIX == key_type[-len(_CERT_SUFFIX) :]:
+ with_cert = True
+ key_type = key_type[: -len(_CERT_SUFFIX)]
+ kformat = _lookup_kformat(key_type)
-def _ssh_write_string(data):
- return struct.pack(">I", len(data)) + data
+ try:
+ data = memoryview(binascii.a2b_base64(key_body))
+ except (TypeError, binascii.Error):
+ raise ValueError("Invalid key format")
+
+ inner_key_type, data = _get_sshstr(data)
+ if inner_key_type != orig_key_type:
+ raise ValueError("Invalid key format")
+ if with_cert:
+ nonce, data = _get_sshstr(data)
+ public_key, data = kformat.load_public(key_type, data, backend)
+ if with_cert:
+ serial, data = _get_u64(data)
+ cctype, data = _get_u32(data)
+ key_id, data = _get_sshstr(data)
+ principals, data = _get_sshstr(data)
+ valid_after, data = _get_u64(data)
+ valid_before, data = _get_u64(data)
+ crit_options, data = _get_sshstr(data)
+ extensions, data = _get_sshstr(data)
+ reserved, data = _get_sshstr(data)
+ sig_key, data = _get_sshstr(data)
+ signature, data = _get_sshstr(data)
+ _check_empty(data)
+ return public_key
+
+
+def serialize_ssh_public_key(public_key):
+ """One-line public key format for OpenSSH"""
+ if isinstance(public_key, ec.EllipticCurvePublicKey):
+ key_type = _ecdsa_key_type(public_key)
+ elif isinstance(public_key, rsa.RSAPublicKey):
+ key_type = _SSH_RSA
+ elif isinstance(public_key, dsa.DSAPublicKey):
+ key_type = _SSH_DSA
+ elif isinstance(public_key, ed25519.Ed25519PublicKey):
+ key_type = _SSH_ED25519
+ else:
+ raise ValueError("Unsupported key type")
+ kformat = _lookup_kformat(key_type)
+ f_pub = _FragList()
+ f_pub.put_sshstr(key_type)
+ kformat.encode_public(public_key, f_pub)
-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)
+ pub = binascii.b2a_base64(f_pub.tobytes()).strip()
+ return b"".join([key_type, b" ", pub])
@@ -19,12 +19,15 @@
if issuer is not None:
parameters.append(("issuer", issuer))
parameters.extend(extra_parameters)
uriparts = {
"type": type_name,
- "label": ("%s:%s" % (quote(issuer), quote(account_name)) if issuer
- else quote(account_name)),
+ "label": (
+ "%s:%s" % (quote(issuer), quote(account_name))
+ if issuer
+ else quote(account_name)
+ ),
"parameters": urlencode(parameters),
}
return "otpauth://{type}/{label}?{parameters}".format(**uriparts)
@@ -4,31 +4,32 @@
from __future__ import absolute_import, division, print_function
import struct
import six
-from cryptography.exceptions import (
- UnsupportedAlgorithm, _Reasons
-)
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time, hmac
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512
from cryptography.hazmat.primitives.twofactor import InvalidToken
from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class HOTP(object):
- def __init__(self, key, length, algorithm, backend,
- enforce_key_length=True):
+ def __init__(
+ self, key, length, algorithm, backend=None, enforce_key_length=True
+ ):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
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):
raise TypeError("Length parameter must be an integer type.")
@@ -55,14 +56,14 @@
def _dynamic_truncate(self, counter):
ctx = hmac.HMAC(self._key, self._algorithm, self._backend)
ctx.update(struct.pack(">Q", counter))
hmac_value = ctx.finalize()
offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
- p = hmac_value[offset:offset + 4]
- return struct.unpack(">I", p)[0] & 0x7fffffff
+ p = hmac_value[offset : offset + 4]
+ return struct.unpack(">I", p)[0] & 0x7FFFFFFF
def get_provisioning_uri(self, account_name, counter, issuer):
- return _generate_uri(self, "hotp", account_name, issuer, [
- ("counter", int(counter)),
- ])
+ return _generate_uri(
+ self, "hotp", account_name, issuer, [("counter", int(counter))]
+ )
@@ -1,40 +1,51 @@
# 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 (
- UnsupportedAlgorithm, _Reasons
-)
+from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import HMACBackend
from cryptography.hazmat.primitives import constant_time
from cryptography.hazmat.primitives.twofactor import InvalidToken
from cryptography.hazmat.primitives.twofactor.hotp import HOTP
from cryptography.hazmat.primitives.twofactor.utils import _generate_uri
class TOTP(object):
- def __init__(self, key, length, algorithm, time_step, backend,
- enforce_key_length=True):
+ def __init__(
+ self,
+ key,
+ length,
+ algorithm,
+ time_step,
+ backend=None,
+ enforce_key_length=True,
+ ):
+ backend = _get_backend(backend)
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
"Backend object does not implement HMACBackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
self._time_step = time_step
self._hotp = HOTP(key, length, algorithm, backend, enforce_key_length)
def generate(self, time):
counter = int(time / self._time_step)
return self._hotp.generate(counter)
def verify(self, totp, time):
if not constant_time.bytes_eq(self.generate(time), totp):
raise InvalidToken("Supplied TOTP value does not match.")
def get_provisioning_uri(self, account_name, issuer):
- return _generate_uri(self._hotp, "totp", account_name, issuer, [
- ("period", int(self._time_step)),
- ])
+ return _generate_uri(
+ self._hotp,
+ "totp",
+ account_name,
+ issuer,
+ [("period", int(self._time_step))],
+ )
@@ -5,14 +5,15 @@
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
+from cryptography.hazmat.backends import _get_backend
@six.add_metaclass(abc.ABCMeta)
class DSAParameters(object):
@abc.abstractmethod
def generate_private_key(self):
"""
@@ -115,25 +116,29 @@
Verifies the signature of the data.
"""
DSAPublicKeyWithSerialization = DSAPublicKey
-def generate_parameters(key_size, backend):
+def generate_parameters(key_size, backend=None):
+ backend = _get_backend(backend)
return backend.generate_dsa_parameters(key_size)
-def generate_private_key(key_size, backend):
+def generate_private_key(key_size, backend=None):
+ backend = _get_backend(backend)
return backend.generate_dsa_private_key_and_parameters(key_size)
def _check_dsa_parameters(parameters):
- if parameters.p.bit_length() not in [1024, 2048, 3072]:
- raise ValueError("p must be exactly 1024, 2048, or 3072 bits long")
+ if parameters.p.bit_length() not in [1024, 2048, 3072, 4096]:
+ raise ValueError(
+ "p must be exactly 1024, 2048, 3072, or 4096 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.")
@@ -146,47 +151,47 @@
if numbers.public_numbers.y != pow(parameters.g, numbers.x, parameters.p):
raise ValueError("y must be equal to (g ** x % p).")
class DSAParameterNumbers(object):
def __init__(self, p, q, g):
if (
- not isinstance(p, six.integer_types) or
- not isinstance(q, six.integer_types) or
- not isinstance(g, six.integer_types)
+ not isinstance(p, six.integer_types)
+ or not isinstance(q, six.integer_types)
+ or not isinstance(g, six.integer_types)
):
raise TypeError(
"DSAParameterNumbers p, q, and g arguments must be integers."
)
self._p = p
self._q = q
self._g = g
p = utils.read_only_property("_p")
q = utils.read_only_property("_q")
g = utils.read_only_property("_g")
- def parameters(self, backend):
+ def parameters(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_dsa_parameter_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAParameterNumbers):
return NotImplemented
return self.p == other.p and self.q == other.q and self.g == other.g
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
- )
+ "<DSAParameterNumbers(p={self.p}, q={self.q}, "
+ "g={self.g})>".format(self=self)
)
class DSAPublicNumbers(object):
def __init__(self, y, parameter_numbers):
if not isinstance(y, six.integer_types):
raise TypeError("DSAPublicNumbers y argument must be an integer.")
@@ -198,24 +203,25 @@
self._y = y
self._parameter_numbers = parameter_numbers
y = utils.read_only_property("_y")
parameter_numbers = utils.read_only_property("_parameter_numbers")
- def public_key(self, backend):
+ def public_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_dsa_public_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAPublicNumbers):
return NotImplemented
return (
- self.y == other.y and
- self.parameter_numbers == other.parameter_numbers
+ self.y == other.y
+ and self.parameter_numbers == other.parameter_numbers
)
def __ne__(self, other):
return not self == other
def __repr__(self):
return (
@@ -235,15 +241,16 @@
)
self._public_numbers = public_numbers
self._x = x
x = utils.read_only_property("_x")
public_numbers = utils.read_only_property("_public_numbers")
- def private_key(self, backend):
+ def private_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_dsa_private_numbers(self)
def __eq__(self, other):
if not isinstance(other, DSAPrivateNumbers):
return NotImplemented
return (
@@ -1,24 +1,26 @@
# 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
+
try:
# Only available in math in 3.5+
from math import gcd
except ImportError:
from fractions import gcd
import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
+from cryptography.hazmat.backends import _get_backend
from cryptography.hazmat.backends.interfaces import RSABackend
@six.add_metaclass(abc.ABCMeta)
class RSAPrivateKey(object):
@abc.abstractmethod
def signer(self, padding, algorithm):
@@ -104,38 +106,40 @@
Verifies the signature of the data.
"""
RSAPublicKeyWithSerialization = RSAPublicKey
-def generate_private_key(public_exponent, key_size, backend):
+def generate_private_key(public_exponent, key_size, backend=None):
+ backend = _get_backend(backend)
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement RSABackend.",
- _Reasons.BACKEND_MISSING_INTERFACE
+ _Reasons.BACKEND_MISSING_INTERFACE,
)
_verify_rsa_parameters(public_exponent, key_size)
return backend.generate_rsa_private_key(public_exponent, key_size)
def _verify_rsa_parameters(public_exponent, key_size):
- if public_exponent < 3:
- raise ValueError("public_exponent must be >= 3.")
-
- if public_exponent & 1 == 0:
- raise ValueError("public_exponent must be odd.")
+ if public_exponent not in (3, 65537):
+ raise ValueError(
+ "public_exponent must be either 3 (for legacy compatibility) or "
+ "65537. Almost everyone should choose 65537 here!"
+ )
if key_size < 512:
raise ValueError("key_size must be at least 512-bits.")
-def _check_private_key_components(p, q, private_exponent, dmp1, dmq1, iqmp,
- public_exponent, modulus):
+def _check_private_key_components(
+ p, q, private_exponent, dmp1, dmq1, iqmp, public_exponent, modulus
+):
if modulus < 3:
raise ValueError("modulus must be >= 3.")
if p >= modulus:
raise ValueError("p must be < modulus.")
if q >= modulus:
@@ -180,20 +184,20 @@
raise ValueError("e must be odd.")
def _modinv(e, m):
"""
Modular Multiplicative Inverse. Returns x such that: (x*e) mod m == 1
"""
- x1, y1, x2, y2 = 1, 0, 0, 1
+ 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
def rsa_crt_iqmp(p, q):
"""
Compute the CRT (q ** -1) % p value from RSA primes p and q.
"""
@@ -262,23 +266,22 @@
q, r = divmod(n, p)
assert r == 0
p, q = sorted((p, q), reverse=True)
return (p, q)
class RSAPrivateNumbers(object):
- def __init__(self, p, q, d, dmp1, dmq1, iqmp,
- public_numbers):
+ def __init__(self, p, q, d, dmp1, dmq1, iqmp, public_numbers):
if (
- not isinstance(p, six.integer_types) or
- not isinstance(q, six.integer_types) or
- not isinstance(d, six.integer_types) or
- not isinstance(dmp1, six.integer_types) or
- not isinstance(dmq1, six.integer_types) or
- not isinstance(iqmp, six.integer_types)
+ not isinstance(p, six.integer_types)
+ or not isinstance(q, six.integer_types)
+ or not isinstance(d, six.integer_types)
+ or not isinstance(dmp1, six.integer_types)
+ or not isinstance(dmq1, six.integer_types)
+ or not isinstance(iqmp, six.integer_types)
):
raise TypeError(
"RSAPrivateNumbers p, q, d, dmp1, dmq1, iqmp arguments must"
" all be an integers."
)
if not isinstance(public_numbers, RSAPublicNumbers):
@@ -299,61 +302,64 @@
q = utils.read_only_property("_q")
d = utils.read_only_property("_d")
dmp1 = utils.read_only_property("_dmp1")
dmq1 = utils.read_only_property("_dmq1")
iqmp = utils.read_only_property("_iqmp")
public_numbers = utils.read_only_property("_public_numbers")
- def private_key(self, backend):
+ def private_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_rsa_private_numbers(self)
def __eq__(self, other):
if not isinstance(other, RSAPrivateNumbers):
return NotImplemented
return (
- self.p == other.p and
- self.q == other.q and
- self.d == other.d and
- self.dmp1 == other.dmp1 and
- self.dmq1 == other.dmq1 and
- self.iqmp == other.iqmp and
- self.public_numbers == other.public_numbers
+ self.p == other.p
+ and self.q == other.q
+ and self.d == other.d
+ and self.dmp1 == other.dmp1
+ and self.dmq1 == other.dmq1
+ and self.iqmp == other.iqmp
+ and self.public_numbers == other.public_numbers
)
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,
- ))
+ 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):
- if (
- not isinstance(e, six.integer_types) or
- not isinstance(n, six.integer_types)
+ if not isinstance(e, six.integer_types) or not isinstance(
+ n, six.integer_types
):
raise TypeError("RSAPublicNumbers arguments must be integers.")
self._e = e
self._n = n
e = utils.read_only_property("_e")
n = utils.read_only_property("_n")
- def public_key(self, backend):
+ def public_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_rsa_public_numbers(self)
def __repr__(self):
return "<RSAPublicNumbers(e={0.e}, n={0.n})>".format(self)
def __eq__(self, other):
if not isinstance(other, RSAPublicNumbers):
@@ -12,18 +12,19 @@
@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
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
)
return backend.ed448_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
@@ -38,28 +39,30 @@
@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
+ _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
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
)
return backend.ed448_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
@@ -12,48 +12,51 @@
@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
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM,
)
return backend.x25519_load_public_bytes(data)
@abc.abstractmethod
- def public_bytes(self, encoding=None, format=None):
+ 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
+ _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
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM,
)
return backend.x25519_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
@@ -16,18 +16,19 @@
@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
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
)
return backend.ed25519_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
@@ -42,29 +43,31 @@
@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
+ _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
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM,
)
return backend.ed25519_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
@@ -5,87 +5,92 @@
from __future__ import absolute_import, division, print_function
import abc
import six
from cryptography import utils
+from cryptography.hazmat.backends import _get_backend
-def generate_parameters(generator, key_size, backend):
+def generate_parameters(generator, key_size, backend=None):
+ backend = _get_backend(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):
raise TypeError("x must be an integer.")
if not isinstance(public_numbers, DHPublicNumbers):
- raise TypeError("public_numbers must be an instance of "
- "DHPublicNumbers.")
+ raise TypeError(
+ "public_numbers must be an instance of " "DHPublicNumbers."
+ )
self._x = x
self._public_numbers = public_numbers
def __eq__(self, other):
if not isinstance(other, DHPrivateNumbers):
return NotImplemented
return (
- self._x == other._x and
- self._public_numbers == other._public_numbers
+ self._x == other._x
+ and self._public_numbers == other._public_numbers
)
def __ne__(self, other):
return not self == other
- def private_key(self, backend):
+ def private_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_dh_private_numbers(self)
public_numbers = utils.read_only_property("_public_numbers")
x = utils.read_only_property("_x")
class DHPublicNumbers(object):
def __init__(self, y, parameter_numbers):
if not isinstance(y, six.integer_types):
raise TypeError("y must be an integer.")
if not isinstance(parameter_numbers, DHParameterNumbers):
raise TypeError(
- "parameters must be an instance of DHParameterNumbers.")
+ "parameters must be an instance of DHParameterNumbers."
+ )
self._y = y
self._parameter_numbers = parameter_numbers
def __eq__(self, other):
if not isinstance(other, DHPublicNumbers):
return NotImplemented
return (
- self._y == other._y and
- self._parameter_numbers == other._parameter_numbers
+ self._y == other._y
+ and self._parameter_numbers == other._parameter_numbers
)
def __ne__(self, other):
return not self == other
- def public_key(self, backend):
+ def public_key(self, backend=None):
+ backend = _get_backend(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, q=None):
- if (
- not isinstance(p, six.integer_types) or
- not isinstance(g, six.integer_types)
+ 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")
@@ -95,23 +100,22 @@
self._q = q
def __eq__(self, other):
if not isinstance(other, DHParameterNumbers):
return NotImplemented
return (
- self._p == other._p and
- self._g == other._g and
- self._q == other._q
+ self._p == other._p and self._g == other._g and self._q == other._q
)
def __ne__(self, other):
return not self == other
- def parameters(self, backend):
+ def parameters(self, backend=None):
+ backend = _get_backend(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")
@@ -1,34 +1,37 @@
# 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 asn1crypto.algos import DSASignature
-
-import six
-
from cryptography import utils
+from cryptography.hazmat._der import (
+ DERReader,
+ INTEGER,
+ SEQUENCE,
+ encode_der,
+ encode_der_integer,
+)
from cryptography.hazmat.primitives import hashes
def decode_dss_signature(signature):
- data = DSASignature.load(signature, strict=True).native
- return data['r'], data['s']
+ 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 encode_dss_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")
-
- return DSASignature({'r': r, 's': s}).dump()
+ return encode_der(
+ SEQUENCE,
+ encode_der(INTEGER, encode_der_integer(r)),
+ encode_der(INTEGER, encode_der_integer(s)),
+ )
class Prehashed(object):
def __init__(self, algorithm):
if not isinstance(algorithm, hashes.HashAlgorithm):
raise TypeError("Expected instance of HashAlgorithm.")
@@ -1,15 +1,14 @@
# 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 math
import six
from cryptography import utils
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
@@ -32,16 +31,18 @@
class PSS(object):
MAX_LENGTH = object()
name = "EMSA-PSS"
def __init__(self, mgf, salt_length):
self._mgf = mgf
- if (not isinstance(salt_length, six.integer_types) and
- salt_length is not self.MAX_LENGTH):
+ if (
+ not isinstance(salt_length, six.integer_types)
+ and salt_length is not self.MAX_LENGTH
+ ):
raise TypeError("salt_length must be an integer.")
if salt_length is not self.MAX_LENGTH and salt_length < 0:
raise ValueError("salt_length must be zero or greater.")
self._salt_length = salt_length
@@ -69,11 +70,11 @@
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 = int(math.ceil((key.key_size - 1) / 8.0))
+ emlen = (key.key_size + 6) // 8
salt_length = emlen - hash_algorithm.digest_size - 2
assert salt_length >= 0
return salt_length
@@ -12,18 +12,19 @@
@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
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM,
)
return backend.x448_load_public_bytes(data)
@abc.abstractmethod
def public_bytes(self, encoding, format):
"""
@@ -32,28 +33,30 @@
@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
+ _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
+ _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM,
)
return backend.x448_load_private_bytes(data)
@abc.abstractmethod
def public_key(self):
"""
@@ -7,14 +7,15 @@
import abc
import warnings
import six
from cryptography import utils
from cryptography.hazmat._oid import ObjectIdentifier
+from cryptography.hazmat.backends import _get_backend
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")
@@ -162,14 +163,15 @@
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)
@@ -285,137 +287,136 @@
name = "brainpoolP512r1"
key_size = 512
_CURVE_TYPES = {
"prime192v1": SECP192R1,
"prime256v1": SECP256R1,
-
"secp192r1": SECP192R1,
"secp224r1": SECP224R1,
"secp256r1": SECP256R1,
"secp384r1": SECP384R1,
"secp521r1": SECP521R1,
"secp256k1": SECP256K1,
-
"sect163k1": SECT163K1,
"sect233k1": SECT233K1,
"sect283k1": SECT283K1,
"sect409k1": SECT409K1,
"sect571k1": SECT571K1,
-
"sect163r2": SECT163R2,
"sect233r1": SECT233R1,
"sect283r1": SECT283R1,
"sect409r1": SECT409R1,
"sect571r1": SECT571R1,
-
"brainpoolP256r1": BrainpoolP256R1,
"brainpoolP384r1": BrainpoolP384R1,
"brainpoolP512r1": BrainpoolP512R1,
}
@utils.register_interface(EllipticCurveSignatureAlgorithm)
class ECDSA(object):
def __init__(self, algorithm):
self._algorithm = algorithm
algorithm = utils.read_only_property("_algorithm")
-def generate_private_key(curve, backend):
+def generate_private_key(curve, backend=None):
+ backend = _get_backend(backend)
return backend.generate_elliptic_curve_private_key(curve)
-def derive_private_key(private_value, curve, backend):
+def derive_private_key(private_value, curve, backend=None):
+ backend = _get_backend(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 (
- not isinstance(x, six.integer_types) or
- not isinstance(y, six.integer_types)
+ if not isinstance(x, six.integer_types) or not isinstance(
+ y, six.integer_types
):
raise TypeError("x and y must be integers.")
if not isinstance(curve, EllipticCurve):
raise TypeError("curve must provide the EllipticCurve interface.")
self._y = y
self._x = x
self._curve = curve
- def public_key(self, backend):
+ def public_key(self, backend=None):
+ backend = _get_backend(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.DeprecatedIn25,
+ 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)
+ 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.DeprecatedIn25,
+ utils.PersistentlyDeprecated2019,
stacklevel=2,
)
- if data.startswith(b'\x04'):
+ 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')
+ 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')
+ raise ValueError("Invalid elliptic curve point data length")
else:
- raise ValueError('Unsupported elliptic curve point type')
+ 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")
def __eq__(self, other):
if not isinstance(other, EllipticCurvePublicNumbers):
return NotImplemented
return (
- self.x == other.x and
- self.y == other.y and
- self.curve.name == other.curve.name and
- self.curve.key_size == other.curve.key_size
+ self.x == other.x
+ and self.y == other.y
+ and self.curve.name == other.curve.name
+ and self.curve.key_size == other.curve.key_size
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.x, self.y, self.curve.name, self.curve.key_size))
@@ -437,27 +438,28 @@
"public_numbers must be an EllipticCurvePublicNumbers "
"instance."
)
self._private_value = private_value
self._public_numbers = public_numbers
- def private_key(self, backend):
+ def private_key(self, backend=None):
+ backend = _get_backend(backend)
return backend.load_elliptic_curve_private_numbers(self)
private_value = utils.read_only_property("_private_value")
public_numbers = utils.read_only_property("_public_numbers")
def __eq__(self, other):
if not isinstance(other, EllipticCurvePrivateNumbers):
return NotImplemented
return (
- self.private_value == other.private_value and
- self.public_numbers == other.public_numbers
+ self.private_value == other.private_value
+ and self.public_numbers == other.public_numbers
)
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash((self.private_value, self.public_numbers))
@@ -9,15 +9,17 @@
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
+ _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(),
@@ -36,18 +38,21 @@
MALFORMED_REQUEST = 1
INTERNAL_ERROR = 2
TRY_LATER = 3
SIG_REQUIRED = 5
UNAUTHORIZED = 6
-_RESPONSE_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPResponseStatus)
+_RESPONSE_STATUS_TO_ENUM = {x.value: x for x in OCSPResponseStatus}
_ALLOWED_HASHES = (
- hashes.SHA1, hashes.SHA224, hashes.SHA256,
- hashes.SHA384, hashes.SHA512
+ 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"
@@ -56,40 +61,41 @@
class OCSPCertStatus(Enum):
GOOD = 0
REVOKED = 1
UNKNOWN = 2
-_CERT_STATUS_TO_ENUM = dict((x.value, x) for x in OCSPCertStatus)
+_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)
+ 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):
@@ -100,35 +106,43 @@
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)
+ 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)
+ 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
@@ -151,110 +165,134 @@
)
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.')
+ 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)
+ 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=[]):
+ 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):
+ 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
+ cert,
+ issuer,
+ algorithm,
+ cert_status,
+ this_update,
+ next_update,
+ revocation_time,
+ revocation_reason,
)
return OCSPResponseBuilder(
- singleresp, self._responder_id,
- self._certs, self._extensions,
+ 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,
+ 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,
+ 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],
+ 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")
- if not isinstance(algorithm, hashes.HashAlgorithm):
- raise TypeError("Algorithm must be a registered hash algorithm.")
-
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")
@@ -282,14 +320,15 @@
"""
@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
@@ -416,7 +455,13 @@
"""
@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.
+ """
@@ -6,55 +6,92 @@
import abc
import datetime
import hashlib
import ipaddress
from enum import Enum
-from asn1crypto.keys import PublicKeyInfo
-
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
+ 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,
+ 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
+ serialization.PublicFormat.UncompressedPoint,
)
else:
# This is a very slow way to do this.
serialized = public_key.public_bytes(
serialization.Encoding.DER,
- serialization.PublicFormat.SubjectPublicKeyInfo
+ serialization.PublicFormat.SubjectPublicKeyInfo,
)
- data = bytes(PublicKeyInfo.load(serialized)['public_key'])
+ 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):
@@ -95,27 +132,18 @@
if isinstance(ext.value, extclass):
return ext
raise ExtensionNotFound(
"No {} extension was found".format(extclass), extclass.oid
)
- def __iter__(self):
- return iter(self._extensions)
-
- def __len__(self):
- return len(self._extensions)
-
- def __getitem__(self, idx):
- return self._extensions[idx]
+ __len__, __iter__, __getitem__ = _make_sequence_methods("_extensions")
def __repr__(self):
- return (
- "<Extensions({})>".format(self._extensions)
- )
+ return "<Extensions({})>".format(self._extensions)
@utils.register_interface(ExtensionType)
class CRLNumber(object):
oid = ExtensionOID.CRL_NUMBER
def __init__(self, crl_number):
@@ -142,16 +170,20 @@
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):
+ 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"
)
@@ -165,37 +197,35 @@
"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"
- )
+ 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
+ authority_cert_serial_number=None,
)
@classmethod
def from_issuer_subject_key_identifier(cls, ski):
return cls(
- key_identifier=ski.value.digest,
+ key_identifier=ski.digest,
authority_cert_issuer=None,
- authority_cert_serial_number=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}"
@@ -203,31 +233,31 @@
)
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
+ 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
- ))
+ 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"
)
@@ -271,34 +301,59 @@
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)
+ __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 __getitem__(self, idx):
- return self._descriptions[idx]
+ def __hash__(self):
+ return hash(tuple(self._descriptions))
+
+
[email protected]_interface(ExtensionType)
+class SubjectInformationAccess(object):
+ oid = ExtensionOID.SUBJECT_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 "<SubjectInformationAccess({})>".format(self._descriptions)
+
+ def __eq__(self, other):
+ if not isinstance(other, SubjectInformationAccess):
+ 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):
@@ -318,16 +373,16 @@
)
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
+ 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))
@@ -343,31 +398,31 @@
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)
+ 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)
+ 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
@@ -418,35 +473,30 @@
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)
+ __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 __getitem__(self, idx):
- return self._distribution_points[idx]
-
def __hash__(self):
return hash(tuple(self._distribution_points))
@utils.register_interface(ExtensionType)
class FreshestCRL(object):
oid = ExtensionOID.FRESHEST_CRL
@@ -459,35 +509,30 @@
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)
+ __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 __getitem__(self, idx):
- return self._distribution_points[idx]
-
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:
@@ -512,22 +557,23 @@
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
- )):
+ 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
+ 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):
@@ -540,27 +586,27 @@
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)
+ "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
+ 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:
@@ -631,16 +677,16 @@
)
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
+ 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(
@@ -665,51 +711,44 @@
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)
+ __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 __getitem__(self, idx):
- return self._policies[idx]
-
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
+ 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
@@ -721,16 +760,16 @@
)
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
+ 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:
@@ -763,16 +802,16 @@
)
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
+ 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))
@@ -782,33 +821,31 @@
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"
- )
+ 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
+ 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)))
@@ -826,19 +863,15 @@
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)
+ __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
@@ -852,55 +885,78 @@
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
+ 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
- def __iter__(self):
- return iter(self._features)
-
- def __len__(self):
- return len(self._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 __getitem__(self, idx):
- return self._features[idx]
-
def __ne__(self, other):
return not self == other
def __hash__(self):
return hash(tuple(self._features))
@@ -911,15 +967,15 @@
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 = dict((x.value, x) for x in TLSFeatureType)
+_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):
@@ -949,17 +1005,26 @@
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):
+ 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
@@ -999,77 +1064,83 @@
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
+ # Users found None confusing because even though encipher/decipher
+ # have no meaning unless key_agreement is true, to construct an
+ # instance of the class you still need to pass False.
+ encipher_only = False
+ decipher_only = False
- 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)
+ 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
+ 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
- ))
+ 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
- ):
+ 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
- ):
+ 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)
@@ -1083,25 +1154,29 @@
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
+ 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):
+ 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 (
@@ -1141,25 +1216,27 @@
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)
+ 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
+ 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))
@@ -1172,19 +1249,15 @@
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)
+ __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:
@@ -1199,68 +1272,54 @@
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
- def __getitem__(self, idx):
- return self._general_names[idx]
-
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)
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._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 __getitem__(self, idx):
- return self._general_names[idx]
-
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)
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._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)
@@ -1269,33 +1328,26 @@
return NotImplemented
return self._general_names == other._general_names
def __ne__(self, other):
return not self == other
- def __getitem__(self, idx):
- return self._general_names[idx]
-
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)
- def __iter__(self):
- return iter(self._general_names)
-
- def __len__(self):
- return len(self._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)
@@ -1304,17 +1356,14 @@
return Not