diff options
| -rw-r--r-- | CHANGELOG.rst | 8 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/ec.rst | 30 | ||||
| -rw-r--r-- | docs/hazmat/primitives/asymmetric/serialization.rst | 8 | ||||
| -rw-r--r-- | src/cryptography/hazmat/backends/openssl/ec.py | 23 | ||||
| -rw-r--r-- | src/cryptography/hazmat/primitives/asymmetric/ec.py | 19 | ||||
| -rw-r--r-- | tests/hazmat/primitives/test_ec.py | 70 | 
6 files changed, 153 insertions, 5 deletions
| diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 86628946..e45a4ae6 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -115,6 +115,14 @@ Changelog    :meth:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization.public_bytes`    to    :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`. +* Added +  :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization` +  and deprecated +  :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithNumbers`. +* Added +  :meth:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization.public_bytes` +  to +  :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKeyWithSerialization`.  0.7.2 - 2015-01-16  ~~~~~~~~~~~~~~~~~~ diff --git a/docs/hazmat/primitives/asymmetric/ec.rst b/docs/hazmat/primitives/asymmetric/ec.rst index 256c1832..6c03d773 100644 --- a/docs/hazmat/primitives/asymmetric/ec.rst +++ b/docs/hazmat/primitives/asymmetric/ec.rst @@ -405,6 +405,36 @@ Key Interfaces          :returns: An :class:`EllipticCurvePublicNumbers` instance. +.. class:: EllipticCurvePublicKeyWithSerialization + +    .. versionadded:: 0.6 + +    Extends :class:`EllipticCurvePublicKey`. + +    .. method:: public_numbers() + +        Create a :class:`EllipticCurvePublicNumbers` object. + +        :returns: An :class:`EllipticCurvePublicNumbers` 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. + +  .. _`FIPS 186-3`: http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf  .. _`FIPS 186-4`: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf  .. _`some concern`: https://crypto.stackexchange.com/questions/10263/should-we-trust-the-nist-recommended-ecc-parameters diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index fb8c93a4..e4b2d68b 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -315,7 +315,9 @@ Serialization Formats      An enumeration for public key formats. Used with the ``public_bytes``      method available on -    :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`. +    :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization` +    and +    :class:`~cryptography.hazmat.primitives.asymmetric.rsa.EllipticCurvePublicKeyWithSerialization`.      .. attribute:: SubjectPublicKeyInfo @@ -341,7 +343,9 @@ Serialization Encodings      ,      :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKeyWithSerialization`      and -    :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization`. +    :class:`~cryptography.hazmat.primitives.asymmetric.dsa.DSAPrivateKeyWithSerialization` +    as well as ``public_bytes`` on +    :class:`~cryptography.hazmat.primitives.asymmetric.rsa.RSAPublicKeyWithSerialization`.      .. attribute:: PEM diff --git a/src/cryptography/hazmat/backends/openssl/ec.py b/src/cryptography/hazmat/backends/openssl/ec.py index 19d646e8..39b0a555 100644 --- a/src/cryptography/hazmat/backends/openssl/ec.py +++ b/src/cryptography/hazmat/backends/openssl/ec.py @@ -9,7 +9,7 @@ from cryptography.exceptions import (      InvalidSignature, UnsupportedAlgorithm, _Reasons  )  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, ec  ) @@ -262,3 +262,24 @@ class _EllipticCurvePublicKey(object):              y=y,              curve=self._curve          ) + +    def public_bytes(self, encoding, format): +        if format is serialization.PublicFormat.PKCS1: +            raise ValueError( +                "EC 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_EC_KEY(evp_pkey, self._ec_key) +        assert res == 1 +        return self._backend._public_key_bytes( +            encoding, +            format, +            None, +            evp_pkey, +            None +        ) diff --git a/src/cryptography/hazmat/primitives/asymmetric/ec.py b/src/cryptography/hazmat/primitives/asymmetric/ec.py index 52e14816..bf1705db 100644 --- a/src/cryptography/hazmat/primitives/asymmetric/ec.py +++ b/src/cryptography/hazmat/primitives/asymmetric/ec.py @@ -98,13 +98,30 @@ class EllipticCurvePublicKey(object):  @six.add_metaclass(abc.ABCMeta) -class EllipticCurvePublicKeyWithNumbers(EllipticCurvePublicKey): +class EllipticCurvePublicKeyWithSerialization(EllipticCurvePublicKey):      @abc.abstractmethod      def public_numbers(self):          """          Returns an EllipticCurvePublicNumbers.          """ +    @abc.abstractmethod +    def public_bytes(self, encoding, format): +        """ +        Returns the key serialized as bytes. +        """ + + +EllipticCurvePublicKeyWithNumbers = utils.deprecated( +    EllipticCurvePublicKeyWithSerialization, +    __name__, +    ( +        "The EllipticCurvePublicKeyWithNumbers interface has been renamed to " +        "EllipticCurvePublicKeyWithSerialization" +    ), +    utils.DeprecatedIn08 +) +  @utils.register_interface(EllipticCurve)  class SECT571R1(object): diff --git a/tests/hazmat/primitives/test_ec.py b/tests/hazmat/primitives/test_ec.py index 77ee38b4..73201f8e 100644 --- a/tests/hazmat/primitives/test_ec.py +++ b/tests/hazmat/primitives/test_ec.py @@ -34,7 +34,12 @@ _HASH_TYPES = {  def _skip_if_no_serialization(key, backend): -    if not isinstance(key, ec.EllipticCurvePrivateKeyWithSerialization): +    if not isinstance( +        key, ( +            ec.EllipticCurvePrivateKeyWithSerialization, +            ec.EllipticCurvePublicKeyWithSerialization +        ) +    ):          pytest.skip(              "{0} does not support EC key serialization".format(backend)          ) @@ -548,3 +553,66 @@ class TestECSerialization(object):                  serialization.PrivateFormat.TraditionalOpenSSL,                  DummyKeyEncryption()              ) + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +@pytest.mark.requires_backend_interface(interface=PEMSerializationBackend) +class TestEllipticCurvePEMPublicKeySerialization(object): +    def test_public_bytes_unencrypted_pem(self, backend): +        key_bytes = load_vectors_from_file( +            os.path.join( +                "asymmetric", "PEM_Serialization", "ec_public_key.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 = load_vectors_from_file( +            os.path.join( +                "asymmetric", "PEM_Serialization", "ec_public_key.pem" +            ), +            lambda pemfile: serialization.load_pem_public_key( +                pemfile.read().encode(), backend +            ) +        ) +        _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 = load_vectors_from_file( +            os.path.join( +                "asymmetric", "PEM_Serialization", "ec_public_key.pem" +            ), +            lambda pemfile: serialization.load_pem_public_key( +                pemfile.read().encode(), backend +            ) +        ) +        _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 = load_vectors_from_file( +            os.path.join( +                "asymmetric", "PEM_Serialization", "ec_public_key.pem" +            ), +            lambda pemfile: serialization.load_pem_public_key( +                pemfile.read().encode(), backend +            ) +        ) +        _skip_if_no_serialization(key, backend) +        with pytest.raises(ValueError): +            key.public_bytes( +                serialization.Encoding.PEM, serialization.PublicFormat.PKCS1 +            ) | 
