From 2c2d182cf781361117402f5dd0d8f9ee5387fd1a Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:34:37 -0800 Subject: Fixes #1533 -- Initial work at parsing ECDSA public keys in OpenSSH format --- .../hazmat/primitives/serialization.py | 53 ++++++++++++++++++---- tests/hazmat/primitives/test_serialization.py | 27 ++++++++++- 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 083f17e5..67f8a644 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -7,11 +7,10 @@ from __future__ import absolute_import, division, print_function import base64 import struct +import six + from cryptography.exceptions import UnsupportedAlgorithm -from cryptography.hazmat.primitives.asymmetric.dsa import ( - DSAParameterNumbers, DSAPublicNumbers -) -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa def load_pem_private_key(data, password, backend): @@ -41,6 +40,10 @@ def load_ssh_public_key(data, backend): return _load_ssh_rsa_public_key(decoded_data, backend) elif key_type == b'ssh-dss': return _load_ssh_dss_public_key(decoded_data, backend) + elif key_type in [ + b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', + ]: + return _load_ssh_ecdsa_public_key(key_type, decoded_data, backend) else: raise UnsupportedAlgorithm( 'Only RSA and DSA keys are currently supported.' @@ -59,7 +62,7 @@ def _load_ssh_rsa_public_key(decoded_data, backend): if rest: raise ValueError('Key body contains extra bytes.') - return RSAPublicNumbers(e, n).public_key(backend) + return rsa.RSAPublicNumbers(e, n).public_key(backend) def _load_ssh_dss_public_key(decoded_data, backend): @@ -71,17 +74,51 @@ def _load_ssh_dss_public_key(decoded_data, backend): if key_type != b'ssh-dss': raise ValueError( - 'Key header and key body contain different key type values.') + 'Key header and key body contain different key type values.' + ) if rest: raise ValueError('Key body contains extra bytes.') - parameter_numbers = DSAParameterNumbers(p, q, g) - public_numbers = DSAPublicNumbers(y, parameter_numbers) + parameter_numbers = dsa.DSAParameterNumbers(p, q, g) + public_numbers = dsa.DSAPublicNumbers(y, parameter_numbers) return public_numbers.public_key(backend) +def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): + key_type, rest = _read_next_string(decoded_data) + curve_name, rest = _read_next_string(rest) + data, rest = _read_next_string(rest) + + if key_type != expected_key_type != b"ecdsa-sha2" + curve_name: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + + if rest: + raise ValueError('Key body contains extra bytes.') + + if key_type == "ecdsa-sha2-nistp256": + curve = ec.SECP256R1() + elif key_type == "ecdsa-sha2-nistp384": + curve = ec.SECP384R1() + elif key_type == "ecdsa-sha2-nistp521": + curve = ec.SECP521R1() + + if len(data) != 1 + 2 * (curve.key_size // 8): + raise ValueError("Malformed key bytes") + + if six.indexbytes(data, 0) != 4: + raise NotImplementedError( + "Compressed elliptic curve points are not supported" + ) + + x = _int_from_bytes(data[1:1 + curve.key_size // 8], byteorder='big') + y = _int_from_bytes(data[1 + curve.key_size // 8:], byteorder='big') + return ec.EllipticCurvePublicNumbers(x, y, curve).public_key(backend) + + def _read_next_string(data): """Retrieves the next RFC 4251 string value from the data.""" str_len, = struct.unpack('>I', data[:4]) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index f3166d7b..10afa9d5 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -576,7 +576,7 @@ class TestPEMSerialization(object): @pytest.mark.requires_backend_interface(interface=RSABackend) class TestRSASSHSerialization(object): def test_load_ssh_public_key_unsupported(self, backend): - ssh_key = b'ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=' + ssh_key = b'ecdsa-sha2-junk AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY=' with pytest.raises(UnsupportedAlgorithm): load_ssh_public_key(ssh_key, backend) @@ -784,3 +784,28 @@ class TestDSSSSHSerialization(object): ) assert numbers == expected + + +@pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) +class TestECDSASSHSerialization(object): + def test_load_ssh_public_key_ecdsa_nist_p256(self, backend): + ssh_key = ( + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" + ) + key = load_ssh_public_key(ssh_key, backend) + assert isinstance(key, interfaces.EllipticCurvePublicKey) + + expected_x = int( + "44196257377740326295529888716212621920056478823906609851236662550" + "785814128027", 10 + ) + expected_y = int( + "12257763433170736656417248739355923610241609728032203358057767672" + "925775019611", 10 + ) + + assert key.public_numbers() == ec.EllipticCurvePublicNumbers( + expected_x, expected_y, ec.SECP256R1() + ) -- cgit v1.2.3 From 6db8f988b8f920b7ea7786479e00b8b2b8a96f70 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:36:14 -0800 Subject: Update the docs a bit --- docs/hazmat/primitives/asymmetric/serialization.rst | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index b523c342..f0f18fd8 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -201,9 +201,6 @@ OpenSSH Public Key The format used by OpenSSH to store public keys, as specified in :rfc:`4253`. -Currently, only RSA and DSA public keys are supported. Any other type of key -will result in an exception being thrown. - An example RSA key in OpenSSH format (line breaks added for formatting purposes):: @@ -216,7 +213,8 @@ purposes):: 2MzHvnbv testkey@localhost DSA keys look almost identical but begin with ``ssh-dss`` rather than -``ssh-rsa``. +``ssh-rsa``. ECDSA keys have a slightly different format, they begin with +``ecdsa-sha2-{curve}``. .. function:: load_ssh_public_key(data, backend) @@ -228,9 +226,10 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than :param bytes data: The OpenSSH encoded key data. :param backend: A backend providing - :class:`~cryptography.hazmat.backends.interfaces.RSABackend` or - :class:`~cryptography.hazmat.backends.interfaces.DSABackend` depending - on key type. + :class:`~cryptography.hazmat.backends.interfaces.RSABackend`, + :class:`~cryptography.hazmat.backends.interfaces.DSABackend`, or + :class:`~cryptography.hazmat.backends.interfaces.EllipticCurveBackend` + depending on the key's type. :returns: A new instance of a public key type. -- cgit v1.2.3 From a4d59a9fea7ba549472b1a61af5f8c635f00d6c1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:41:53 -0800 Subject: Attempt to remove some duplication --- .../hazmat/primitives/serialization.py | 50 +++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 67f8a644..8a1c7ed6 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -29,6 +29,13 @@ def load_ssh_public_key(data, backend): 'Key is not in the proper format or contains extra data.') key_type = key_parts[0] + + if key_type not in [ + b'ssh-rsa', b'ssh-dss', b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', + b'ecdsa-sha2-nistp521', + ]: + raise UnsupportedAlgorithm('Key type is not supported.') + key_body = key_parts[1] try: @@ -36,29 +43,27 @@ def load_ssh_public_key(data, backend): except TypeError: raise ValueError('Key is not in the proper format.') + inner_key_type, rest = _read_next_string(decoded_data) + + if inner_key_type != key_type: + raise ValueError( + 'Key header and key body contain different key type values.' + ) + if key_type == b'ssh-rsa': - return _load_ssh_rsa_public_key(decoded_data, backend) + return _load_ssh_rsa_public_key(rest, backend) elif key_type == b'ssh-dss': - return _load_ssh_dss_public_key(decoded_data, backend) + return _load_ssh_dss_public_key(rest, backend) elif key_type in [ b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', ]: - return _load_ssh_ecdsa_public_key(key_type, decoded_data, backend) - else: - raise UnsupportedAlgorithm( - 'Only RSA and DSA keys are currently supported.' - ) + return _load_ssh_ecdsa_public_key(key_type, rest, backend) def _load_ssh_rsa_public_key(decoded_data, backend): - key_type, rest = _read_next_string(decoded_data) - e, rest = _read_next_mpint(rest) + e, rest = _read_next_mpint(decoded_data) n, rest = _read_next_mpint(rest) - if key_type != b'ssh-rsa': - raise ValueError( - 'Key header and key body contain different key type values.') - if rest: raise ValueError('Key body contains extra bytes.') @@ -66,17 +71,11 @@ def _load_ssh_rsa_public_key(decoded_data, backend): def _load_ssh_dss_public_key(decoded_data, backend): - key_type, rest = _read_next_string(decoded_data) - p, rest = _read_next_mpint(rest) + p, rest = _read_next_mpint(decoded_data) q, rest = _read_next_mpint(rest) g, rest = _read_next_mpint(rest) y, rest = _read_next_mpint(rest) - if key_type != b'ssh-dss': - raise ValueError( - 'Key header and key body contain different key type values.' - ) - if rest: raise ValueError('Key body contains extra bytes.') @@ -87,11 +86,10 @@ def _load_ssh_dss_public_key(decoded_data, backend): def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): - key_type, rest = _read_next_string(decoded_data) - curve_name, rest = _read_next_string(rest) + curve_name, rest = _read_next_string(decoded_data) data, rest = _read_next_string(rest) - if key_type != expected_key_type != b"ecdsa-sha2" + curve_name: + if expected_key_type != b"ecdsa-sha2-" + curve_name: raise ValueError( 'Key header and key body contain different key type values.' ) @@ -99,11 +97,11 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): if rest: raise ValueError('Key body contains extra bytes.') - if key_type == "ecdsa-sha2-nistp256": + if curve_name == "nistp256": curve = ec.SECP256R1() - elif key_type == "ecdsa-sha2-nistp384": + elif curve_name == "nistp384": curve = ec.SECP384R1() - elif key_type == "ecdsa-sha2-nistp521": + elif curve_name == "nistp521": curve = ec.SECP521R1() if len(data) != 1 + 2 * (curve.key_size // 8): -- cgit v1.2.3 From d9aa3fbfa2fd15aa9c40a495ebbd972de2dde4de Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:52:04 -0800 Subject: Reduce the duplication --- .../hazmat/primitives/serialization.py | 24 ++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 8a1c7ed6..777bcc28 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -30,10 +30,15 @@ def load_ssh_public_key(data, backend): key_type = key_parts[0] - if key_type not in [ - b'ssh-rsa', b'ssh-dss', b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', - b'ecdsa-sha2-nistp521', + if key_type == b'ssh-rsa': + loader = _load_ssh_rsa_public_key + elif key_type == b'ssh-dss': + loader = _load_ssh_dss_public_key + elif key_type in [ + b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', ]: + loader = _load_ssh_ecdsa_public_key + else: raise UnsupportedAlgorithm('Key type is not supported.') key_body = key_parts[1] @@ -50,17 +55,10 @@ def load_ssh_public_key(data, backend): 'Key header and key body contain different key type values.' ) - if key_type == b'ssh-rsa': - return _load_ssh_rsa_public_key(rest, backend) - elif key_type == b'ssh-dss': - return _load_ssh_dss_public_key(rest, backend) - elif key_type in [ - b'ecdsa-sha2-nistp256', b'ecdsa-sha2-nistp384', b'ecdsa-sha2-nistp521', - ]: - return _load_ssh_ecdsa_public_key(key_type, rest, backend) + return loader(key_type, rest, backend) -def _load_ssh_rsa_public_key(decoded_data, backend): +def _load_ssh_rsa_public_key(key_type, decoded_data, backend): e, rest = _read_next_mpint(decoded_data) n, rest = _read_next_mpint(rest) @@ -70,7 +68,7 @@ def _load_ssh_rsa_public_key(decoded_data, backend): return rsa.RSAPublicNumbers(e, n).public_key(backend) -def _load_ssh_dss_public_key(decoded_data, backend): +def _load_ssh_dss_public_key(key_type, decoded_data, backend): p, rest = _read_next_mpint(decoded_data) q, rest = _read_next_mpint(rest) g, rest = _read_next_mpint(rest) -- cgit v1.2.3 From 1a7d64e1bfd3e5d3877d3742388ac458bb64faa0 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:54:36 -0800 Subject: THese are bytes for py3k --- src/cryptography/hazmat/primitives/serialization.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 777bcc28..448062d5 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -95,11 +95,11 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): if rest: raise ValueError('Key body contains extra bytes.') - if curve_name == "nistp256": + if curve_name == b"nistp256": curve = ec.SECP256R1() - elif curve_name == "nistp384": + elif curve_name == b"nistp384": curve = ec.SECP384R1() - elif curve_name == "nistp521": + elif curve_name == b"nistp521": curve = ec.SECP521R1() if len(data) != 1 + 2 * (curve.key_size // 8): -- cgit v1.2.3 From 4b223434b4ca96de265334df036689264a82f9b8 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 14:55:06 -0800 Subject: Improved docstring --- src/cryptography/hazmat/primitives/serialization.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index 448062d5..b95ac1cd 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -116,7 +116,11 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): def _read_next_string(data): - """Retrieves the next RFC 4251 string value from the data.""" + """ + Retrieves the next RFC 4251 string value from the data. + + While the RFC calls these strings, in Python they are bytes objects. + """ str_len, = struct.unpack('>I', data[:4]) return data[4:4 + str_len], data[4 + str_len:] -- cgit v1.2.3 From eeb8143a716c995dcd9c4cb883ce8b538735b0a1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 15:49:25 -0800 Subject: Bring back text about unsupported formats --- docs/hazmat/primitives/asymmetric/serialization.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst index f0f18fd8..9ca493ab 100644 --- a/docs/hazmat/primitives/asymmetric/serialization.rst +++ b/docs/hazmat/primitives/asymmetric/serialization.rst @@ -223,6 +223,10 @@ DSA keys look almost identical but begin with ``ssh-dss`` rather than Deserialize a public key from OpenSSH (:rfc:`4253`) encoded data to an instance of the public key type for the specified backend. + .. note:: + + Currently Ed25519 keys are not supported. + :param bytes data: The OpenSSH encoded key data. :param backend: A backend providing -- cgit v1.2.3 From bf4817e9d95d66f5adba8ab5b7224e865e312a45 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Wed, 24 Dec 2014 16:20:42 -0800 Subject: this test requires a specific curve --- tests/hazmat/primitives/test_serialization.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 10afa9d5..acdbbd73 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -789,6 +789,8 @@ class TestDSSSSHSerialization(object): @pytest.mark.requires_backend_interface(interface=EllipticCurveBackend) class TestECDSASSHSerialization(object): def test_load_ssh_public_key_ecdsa_nist_p256(self, backend): + _skip_curve_unsupported(backend, ec.SECP256R1()) + ssh_key = ( b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" -- cgit v1.2.3 From abc4666addc0b985c95815bf18eb2868f504fc19 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 25 Dec 2014 08:05:49 -0800 Subject: Write some tests for failure cases --- tests/hazmat/primitives/test_serialization.py | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index acdbbd73..2434ee45 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -811,3 +811,32 @@ class TestECDSASSHSerialization(object): assert key.public_numbers() == ec.EllipticCurvePublicNumbers( expected_x, expected_y, ec.SECP256R1() ) + + def test_load_ssh_public_key_ecdsa_nist_p256_trailing_data(self, backend): + ssh_key = ( + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCFPltB= root@cloud-server-01" + ) + with pytest.raises(ValueError): + load_ssh_public_key(ssh_key, backend) + + def test_load_ssh_public_key_ecdsa_nist_p256_missing_data(self, backend): + ssh_key = ( + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTYAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCF= root@cloud-server-01" + ) + with pytest.raises(ValueError): + load_ssh_public_key(ssh_key, backend) + + def test_load_ssh_public_key_ecdsa_nist_p256_compressed(self, backend): + # If we ever implement compressed points, note that this is not a valid + # one, it just has the compressed marker in the right place. + ssh_key = ( + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTYAAABBAWG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" + ) + with pytest.raises(NotImplementedError): + load_ssh_public_key(ssh_key, backend) -- cgit v1.2.3 From 8165db59374c7ce83e3ad34abf883195d1ec7b8b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 25 Dec 2014 08:34:42 -0800 Subject: Added test cases for NIST P-384 and 521. Fixed handling of key sizes which aren't divisibly by 8 --- .../hazmat/primitives/serialization.py | 12 +++--- tests/hazmat/primitives/test_serialization.py | 49 ++++++++++++++++++++++ 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py index b95ac1cd..dad419fe 100644 --- a/src/cryptography/hazmat/primitives/serialization.py +++ b/src/cryptography/hazmat/primitives/serialization.py @@ -102,16 +102,18 @@ def _load_ssh_ecdsa_public_key(expected_key_type, decoded_data, backend): elif curve_name == b"nistp521": curve = ec.SECP521R1() - if len(data) != 1 + 2 * (curve.key_size // 8): - raise ValueError("Malformed key bytes") - if six.indexbytes(data, 0) != 4: raise NotImplementedError( "Compressed elliptic curve points are not supported" ) - x = _int_from_bytes(data[1:1 + curve.key_size // 8], byteorder='big') - y = _int_from_bytes(data[1 + curve.key_size // 8:], byteorder='big') + # key_size is in bits, and sometimes it's not evenly divisible by 8, so we + # add 7 to round up the number of bytes. + if len(data) != 1 + 2 * ((curve.key_size + 7) // 8): + raise ValueError("Malformed key bytes") + + x = _int_from_bytes(data[1:1 + (curve.key_size + 7) // 8], byteorder='big') + y = _int_from_bytes(data[1 + (curve.key_size + 7) // 8:], byteorder='big') return ec.EllipticCurvePublicNumbers(x, y, curve).public_key(backend) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index 2434ee45..fdd88a82 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -812,6 +812,55 @@ class TestECDSASSHSerialization(object): expected_x, expected_y, ec.SECP256R1() ) + def test_load_ssh_public_key_ecdsa_nist_p384(self, backend): + _skip_curve_unsupported(backend, ec.SECP384R1()) + ssh_key = ( + b"ecdsa-sha2-nistp384 AAAAE2VjZHNhLXNoYTItbmlzdHAzODQAAAAIbmlzdHAz" + b"ODQAAABhBMzucOm9wbwg4iMr5QL0ya0XNQGXpw4wM5f12E3tWhdcrzyGHyel71t1" + b"4bvF9JZ2/WIuSxUr33XDl8jYo+lMQ5N7Vanc7f7i3AR1YydatL3wQfZStQ1I3rBa" + b"qQtRSEU8Tg== root@cloud-server-01" + ) + key = load_ssh_public_key(ssh_key, backend) + + expected_x = int( + "31541830871345183397582554827482786756220448716666815789487537666" + "592636882822352575507883817901562613492450642523901", 10 + ) + expected_y = int( + "15111413269431823234030344298767984698884955023183354737123929430" + "995703524272335782455051101616329050844273733614670", 10 + ) + + assert key.public_numbers() == ec.EllipticCurvePublicNumbers( + expected_x, expected_y, ec.SECP384R1() + ) + + def test_load_ssh_public_key_ecdsa_nist_p521(self, backend): + _skip_curve_unsupported(backend, ec.SECP521R1()) + ssh_key = ( + b"ecdsa-sha2-nistp521 AAAAE2VjZHNhLXNoYTItbmlzdHA1MjEAAAAIbmlzdHA1" + b"MjEAAACFBAGTrRhMSEgF6Ni+PXNz+5fjS4lw3ypUILVVQ0Av+0hQxOx+MyozELon" + b"I8NKbrbBjijEs1GuImsmkTmWsMXS1j2A7wB4Kseh7W9KA9IZJ1+TMrzWUEwvOOXi" + b"wT23pbaWWXG4NaM7vssWfZBnvz3S174TCXnJ+DSccvWBFnKP0KchzLKxbg== " + b"root@cloud-server-01" + ) + key = load_ssh_public_key(ssh_key, backend) + + expected_x = int( + "54124123120178189598842622575230904027376313369742467279346415219" + "77809037378785192537810367028427387173980786968395921877911964629" + "142163122798974160187785455", 10 + ) + expected_y = int( + "16111775122845033200938694062381820957441843014849125660011303579" + "15284560361402515564433711416776946492019498546572162801954089916" + "006665939539407104638103918", 10 + ) + + assert key.public_numbers() == ec.EllipticCurvePublicNumbers( + expected_x, expected_y, ec.SECP521R1() + ) + def test_load_ssh_public_key_ecdsa_nist_p256_trailing_data(self, backend): ssh_key = ( b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" -- cgit v1.2.3 From 9dd8005cc0acfad841245187c3373501d801fe0c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 25 Dec 2014 09:46:33 -0800 Subject: Get us up to 100% coverage --- tests/hazmat/primitives/test_serialization.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py index fdd88a82..8c79f640 100644 --- a/tests/hazmat/primitives/test_serialization.py +++ b/tests/hazmat/primitives/test_serialization.py @@ -889,3 +889,13 @@ class TestECDSASSHSerialization(object): ) with pytest.raises(NotImplementedError): load_ssh_public_key(ssh_key, backend) + + def test_load_ssh_public_key_ecdsa_nist_p256_bad_curve_name(self, backend): + ssh_key = ( + # The curve name in here is changed to be "nistp255". + b"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAy" + b"NTUAAABBBGG2MfkHXp0UkxUyllDzWNBAImsvt5t7pFtTXegZK2WbGxml8zMrgWi5" + b"teIg1TO03/FD9hbpBFgBeix3NrCFPls= root@cloud-server-01" + ) + with pytest.raises(ValueError): + load_ssh_public_key(ssh_key, backend) -- cgit v1.2.3 From 5d66ca55d9fb17b06882a5a0ae1c1da3200ea148 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Thu, 25 Dec 2014 18:39:39 -0800 Subject: Added a changelog entry --- CHANGELOG.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b777d45a..1ceb39d2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ Changelog .. note:: This version is not yet released and is under active development. +* :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` can + now load elliptic curve public keys. + 0.7 - 2014-12-17 ~~~~~~~~~~~~~~~~ -- cgit v1.2.3