diff options
-rw-r--r-- | CHANGELOG.rst | 8 | ||||
-rw-r--r-- | docs/hazmat/primitives/asymmetric/dsa.rst | 33 | ||||
-rw-r--r-- | docs/hazmat/primitives/asymmetric/serialization.rst | 6 | ||||
-rw-r--r-- | src/cryptography/hazmat/backends/openssl/dsa.py | 23 | ||||
-rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/dsa.py | 19 | ||||
-rw-r--r-- | tests/hazmat/primitives/test_dsa.py | 45 |
6 files changed, 129 insertions, 5 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e45a4ae6..da5d44d9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -123,6 +123,14 @@ Changelog :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization.public_bytes` to :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. +* Added + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization` + and deprecated + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithNumbers`. +* Added + :meth:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization.public_bytes` + to + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`. 0.7.2 - 2015-01-16 ~~~~~~~~~~~~~~~~~~ diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst index bd02423f..3c3567be 100644 --- a/docs/hazmat/primitives/asymmetric/dsa.rst +++ b/docs/hazmat/primitives/asymmetric/dsa.rst @@ -401,6 +401,39 @@ Key interfaces :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` instance. +.. class:: DSAPublicKeyWithSerialization + + .. versionadded:: 0.8 + + Extends :class:`DSAPublicKey`. + + .. method:: public_numbers() + + Create a + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` + object. + + :returns: A + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicNumbers` + instance. + + .. method:: public_bytes(encoding, format) + + Allows serialization of the key to bytes. Encoding ( + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.PEM` or + :attr:`~cryptography.hazmat.primitives.serialization.Encoding.DER`) and + format ( + :attr:`~cryptography.hazmat.primitives.serialization.PublicFormat.SubjectPublicKeyInfo`) + are chosen to define the exact serialization. + + :param encoding: A value from the + :class:`~cryptography.hazmat.primitives.serialization.Encoding` enum. + + :param format: A value from the + :class:`~cryptography.hazmat.primitives.serialization.PublicFormat` enum. + + :return bytes: Serialized key. + .. _`DSA`: https://en.wikipedia.org/wiki/Digital_Signature_Algorithm .. _`public-key`: https://en.wikipedia.org/wiki/Public-key_cryptography diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index ff69973a..7839f346 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -316,8 +316,10 @@ Serialization Formats An enumeration for public key formats. Used with the ``public_bytes`` method available on :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` - and - :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`. + , + :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization` + , and + :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPublicKeyWithSerialization`. .. attribute:: SubjectPublicKeyInfo diff --git a/src/cryptography/hazmat/backends/openssl/dsa.py b/src/cryptography/hazmat/backends/openssl/dsa.py index 8d02e492..0089f58c 100644 --- a/src/cryptography/hazmat/backends/openssl/dsa.py +++ b/src/cryptography/hazmat/backends/openssl/dsa.py @@ -7,7 +7,7 @@ from __future__ import absolute_import, division, print_function from cryptography import utils from cryptography.exceptions import InvalidSignature from cryptography.hazmat.backends.openssl.utils import _truncate_digest -from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import ( AsymmetricSignatureContext, AsymmetricVerificationContext, dsa ) @@ -208,3 +208,24 @@ class _DSAPublicKey(object): dsa_cdata.q = self._backend._lib.BN_dup(self._dsa_cdata.q) dsa_cdata.g = self._backend._lib.BN_dup(self._dsa_cdata.g) return _DSAParameters(self._backend, dsa_cdata) + + def public_bytes(self, encoding, format): + if format is serialization.PublicFormat.PKCS1: + raise ValueError( + "DSA public keys do not support PKCS1 serialization" + ) + + evp_pkey = self._backend._lib.EVP_PKEY_new() + assert evp_pkey != self._backend._ffi.NULL + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + res = self._backend._lib.EVP_PKEY_set1_DSA(evp_pkey, self._dsa_cdata) + assert res == 1 + return self._backend._public_key_bytes( + encoding, + format, + None, + evp_pkey, + None + ) diff --git a/src/cryptography/hazmat/primitives/asymmetric/dsa.py b/src/cryptography/hazmat/primitives/asymmetric/dsa.py index 084686e4..4d332f2a 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/dsa.py +++ b/src/cryptography/hazmat/primitives/asymmetric/dsa.py @@ -104,13 +104,30 @@ class DSAPublicKey(object): @six.add_metaclass(abc.ABCMeta) -class DSAPublicKeyWithNumbers(DSAPublicKey): +class DSAPublicKeyWithSerialization(DSAPublicKey): @abc.abstractmethod def public_numbers(self): """ Returns a DSAPublicNumbers. """ + @abc.abstractmethod + def public_bytes(self, encoding, format): + """ + Returns the key serialized as bytes. + """ + + +DSAPublicKeyWithNumbers = utils.deprecated( + DSAPublicKeyWithSerialization, + __name__, + ( + "The DSAPublicKeyWithNumbers interface has been renamed to " + "DSAPublicKeyWithSerialization" + ), + utils.DeprecatedIn08 +) + def generate_parameters(key_size, backend): return backend.generate_dsa_parameters(key_size) diff --git a/tests/hazmat/primitives/test_dsa.py b/tests/hazmat/primitives/test_dsa.py index 19ca0794..112818f4 100644 --- a/tests/hazmat/primitives/test_dsa.py +++ b/tests/hazmat/primitives/test_dsa.py @@ -31,7 +31,10 @@ from ...utils import ( def _skip_if_no_serialization(key, backend): - if not isinstance(key, dsa.DSAPrivateKeyWithSerialization): + if not isinstance( + key, + (dsa.DSAPrivateKeyWithSerialization, dsa.DSAPublicKeyWithSerialization) + ): pytest.skip( "{0} does not support DSA key serialization".format(backend) ) @@ -936,3 +939,43 @@ class TestDSASerialization(object): serialization.PrivateFormat.TraditionalOpenSSL, DummyKeyEncryption() ) + + +@pytest.mark.requires_backend_interface(interface=DSABackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestDSAPEMPublicKeySerialization(object): + def test_public_bytes_unencrypted_pem(self, backend): + key_bytes = load_vectors_from_file( + os.path.join("asymmetric", "PKCS8", "unenc-dsa-pkcs8.pub.pem"), + lambda pemfile: pemfile.read().encode() + ) + key = serialization.load_pem_public_key(key_bytes, backend) + _skip_if_no_serialization(key, backend) + serialized = key.public_bytes( + serialization.Encoding.PEM, + serialization.PublicFormat.SubjectPublicKeyInfo, + ) + assert serialized == key_bytes + + def test_public_bytes_invalid_encoding(self, backend): + key = DSA_KEY_2048.private_key(backend).public_key() + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes( + "notencoding", + serialization.PublicFormat.SubjectPublicKeyInfo + ) + + def test_public_bytes_invalid_format(self, backend): + key = DSA_KEY_2048.private_key(backend).public_key() + _skip_if_no_serialization(key, backend) + with pytest.raises(TypeError): + key.public_bytes(serialization.Encoding.PEM, "invalidformat") + + def test_public_bytes_pkcs1_unsupported(self, backend): + key = DSA_KEY_2048.private_key(backend).public_key() + _skip_if_no_serialization(key, backend) + with pytest.raises(ValueError): + key.public_bytes( + serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 + ) |