diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2014-03-17 20:50:03 -0700 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2014-03-17 20:50:03 -0700 |
commit | 38c42635490d24d7ee88041b52002156c6f5a676 (patch) | |
tree | 34606dbe780ec7704051f26b0f12ab8755fca812 /cryptography | |
parent | 0380374fdae7bd744e46ad526af721fae11aa475 (diff) | |
parent | a38e8e580c09cebcab528be7e806f63539498f94 (diff) | |
download | cryptography-38c42635490d24d7ee88041b52002156c6f5a676.tar.gz cryptography-38c42635490d24d7ee88041b52002156c6f5a676.tar.bz2 cryptography-38c42635490d24d7ee88041b52002156c6f5a676.zip |
Merge pull request #792 from reaperhulk/rsa-pss-verify
RSA PSS Verify
Diffstat (limited to 'cryptography')
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 84 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/padding.py | 8 |
2 files changed, 90 insertions, 2 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index b977b4c8..7c058f58 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -21,7 +21,7 @@ import six from cryptography import utils from cryptography.exceptions import ( InvalidTag, InternalError, AlreadyFinalized, UnsupportedCipher, - UnsupportedHash, UnsupportedPadding, InvalidSignature + UnsupportedAlgorithm, UnsupportedHash, UnsupportedPadding, InvalidSignature ) from cryptography.hazmat.backends.interfaces import ( CipherBackend, HashBackend, HMACBackend, PBKDF2HMACBackend, RSABackend @@ -29,6 +29,9 @@ from cryptography.hazmat.backends.interfaces import ( from cryptography.hazmat.bindings.openssl.binding import Binding from cryptography.hazmat.primitives import interfaces, hashes from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.padding import ( + PKCS1v15, PSS, MGF1 +) from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, Blowfish, Camellia, CAST5, TripleDES, ARC4, IDEA ) @@ -404,6 +407,12 @@ class Backend(object): return _RSAVerificationContext(self, public_key, signature, padding, algorithm) + def mgf1_hash_supported(self, algorithm): + if self._lib.Cryptography_HAS_MGF1_MD: + return self.hash_supported(algorithm) + else: + return isinstance(algorithm, hashes.SHA1) + class GetCipherByName(object): def __init__(self, fmt): @@ -787,12 +796,29 @@ class _RSAVerificationContext(object): raise TypeError( "Expected provider of interfaces.AsymmetricPadding") - if padding.name == "EMSA-PKCS1-v1_5": + if isinstance(padding, PKCS1v15): if self._backend._lib.Cryptography_HAS_PKEY_CTX: self._verify_method = self._verify_pkey_ctx self._padding_enum = self._backend._lib.RSA_PKCS1_PADDING else: self._verify_method = self._verify_pkcs1 + elif isinstance(padding, PSS): + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend" + ) + + if not self._backend.mgf1_hash_supported(padding._mgf._algorithm): + raise UnsupportedHash( + "When OpenSSL is older than 1.0.1 then only SHA1 is " + "supported with MGF1." + ) + + if self._backend._lib.Cryptography_HAS_PKEY_CTX: + self._verify_method = self._verify_pkey_ctx + self._padding_enum = self._backend._lib.RSA_PKCS1_PSS_PADDING + else: + self._verify_method = self._verify_pss else: raise UnsupportedPadding @@ -833,6 +859,20 @@ class _RSAVerificationContext(object): res = self._backend._lib.EVP_PKEY_CTX_set_rsa_padding( pkey_ctx, self._padding_enum) assert res > 0 + if isinstance(self._padding, PSS): + res = self._backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, self._get_salt_length()) + assert res > 0 + if self._backend._lib.Cryptography_HAS_MGF1_MD: + # MGF1 MD is configurable in OpenSSL 1.0.1+ + mgf1_md = self._backend._lib.EVP_get_digestbyname( + self._padding._mgf._algorithm.name.encode("ascii")) + assert mgf1_md != self._backend._ffi.NULL + res = self._backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md( + pkey_ctx, mgf1_md + ) + assert res > 0 + data_to_verify = self._hash_ctx.finalize() self._hash_ctx = None res = self._backend._lib.EVP_PKEY_verify( @@ -869,5 +909,45 @@ class _RSAVerificationContext(object): assert errors raise InvalidSignature + def _verify_pss(self, evp_pkey, evp_md): + pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey) + assert pkey_size > 0 + rsa_cdata = self._backend._lib.EVP_PKEY_get1_RSA(evp_pkey) + assert rsa_cdata != self._backend._ffi.NULL + rsa_cdata = self._backend._ffi.gc(rsa_cdata, + self._backend._lib.RSA_free) + buf = self._backend._ffi.new("unsigned char[]", pkey_size) + res = self._backend._lib.RSA_public_decrypt( + len(self._signature), + self._signature, + buf, + rsa_cdata, + self._backend._lib.RSA_NO_PADDING + ) + if res != pkey_size: + errors = self._backend._consume_errors() + assert errors + raise InvalidSignature + + data_to_verify = self._hash_ctx.finalize() + self._hash_ctx = None + res = self._backend._lib.RSA_verify_PKCS1_PSS( + rsa_cdata, + data_to_verify, + evp_md, + buf, + self._get_salt_length() + ) + if res != 1: + errors = self._backend._consume_errors() + assert errors + raise InvalidSignature + + def _get_salt_length(self): + if self._padding._mgf._salt_length is MGF1.MAX_LENGTH: + return -2 + else: + return self._padding._mgf._salt_length + backend = Backend() diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py index 46e00b8e..02aff280 100644 --- a/cryptography/hazmat/primitives/asymmetric/padding.py +++ b/cryptography/hazmat/primitives/asymmetric/padding.py @@ -24,6 +24,14 @@ class PKCS1v15(object): name = "EMSA-PKCS1-v1_5" +@utils.register_interface(interfaces.AsymmetricPadding) +class PSS(object): + name = "EMSA-PSS" + + def __init__(self, mgf): + self._mgf = mgf + + class MGF1(object): MAX_LENGTH = object() |