diff options
author | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-03-05 21:01:16 -0600 |
---|---|---|
committer | Paul Kehrer <paul.l.kehrer@gmail.com> | 2015-03-08 15:50:17 -0500 |
commit | 419615b0cf02d3763b7da208d7118b39e5f25a3b (patch) | |
tree | f4e0eeacb33dfa03ad734c4aa2c8e6222edf59df | |
parent | 88e7ed6415ccf7fb2432b90876deefa8ab88cc98 (diff) | |
download | cryptography-419615b0cf02d3763b7da208d7118b39e5f25a3b.tar.gz cryptography-419615b0cf02d3763b7da208d7118b39e5f25a3b.tar.bz2 cryptography-419615b0cf02d3763b7da208d7118b39e5f25a3b.zip |
serialize EC public keys
-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 + ) |