Add DSABackend

This commit is contained in:
Mohammed Attia 2014-04-02 03:46:57 +02:00
parent 9ac7c1d903
commit 97c27c698d
9 changed files with 121 additions and 19 deletions

View file

@ -113,6 +113,21 @@ class RSABackend(six.with_metaclass(abc.ABCMeta)):
"""
class DSABackend(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def generate_dsa_parameters(self, key_size):
"""
Generate a DSAParameters instance with a modulus of key_size bits.
"""
@abc.abstractmethod
def generate_dsa_private_key(self, parameters):
"""
Generate an DSAPrivateKey instance with parameters as
a DSAParameters object.
"""
class OpenSSLSerializationBackend(six.with_metaclass(abc.ABCMeta)):
@abc.abstractmethod
def load_openssl_pem_private_key(self, data, password):

View file

@ -16,7 +16,8 @@ from __future__ import absolute_import, division, print_function
from cryptography import utils
from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.backends.interfaces import (
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend
CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
RSABackend
)
@ -25,6 +26,7 @@ from cryptography.hazmat.backends.interfaces import (
@utils.register_interface(HMACBackend)
@utils.register_interface(PBKDF2HMACBackend)
@utils.register_interface(RSABackend)
@utils.register_interface(DSABackend)
class MultiBackend(object):
name = "multibackend"
@ -142,3 +144,15 @@ class MultiBackend(object):
padding, algorithm)
raise UnsupportedAlgorithm("RSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def generate_dsa_parameters(self, key_size):
for b in self._filtered_backends(DSABackend):
return b.generate_dsa_parameters(key_size)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def generate_dsa_private_key(self, parameters):
for b in self._filtered_backends(DSABackend):
return b.generate_dsa_private_key(parameters)
raise UnsupportedAlgorithm("DSA is not supported by the backend",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)

View file

@ -25,7 +25,8 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend
CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
RSABackend
)
from cryptography.hazmat.bindings.openssl.binding import Binding
from cryptography.hazmat.primitives import hashes, interfaces
@ -46,6 +47,7 @@ _OpenSSLError = collections.namedtuple("_OpenSSLError",
@utils.register_interface(CipherBackend)
@utils.register_interface(DSABackend)
@utils.register_interface(HashBackend)
@utils.register_interface(HMACBackend)
@utils.register_interface(PBKDF2HMACBackend)
@ -420,8 +422,8 @@ class Backend(object):
raise ValueError(
"Key size must be 1024 or 2048 or 3072 bits")
if backend._lib.OPENSSL_VERSION_NUMBER < 0x1000000f \
and key_size > 1024:
if (self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f and
key_size > 1024):
raise ValueError(
"Key size must be 1024 because OpenSSL < 1.0.0 doesn't "
"support larger key sizes")

View file

@ -16,6 +16,8 @@ from __future__ import absolute_import, division, print_function
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
@ -51,6 +53,12 @@ class DSAParameters(object):
@classmethod
def generate(cls, key_size, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement DSABackend",
_Reasons.BACKEND_MISSING_INTERFACE
)
return backend.generate_dsa_parameters(key_size)
@property
@ -102,6 +110,12 @@ class DSAPrivateKey(object):
@classmethod
def generate(cls, parameters, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
"Backend object does not implement DSABackend",
_Reasons.BACKEND_MISSING_INTERFACE
)
return backend.generate_dsa_private_key(parameters)
@property

View file

@ -2,6 +2,7 @@
addopts = -r s
markers =
cipher: this test requires a backend providing CipherBackend
dsa: this test requires a backend providing DSABackend
hash: this test requires a backend providing HashBackend
hmac: this test requires a backend providing HMACBackend
pbkdf2hmac: this test requires a backend providing PBKDF2HMACBackend

View file

@ -17,7 +17,8 @@ import pytest
from cryptography.hazmat.backends import _available_backends
from cryptography.hazmat.backends.interfaces import (
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend
CipherBackend, DSABackend, HMACBackend, HashBackend, PBKDF2HMACBackend,
RSABackend
)
from .utils import check_backend_support, check_for_iface, select_backends
@ -37,6 +38,7 @@ def pytest_runtest_setup(item):
check_for_iface("cipher", CipherBackend, item)
check_for_iface("hash", HashBackend, item)
check_for_iface("pbkdf2hmac", PBKDF2HMACBackend, item)
check_for_iface("dsa", DSABackend, item)
check_for_iface("rsa", RSABackend, item)
check_backend_support(item)

View file

@ -18,7 +18,8 @@ from cryptography.exceptions import (
UnsupportedAlgorithm, _Reasons
)
from cryptography.hazmat.backends.interfaces import (
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend
CipherBackend, HMACBackend, HashBackend, PBKDF2HMACBackend, RSABackend,
DSABackend
)
from cryptography.hazmat.backends.multibackend import MultiBackend
from cryptography.hazmat.primitives import hashes, hmac
@ -27,6 +28,8 @@ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from ...utils import raises_unsupported_algorithm
from pretend import stub
@utils.register_interface(CipherBackend)
class DummyCipherBackend(object):
@ -98,6 +101,15 @@ class DummyRSABackend(object):
pass
@utils.register_interface(DSABackend)
class DummyDSABackend(object):
def generate_dsa_parameters(self, key_size):
pass
def generate_dsa_private_key(self, parameters):
pass
class TestMultiBackend(object):
def test_ciphers(self):
backend = MultiBackend([
@ -193,3 +205,24 @@ class TestMultiBackend(object):
):
backend.create_rsa_verification_ctx(
"public_key", "sig", padding.PKCS1v15(), hashes.MD5())
def test_dsa(self):
backend = MultiBackend([
DummyDSABackend()
])
backend.generate_dsa_parameters(key_size=1024)
parameters = stub()
backend.generate_dsa_private_key(parameters)
backend = MultiBackend([])
with raises_unsupported_algorithm(
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
backend.generate_dsa_parameters(key_size=1024)
with raises_unsupported_algorithm(
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
):
backend.generate_dsa_private_key(parameters)

View file

@ -28,6 +28,8 @@ from cryptography.hazmat.primitives.ciphers.modes import CBC
from ...utils import raises_unsupported_algorithm
from cryptography.utils import bit_length
@utils.register_interface(interfaces.Mode)
class DummyMode(object):
@ -203,6 +205,16 @@ class TestOpenSSL(object):
with pytest.raises(ValueError):
dsa.DSAParameters.generate(3072, backend=backend)
@pytest.mark.skipif(
backend._lib.OPENSSL_VERSION_NUMBER < 0x1000000f,
reason="Requires a newer OpenSSL. Must be >= 1.0.0"
)
def test_large_key_size_on_new_openssl(self):
parameters = dsa.DSAParameters.generate(2048, backend)
assert bit_length(parameters.p) == 2048
parameters = dsa.DSAParameters.generate(3072, backend)
assert bit_length(parameters.p) == 3072
class TestOpenSSLRandomEngine(object):
def teardown_method(self, method):

View file

@ -18,12 +18,13 @@ import os
import pytest
from cryptography.exceptions import _Reasons
from cryptography.hazmat.primitives.asymmetric import dsa
from cryptography.utils import bit_length
from ...utils import (
load_vectors_from_file, load_fips_dsa_key_pair_vectors
load_vectors_from_file, load_fips_dsa_key_pair_vectors,
raises_unsupported_algorithm
)
@ -61,6 +62,7 @@ def _check_dsa_private_key(skey):
assert skey_parameters.generator == pkey_parameters.generator
@pytest.mark.dsa
class TestDSA(object):
_parameters_1024 = {
'p': 'd38311e2cd388c3ed698e82fdf88eb92b5a9a483dc88005d4b725ef341eabb47'
@ -168,11 +170,10 @@ class TestDSA(object):
def test_generate_dsa_parameters(self, backend):
parameters = dsa.DSAParameters.generate(1024, backend)
assert bit_length(parameters.p) == 1024
if backend._lib.OPENSSL_VERSION_NUMBER >= 0x1000000fL:
parameters = dsa.DSAParameters.generate(2048, backend)
assert bit_length(parameters.p) == 2048
parameters = dsa.DSAParameters.generate(3072, backend)
assert bit_length(parameters.p) == 3072
def test_generate_invalid_dsa_parameters(self, backend):
with pytest.raises(ValueError):
dsa.DSAParameters.generate(1, backend)
@pytest.mark.parametrize(
"vector",
@ -183,12 +184,9 @@ class TestDSA(object):
)
)
def test_generate_dsa_keys(self, vector, backend):
class Object(object):
pass
parameters = Object()
parameters.p = vector['p']
parameters.q = vector['q']
parameters.g = vector['g']
parameters = dsa.DSAParameters(modulus=vector['p'],
subgroup_order=vector['q'],
generator=vector['g'])
skey = dsa.DSAPrivateKey.generate(parameters, backend)
skey_parameters = skey.parameters()
@ -720,3 +718,14 @@ class TestDSA(object):
generator=int(self._parameters_1024['g'], 16),
y=None
)
def test_dsa_generate_invalid_backend():
pretend_backend = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
dsa.DSAParameters.generate(1024, pretend_backend)
pretend_parameters = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
dsa.DSAPrivateKey.generate(pretend_parameters, pretend_backend)