diff options
author | David Reid <dreid@dreid.org> | 2014-05-01 12:56:56 -0700 |
---|---|---|
committer | David Reid <dreid@dreid.org> | 2014-05-01 12:56:56 -0700 |
commit | 7d47b98e0e95f759a18e2651a5cc6e466bccef9f (patch) | |
tree | 9d0e0ef64fde6f79f8a3d29c7f42ca2a3b94f8e8 /cryptography | |
parent | 7f39ebc6b32c4e3a92f17357271668c9553dc830 (diff) | |
parent | f58d1ab6cf5d90ae06a593fca52ab388d75da068 (diff) | |
download | cryptography-7d47b98e0e95f759a18e2651a5cc6e466bccef9f.tar.gz cryptography-7d47b98e0e95f759a18e2651a5cc6e466bccef9f.tar.bz2 cryptography-7d47b98e0e95f759a18e2651a5cc6e466bccef9f.zip |
Merge pull request #982 from reaperhulk/dsa-verify
DSA verification
Diffstat (limited to 'cryptography')
-rw-r--r-- | cryptography/hazmat/backends/interfaces.py | 19 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 72 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/dsa.py | 10 |
3 files changed, 101 insertions, 0 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index aaaca5e2..e63b079b 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -145,6 +145,25 @@ class DSABackend(object): a DSAParameters object. """ + @abc.abstractmethod + def create_dsa_verification_ctx(self, public_key, signature, algorithm): + """ + Returns an object conforming to the AsymmetricVerificationContext + interface. + """ + + @abc.abstractmethod + def dsa_hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by the backend for DSA. + """ + + @abc.abstractmethod + def dsa_parameters_supported(self, p, q, g): + """ + Return True if the parameters are supported by the backend for DSA. + """ + @six.add_metaclass(abc.ABCMeta) class TraditionalOpenSSLSerializationBackend(object): diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index f9154f3b..37deb2ae 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -474,6 +474,35 @@ class Backend(object): y=self._bn_to_int(ctx.pub_key) ) + def create_dsa_verification_ctx(self, public_key, signature, + algorithm): + return _DSAVerificationContext(self, public_key, signature, + algorithm) + + def _dsa_cdata_from_public_key(self, public_key): + # Does not GC the DSA cdata. You *must* make sure it's freed + # correctly yourself! + ctx = self._lib.DSA_new() + assert ctx != self._ffi.NULL + parameters = public_key.parameters() + ctx.p = self._int_to_bn(parameters.p) + ctx.q = self._int_to_bn(parameters.q) + ctx.g = self._int_to_bn(parameters.g) + ctx.pub_key = self._int_to_bn(public_key.y) + return ctx + + def dsa_hash_supported(self, algorithm): + if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f: + return isinstance(algorithm, hashes.SHA1) + else: + return self.hash_supported(algorithm) + + def dsa_parameters_supported(self, p, q, g): + if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f: + return (utils.bit_length(p) <= 1024 and utils.bit_length(q) <= 160) + else: + return True + def decrypt_rsa(self, private_key, ciphertext, padding): key_size_bytes = int(math.ceil(private_key.key_size / 8.0)) if key_size_bytes != len(ciphertext): @@ -1297,6 +1326,49 @@ class _RSAVerificationContext(object): raise InvalidSignature +@utils.register_interface(interfaces.AsymmetricVerificationContext) +class _DSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._algorithm = algorithm + + self._hash_ctx = _HashContext(backend, self._algorithm) + + def update(self, data): + if self._hash_ctx is None: + raise AlreadyFinalized("Context has already been finalized") + + self._hash_ctx.update(data) + + def verify(self): + if self._hash_ctx is None: + raise AlreadyFinalized("Context has already been finalized") + + self._dsa_cdata = self._backend._dsa_cdata_from_public_key( + self._public_key) + self._dsa_cdata = self._backend._ffi.gc(self._dsa_cdata, + self._backend._lib.DSA_free) + + data_to_verify = self._hash_ctx.finalize() + self._hash_ctx = None + + # The first parameter passed to DSA_verify is unused by OpenSSL but + # must be an integer. + res = self._backend._lib.DSA_verify( + 0, data_to_verify, len(data_to_verify), self._signature, + len(self._signature), self._dsa_cdata) + + if res != 1: + errors = self._backend._consume_errors() + assert errors + if res == -1: + assert errors[0].lib == self._backend._lib.ERR_LIB_ASN1 + + raise InvalidSignature + + @utils.register_interface(interfaces.CMACContext) class _CMACContext(object): def __init__(self, backend, algorithm, ctx=None): diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py index 4c2de36a..57a7ef3d 100644 --- a/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -151,6 +151,16 @@ class DSAPublicKey(object): self._generator = generator self._y = y + def verifier(self, signature, algorithm, backend): + if not isinstance(backend, DSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement DSABackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + return backend.create_dsa_verification_ctx(self, signature, + algorithm) + @property def key_size(self): return utils.bit_length(self._modulus) |