aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2014-12-24 14:34:37 -0800
committerAlex Gaynor <alex.gaynor@gmail.com>2014-12-24 14:34:37 -0800
commit2c2d182cf781361117402f5dd0d8f9ee5387fd1a (patch)
treebf5e9899bc70a54482bc0d0221a97373358b998e /src
parent06f6a4e7b2e89e588c75c4bf755c1bd0563f9e28 (diff)
downloadcryptography-2c2d182cf781361117402f5dd0d8f9ee5387fd1a.tar.gz
cryptography-2c2d182cf781361117402f5dd0d8f9ee5387fd1a.tar.bz2
cryptography-2c2d182cf781361117402f5dd0d8f9ee5387fd1a.zip
Fixes #1533 -- Initial work at parsing ECDSA public keys in OpenSSH format
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py53
1 files changed, 45 insertions, 8 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])