aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlex Gaynor <alex.gaynor@gmail.com>2018-11-23 18:43:06 -0600
committerPaul Kehrer <paul.l.kehrer@gmail.com>2018-11-24 08:43:06 +0800
commitc8dd3c02e5ea1cbccd0df9c2cfa29582c8d25ed6 (patch)
tree056437ff1d5bf1c1b465c798c13c2a638fafc2f0 /src
parentbf621bafc55f225f9532ea29a0a88702a93c232e (diff)
downloadcryptography-c8dd3c02e5ea1cbccd0df9c2cfa29582c8d25ed6.tar.gz
cryptography-c8dd3c02e5ea1cbccd0df9c2cfa29582c8d25ed6.tar.bz2
cryptography-c8dd3c02e5ea1cbccd0df9c2cfa29582c8d25ed6.zip
Move SSH serialization to it's own file (#4607)
* Move SSH serialization to it's own file * flake8
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py26
-rw-r--r--src/cryptography/hazmat/primitives/serialization/__init__.py4
-rw-r--r--src/cryptography/hazmat/primitives/serialization/base.py133
-rw-r--r--src/cryptography/hazmat/primitives/serialization/ssh.py143
4 files changed, 158 insertions, 148 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index 5d73a7e8..44c2e3cd 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -75,9 +75,7 @@ from cryptography.hazmat.primitives.ciphers.modes import (
CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS
)
from cryptography.hazmat.primitives.kdf import scrypt
-from cryptography.hazmat.primitives.serialization.base import (
- _ssh_write_mpint, _ssh_write_string
-)
+from cryptography.hazmat.primitives.serialization import ssh
from cryptography.x509 import ocsp
@@ -1798,19 +1796,19 @@ class Backend(object):
if isinstance(key, rsa.RSAPublicKey):
public_numbers = key.public_numbers()
return b"ssh-rsa " + base64.b64encode(
- _ssh_write_string(b"ssh-rsa") +
- _ssh_write_mpint(public_numbers.e) +
- _ssh_write_mpint(public_numbers.n)
+ ssh._ssh_write_string(b"ssh-rsa") +
+ ssh._ssh_write_mpint(public_numbers.e) +
+ ssh._ssh_write_mpint(public_numbers.n)
)
elif isinstance(key, dsa.DSAPublicKey):
public_numbers = key.public_numbers()
parameter_numbers = public_numbers.parameter_numbers
return b"ssh-dss " + base64.b64encode(
- _ssh_write_string(b"ssh-dss") +
- _ssh_write_mpint(parameter_numbers.p) +
- _ssh_write_mpint(parameter_numbers.q) +
- _ssh_write_mpint(parameter_numbers.g) +
- _ssh_write_mpint(public_numbers.y)
+ ssh._ssh_write_string(b"ssh-dss") +
+ ssh._ssh_write_mpint(parameter_numbers.p) +
+ ssh._ssh_write_mpint(parameter_numbers.q) +
+ ssh._ssh_write_mpint(parameter_numbers.g) +
+ ssh._ssh_write_mpint(public_numbers.y)
)
else:
assert isinstance(key, ec.EllipticCurvePublicKey)
@@ -1827,9 +1825,9 @@ class Backend(object):
"supported by the SSH public key format"
)
return b"ecdsa-sha2-" + curve_name + b" " + base64.b64encode(
- _ssh_write_string(b"ecdsa-sha2-" + curve_name) +
- _ssh_write_string(curve_name) +
- _ssh_write_string(public_numbers.encode_point())
+ ssh._ssh_write_string(b"ecdsa-sha2-" + curve_name) +
+ ssh._ssh_write_string(curve_name) +
+ ssh._ssh_write_string(public_numbers.encode_point())
)
def _parameter_bytes(self, encoding, format, cdata):
diff --git a/src/cryptography/hazmat/primitives/serialization/__init__.py b/src/cryptography/hazmat/primitives/serialization/__init__.py
index cff775b8..3a34bf8f 100644
--- a/src/cryptography/hazmat/primitives/serialization/__init__.py
+++ b/src/cryptography/hazmat/primitives/serialization/__init__.py
@@ -9,7 +9,9 @@ from cryptography.hazmat.primitives.serialization.base import (
NoEncryption, ParameterFormat, PrivateFormat, PublicFormat,
load_der_parameters, load_der_private_key, load_der_public_key,
load_pem_parameters, load_pem_private_key, load_pem_public_key,
- load_ssh_public_key,
+)
+from cryptography.hazmat.primitives.serialization.ssh import (
+ load_ssh_public_key
)
__all__ = [
diff --git a/src/cryptography/hazmat/primitives/serialization/base.py b/src/cryptography/hazmat/primitives/serialization/base.py
index bd09e6e3..5dd0c639 100644
--- a/src/cryptography/hazmat/primitives/serialization/base.py
+++ b/src/cryptography/hazmat/primitives/serialization/base.py
@@ -5,15 +5,11 @@
from __future__ import absolute_import, division, print_function
import abc
-import base64
-import struct
from enum import Enum
import six
from cryptography import utils
-from cryptography.exceptions import UnsupportedAlgorithm
-from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
def load_pem_private_key(data, password, backend):
@@ -40,135 +36,6 @@ def load_der_parameters(data, backend):
return backend.load_der_parameters(data)
-def load_ssh_public_key(data, backend):
- key_parts = data.split(b' ', 2)
-
- if len(key_parts) < 2:
- raise ValueError(
- 'Key is not in the proper format or contains extra data.')
-
- key_type = key_parts[0]
-
- 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]
-
- try:
- decoded_data = base64.b64decode(key_body)
- except TypeError:
- raise ValueError('Key is not in the proper format.')
-
- inner_key_type, rest = _ssh_read_next_string(decoded_data)
-
- if inner_key_type != key_type:
- raise ValueError(
- 'Key header and key body contain different key type values.'
- )
-
- return loader(key_type, rest, backend)
-
-
-def _load_ssh_rsa_public_key(key_type, decoded_data, backend):
- e, rest = _ssh_read_next_mpint(decoded_data)
- n, rest = _ssh_read_next_mpint(rest)
-
- if rest:
- raise ValueError('Key body contains extra bytes.')
-
- return rsa.RSAPublicNumbers(e, n).public_key(backend)
-
-
-def _load_ssh_dss_public_key(key_type, decoded_data, backend):
- p, rest = _ssh_read_next_mpint(decoded_data)
- q, rest = _ssh_read_next_mpint(rest)
- g, rest = _ssh_read_next_mpint(rest)
- y, rest = _ssh_read_next_mpint(rest)
-
- if rest:
- raise ValueError('Key body contains extra bytes.')
-
- 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):
- curve_name, rest = _ssh_read_next_string(decoded_data)
- data, rest = _ssh_read_next_string(rest)
-
- if 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.')
-
- curve = {
- b"nistp256": ec.SECP256R1,
- b"nistp384": ec.SECP384R1,
- b"nistp521": ec.SECP521R1,
- }[curve_name]()
-
- if six.indexbytes(data, 0) != 4:
- raise NotImplementedError(
- "Compressed elliptic curve points are not supported"
- )
-
- numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(curve, data)
- return numbers.public_key(backend)
-
-
-def _ssh_read_next_string(data):
- """
- Retrieves the next RFC 4251 string value from the data.
-
- While the RFC calls these strings, in Python they are bytes objects.
- """
- if len(data) < 4:
- raise ValueError("Key is not in the proper format")
-
- str_len, = struct.unpack('>I', data[:4])
- if len(data) < str_len + 4:
- raise ValueError("Key is not in the proper format")
-
- return data[4:4 + str_len], data[4 + str_len:]
-
-
-def _ssh_read_next_mpint(data):
- """
- Reads the next mpint from the data.
-
- Currently, all mpints are interpreted as unsigned.
- """
- mpint_data, rest = _ssh_read_next_string(data)
-
- return (
- utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
- )
-
-
-def _ssh_write_string(data):
- return struct.pack(">I", len(data)) + data
-
-
-def _ssh_write_mpint(value):
- data = utils.int_to_bytes(value)
- if six.indexbytes(data, 0) & 0x80:
- data = b"\x00" + data
- return _ssh_write_string(data)
-
-
class Encoding(Enum):
PEM = "PEM"
DER = "DER"
diff --git a/src/cryptography/hazmat/primitives/serialization/ssh.py b/src/cryptography/hazmat/primitives/serialization/ssh.py
new file mode 100644
index 00000000..f58ff074
--- /dev/null
+++ b/src/cryptography/hazmat/primitives/serialization/ssh.py
@@ -0,0 +1,143 @@
+# This file is dual licensed under the terms of the Apache License, Version
+# 2.0, and the BSD License. See the LICENSE file in the root of this repository
+# for complete details.
+
+from __future__ import absolute_import, division, print_function
+
+import base64
+import struct
+
+import six
+
+from cryptography import utils
+from cryptography.exceptions import UnsupportedAlgorithm
+from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
+
+
+def load_ssh_public_key(data, backend):
+ key_parts = data.split(b' ', 2)
+
+ if len(key_parts) < 2:
+ raise ValueError(
+ 'Key is not in the proper format or contains extra data.')
+
+ key_type = key_parts[0]
+
+ 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]
+
+ try:
+ decoded_data = base64.b64decode(key_body)
+ except TypeError:
+ raise ValueError('Key is not in the proper format.')
+
+ inner_key_type, rest = _ssh_read_next_string(decoded_data)
+
+ if inner_key_type != key_type:
+ raise ValueError(
+ 'Key header and key body contain different key type values.'
+ )
+
+ return loader(key_type, rest, backend)
+
+
+def _load_ssh_rsa_public_key(key_type, decoded_data, backend):
+ e, rest = _ssh_read_next_mpint(decoded_data)
+ n, rest = _ssh_read_next_mpint(rest)
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ return rsa.RSAPublicNumbers(e, n).public_key(backend)
+
+
+def _load_ssh_dss_public_key(key_type, decoded_data, backend):
+ p, rest = _ssh_read_next_mpint(decoded_data)
+ q, rest = _ssh_read_next_mpint(rest)
+ g, rest = _ssh_read_next_mpint(rest)
+ y, rest = _ssh_read_next_mpint(rest)
+
+ if rest:
+ raise ValueError('Key body contains extra bytes.')
+
+ 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):
+ curve_name, rest = _ssh_read_next_string(decoded_data)
+ data, rest = _ssh_read_next_string(rest)
+
+ if 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.')
+
+ curve = {
+ b"nistp256": ec.SECP256R1,
+ b"nistp384": ec.SECP384R1,
+ b"nistp521": ec.SECP521R1,
+ }[curve_name]()
+
+ if six.indexbytes(data, 0) != 4:
+ raise NotImplementedError(
+ "Compressed elliptic curve points are not supported"
+ )
+
+ numbers = ec.EllipticCurvePublicNumbers.from_encoded_point(curve, data)
+ return numbers.public_key(backend)
+
+
+def _ssh_read_next_string(data):
+ """
+ Retrieves the next RFC 4251 string value from the data.
+
+ While the RFC calls these strings, in Python they are bytes objects.
+ """
+ if len(data) < 4:
+ raise ValueError("Key is not in the proper format")
+
+ str_len, = struct.unpack('>I', data[:4])
+ if len(data) < str_len + 4:
+ raise ValueError("Key is not in the proper format")
+
+ return data[4:4 + str_len], data[4 + str_len:]
+
+
+def _ssh_read_next_mpint(data):
+ """
+ Reads the next mpint from the data.
+
+ Currently, all mpints are interpreted as unsigned.
+ """
+ mpint_data, rest = _ssh_read_next_string(data)
+
+ return (
+ utils.int_from_bytes(mpint_data, byteorder='big', signed=False), rest
+ )
+
+
+def _ssh_write_string(data):
+ return struct.pack(">I", len(data)) + data
+
+
+def _ssh_write_mpint(value):
+ data = utils.int_to_bytes(value)
+ if six.indexbytes(data, 0) & 0x80:
+ data = b"\x00" + data
+ return _ssh_write_string(data)