aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohammed Attia <skeuomorf@gmail.com>2014-04-09 23:28:09 +0200
committerPaul Kehrer <paul.l.kehrer@gmail.com>2014-04-30 15:55:00 -0500
commit8ae64e4dec332942cf428a8426b0062511de40f2 (patch)
tree680187b953db48e478c490bce43e1ca048ecad59
parent461e83742aec0da4dc34ef0428f7b8e20f40b174 (diff)
downloadcryptography-8ae64e4dec332942cf428a8426b0062511de40f2.tar.gz
cryptography-8ae64e4dec332942cf428a8426b0062511de40f2.tar.bz2
cryptography-8ae64e4dec332942cf428a8426b0062511de40f2.zip
Add DSA verification
-rw-r--r--cryptography/hazmat/backends/interfaces.py25
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py91
-rw-r--r--cryptography/hazmat/primitives/asymmetric/dsa.py19
3 files changed, 134 insertions, 1 deletions
diff --git a/cryptography/hazmat/backends/interfaces.py b/cryptography/hazmat/backends/interfaces.py
index aaaca5e2..3192789c 100644
--- a/cryptography/hazmat/backends/interfaces.py
+++ b/cryptography/hazmat/backends/interfaces.py
@@ -145,6 +145,31 @@ 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_signature_from_components(self, r, s):
+ """
+ Convert a DSA signature pair r and s into a DER byte string.
+ """
+
+ @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):
+ """
+ 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..bd1ce02b 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -474,6 +474,58 @@ 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_signature_from_components(self, r, s):
+ dsa_sig = self._lib.DSA_SIG_new()
+ assert dsa_sig != self._ffi.NULL
+ dsa_sig = self._ffi.gc(dsa_sig, self._lib.DSA_SIG_free)
+
+ dsa_sig.r = self._int_to_bn(r)
+ dsa_sig.s = self._int_to_bn(s)
+
+ sig_len = self._lib.i2d_DSA_SIG(dsa_sig, self._ffi.NULL)
+ assert sig_len != 0
+
+ sig_buf = self._ffi.new("unsigned char []", sig_len)
+ sig_bufptr = self._ffi.new("unsigned char **", sig_buf)
+
+ sig_len = self._lib.i2d_DSA_SIG(dsa_sig, sig_bufptr)
+
+ return self._ffi.buffer(sig_buf)[:sig_len]
+
+ 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 and
+ not isinstance(algorithm, hashes.SHA1)):
+ return False
+ else:
+ return True
+
+ def dsa_parameters_supported(self, p, q):
+ if (self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f
+ and not (
+ utils.bit_length(p) <= 1024
+ and utils.bit_length(q) <= 160)):
+ return False
+ 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 +1349,45 @@ 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
+
+ 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
+ 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..0f7cf21a 100644
--- a/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -18,7 +18,7 @@ import six
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import DSABackend
-from cryptography.hazmat.primitives import interfaces
+from cryptography.hazmat.primitives import hashes, interfaces
def _check_dsa_parameters(modulus, subgroup_order, generator):
@@ -151,6 +151,23 @@ 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
+ )
+ if not isinstance(algorithm, (hashes.SHA1, hashes.SHA224,
+ hashes.SHA256, hashes.SHA384, hashes.SHA512)):
+ raise UnsupportedAlgorithm(
+ "Unsupported Hash Algorithm, please use one of these: "
+ "SHA1, SHA224, SHA256, SHA384, SHA512",
+ _Reasons.UNSUPPORTED_HASH
+ )
+
+ return backend.create_dsa_verification_ctx(self, signature,
+ algorithm)
+
@property
def key_size(self):
return utils.bit_length(self._modulus)