diff options
author | Alex Gaynor <alex.gaynor@gmail.com> | 2014-05-01 22:52:34 -0700 |
---|---|---|
committer | Alex Gaynor <alex.gaynor@gmail.com> | 2014-05-01 22:52:34 -0700 |
commit | c7f3d9723d7512a95f5d9b56d7c02156df04936c (patch) | |
tree | 465162cd2b9c8cabc1a4459b31e488ef84c45dee /cryptography | |
parent | 8c977a3bac7476b1d8a59c42bc96cf7ad08f430e (diff) | |
parent | 262e0051ce6d51ab4937f8da99e850d9e403572a (diff) | |
download | cryptography-c7f3d9723d7512a95f5d9b56d7c02156df04936c.tar.gz cryptography-c7f3d9723d7512a95f5d9b56d7c02156df04936c.tar.bz2 cryptography-c7f3d9723d7512a95f5d9b56d7c02156df04936c.zip |
Merge pull request #991 from reaperhulk/dsa-sign
DSA signing support
Diffstat (limited to 'cryptography')
-rw-r--r-- | cryptography/hazmat/backends/interfaces.py | 7 | ||||
-rw-r--r-- | cryptography/hazmat/backends/openssl/backend.py | 54 | ||||
-rw-r--r-- | cryptography/hazmat/primitives/asymmetric/dsa.py | 9 |
3 files changed, 70 insertions, 0 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py index e63b079b..264c5afb 100644 --- a/cryptography/hazmat/backends/interfaces.py +++ b/cryptography/hazmat/backends/interfaces.py @@ -146,6 +146,13 @@ class DSABackend(object): """ @abc.abstractmethod + def create_dsa_signature_ctx(self, private_key, algorithm): + """ + Returns an object conforming to the AsymmetricSignatureContext + interface. + """ + + @abc.abstractmethod def create_dsa_verification_ctx(self, public_key, signature, algorithm): """ Returns an object conforming to the AsymmetricVerificationContext diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py index 37deb2ae..729f1471 100644 --- a/cryptography/hazmat/backends/openssl/backend.py +++ b/cryptography/hazmat/backends/openssl/backend.py @@ -474,6 +474,9 @@ class Backend(object): y=self._bn_to_int(ctx.pub_key) ) + def create_dsa_signature_ctx(self, private_key, algorithm): + return _DSASignatureContext(self, private_key, algorithm) + def create_dsa_verification_ctx(self, public_key, signature, algorithm): return _DSAVerificationContext(self, public_key, signature, @@ -491,6 +494,19 @@ class Backend(object): ctx.pub_key = self._int_to_bn(public_key.y) return ctx + def _dsa_cdata_from_private_key(self, private_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 = private_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.priv_key = self._int_to_bn(private_key.x) + ctx.pub_key = self._int_to_bn(private_key.y) + return ctx + def dsa_hash_supported(self, algorithm): if self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f: return isinstance(algorithm, hashes.SHA1) @@ -1369,6 +1385,44 @@ class _DSAVerificationContext(object): raise InvalidSignature +@utils.register_interface(interfaces.AsymmetricSignatureContext) +class _DSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._algorithm = algorithm + self._hash_ctx = _HashContext(backend, self._algorithm) + self._dsa_cdata = self._backend._dsa_cdata_from_private_key( + self._private_key) + self._dsa_cdata = self._backend._ffi.gc(self._dsa_cdata, + self._backend._lib.DSA_free) + + def update(self, data): + if self._hash_ctx is None: + raise AlreadyFinalized("Context has already been finalized") + + self._hash_ctx.update(data) + + def finalize(self): + if self._hash_ctx is None: + raise AlreadyFinalized("Context has already been finalized") + + data_to_sign = self._hash_ctx.finalize() + self._hash_ctx = None + sig_buf_len = self._backend._lib.DSA_size(self._dsa_cdata) + sig_buf = self._backend._ffi.new("unsigned char[]", sig_buf_len) + buflen = self._backend._ffi.new("unsigned int *") + + # The first parameter passed to DSA_sign is unused by OpenSSL but + # must be an integer. + res = self._backend._lib.DSA_sign( + 0, data_to_sign, len(data_to_sign), sig_buf, + buflen, self._dsa_cdata) + assert res == 1 + + return self._backend._ffi.buffer(sig_buf)[:] + + @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 57a7ef3d..aa3cdc90 100644 --- a/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -118,6 +118,15 @@ class DSAPrivateKey(object): return backend.generate_dsa_private_key(parameters) + def signer(self, algorithm, backend): + if not isinstance(backend, DSABackend): + raise UnsupportedAlgorithm( + "Backend object does not implement DSABackend", + _Reasons.BACKEND_MISSING_INTERFACE + ) + + return backend.create_dsa_signature_ctx(self, algorithm) + @property def key_size(self): return utils.bit_length(self._modulus) |