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 ++++++++++++++++++---- 1 file changed, 45 insertions(+), 8 deletions(-) (limited to 'src') 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]) -- cgit v1.2.3