aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2014-05-01 22:52:34 -0700
committerAlex Gaynor <alex.gaynor@gmail.com>2014-05-01 22:52:34 -0700
commitc7f3d9723d7512a95f5d9b56d7c02156df04936c (patch)
tree465162cd2b9c8cabc1a4459b31e488ef84c45dee /cryptography
parent8c977a3bac7476b1d8a59c42bc96cf7ad08f430e (diff)
parent262e0051ce6d51ab4937f8da99e850d9e403572a (diff)
downloadcryptography-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.py7
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py54
-rw-r--r--cryptography/hazmat/primitives/asymmetric/dsa.py9
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)