aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography
diff options
context:
space:
mode:
authorPaul Kehrer <paul.l.kehrer@gmail.com>2014-03-13 21:03:00 -0400
committerPaul Kehrer <paul.l.kehrer@gmail.com>2014-03-16 17:03:40 -0400
commitb5936a7817b535422574a3627473b13a5f21e5d8 (patch)
treea02c697daed7046959dad2bf54278edad2d2bf2b /cryptography
parent31b837fdefc1516e4e1dff7bfb8db9c4303078f0 (diff)
downloadcryptography-b5936a7817b535422574a3627473b13a5f21e5d8.tar.gz
cryptography-b5936a7817b535422574a3627473b13a5f21e5d8.tar.bz2
cryptography-b5936a7817b535422574a3627473b13a5f21e5d8.zip
add RSA PSS verification support
Diffstat (limited to 'cryptography')
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py73
-rw-r--r--cryptography/hazmat/primitives/asymmetric/padding.py8
2 files changed, 80 insertions, 1 deletions
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index a68bc089..73582808 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -27,6 +27,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
)
@@ -377,6 +380,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):
@@ -760,12 +769,26 @@ 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 TypeError("Only MGF1 is supported by this backend")
+
+ if (not isinstance(padding.mgf._algorithm, hashes.SHA1) and
+ not self._backend._lib.Cryptography_HAS_MGF1_MD):
+ raise UnsupportedHash("This backend only supports MGF1 with "
+ "SHA1 when OpenSSL is not 1.0.1+")
+
+ 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
@@ -806,6 +829,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(
@@ -842,5 +879,39 @@ class _RSAVerificationContext(object):
assert errors
raise InvalidSignature
+ def _verify_pss(self, rsa_cdata, evp_pkey, evp_md):
+ pkey_size = self._backend._lib.EVP_PKEY_size(evp_pkey)
+ assert pkey_size > 0
+ 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:
+ assert self._backend._consume_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:
+ assert self._backend._consume_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..a8129804 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()