aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2015-03-08 22:39:49 -0400
committerAlex Gaynor <alex.gaynor@gmail.com>2015-03-08 22:39:49 -0400
commit0ee210bf4c03309512fdaad13d481548d9056237 (patch)
tree3bdb6730ce0a993f373193528e618388282e70cf
parent930fc6a24e890ac1ed044985eaf82118db542617 (diff)
parent26006c526782bba2628da1d7819550b455a3b784 (diff)
downloadcryptography-0ee210bf4c03309512fdaad13d481548d9056237.tar.gz
cryptography-0ee210bf4c03309512fdaad13d481548d9056237.tar.bz2
cryptography-0ee210bf4c03309512fdaad13d481548d9056237.zip
Merge pull request #1734 from reaperhulk/serialize-dsa-public-key
DSA public key serialization
-rw-r--r--CHANGELOG.rst8
-rw-r--r--docs/hazmat/primitives/asymmetric/dsa.rst33
-rw-r--r--docs/hazmat/primitives/asymmetric/serialization.rst6
-rw-r--r--src/cryptography/hazmat/backends/openssl/dsa.py23
-rw-r--r--src/cryptography/hazmat/primitives/asymmetric/dsa.py19
-rw-r--r--tests/hazmat/primitives/test_dsa.py45
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
+ )