aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst6
-rw-r--r--docs/hazmat/primitives/asymmetric/serialization.rst5
-rw-r--r--src/cryptography/hazmat/primitives/serialization.py49
-rw-r--r--src/cryptography/utils.py7
-rw-r--r--tests/hazmat/primitives/test_serialization.py69
5 files changed, 77 insertions, 59 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 0394ebd9..cf6d2252 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -19,9 +19,9 @@ Changelog
* Added support for encoding and decoding :rfc:`6979` signatures in
:doc:`/hazmat/primitives/asymmetric/utils`.
* Added
- :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key`
- to support the loading of OpenSSH public keys (:rfc:`4253`). Currently, only RSA
- is supported.
+ :func:`~cryptography.hazmat.primitives.serialization.load_ssh_public_key` to
+ support the loading of OpenSSH public keys (:rfc:`4253`). Currently, only RSA
+ keys are supported.
0.6.1 - 2014-10-15
~~~~~~~~~~~~~~~~~~
diff --git a/docs/hazmat/primitives/asymmetric/serialization.rst b/docs/hazmat/primitives/asymmetric/serialization.rst
index 45c7a5bc..a9392c7b 100644
--- a/docs/hazmat/primitives/asymmetric/serialization.rst
+++ b/docs/hazmat/primitives/asymmetric/serialization.rst
@@ -199,7 +199,7 @@ KEY-----`` or ``-----BEGIN DSA PRIVATE KEY-----``.
OpenSSH Public Key
~~~~~~~~~~~~~~~~~~
-The format used by OpenSSH to store public keys as specified in :rfc:`4253`.
+The format used by OpenSSH to store public keys, as specified in :rfc:`4253`.
Currently, only RSA public keys are supported. Any other type of key will
result in an exception being thrown.
@@ -224,7 +224,8 @@ purposes)::
:param bytes data: The OpenSSH encoded key data.
- :param backend: A backend provider.
+ :param backend: An
+ :class:`~cryptography.hazmat.backends.interfaces.RSABackend` provider.
:returns: A new instance of a public key type.
diff --git a/src/cryptography/hazmat/primitives/serialization.py b/src/cryptography/hazmat/primitives/serialization.py
index 8a4c8bd8..858ec043 100644
--- a/src/cryptography/hazmat/primitives/serialization.py
+++ b/src/cryptography/hazmat/primitives/serialization.py
@@ -49,7 +49,7 @@ def load_pem_public_key(data, backend):
def load_ssh_public_key(data, backend):
key_parts = data.split(b' ')
- if len(key_parts) < 2 or len(key_parts) > 3:
+ if len(key_parts) != 2 and len(key_parts) != 3:
raise ValueError(
'Key is not in the proper format or contains extra data.')
@@ -62,21 +62,21 @@ def load_ssh_public_key(data, backend):
if not key_type.startswith(b'ssh-rsa'):
raise UnsupportedAlgorithm('Only RSA keys are currently supported.')
- return _load_ssh_rsa_public_key(key_type, key_body, backend)
+ return _load_ssh_rsa_public_key(key_body, backend)
-def _load_ssh_rsa_public_key(key_type, key_body, backend):
+def _load_ssh_rsa_public_key(key_body, backend):
data = base64.b64decode(key_body)
- key_body_type, rest = _read_next_string(data)
+ key_type, rest = _read_next_string(data)
e, rest = _read_next_mpint(rest)
n, rest = _read_next_mpint(rest)
- if key_type != key_body_type:
+ if key_type != b'ssh-rsa':
raise ValueError(
'Key header and key body contain different key type values.')
- if len(rest) != 0:
+ if rest:
raise ValueError('Key body contains extra bytes.')
return backend.load_rsa_public_numbers(RSAPublicNumbers(e, n))
@@ -84,26 +84,37 @@ def _load_ssh_rsa_public_key(key_type, key_body, backend):
def _read_next_string(data):
"""Retrieves the next RFC 4251 string value from the data."""
- str_len, = struct.unpack('>I', data[0:4])
+ str_len, = struct.unpack('>I', data[:4])
return data[4:4 + str_len], data[4 + str_len:]
def _read_next_mpint(data):
- """Reads the next mpint from the data. Currently, all mpints are
- interpreted as unsigned."""
+ """
+ Reads the next mpint from the data.
+
+ Currently, all mpints are interpreted as unsigned.
+ """
mpint_data, rest = _read_next_string(data)
- if sys.version_info >= (3, 2):
- # If we're using >= 3.2, use int.from_bytes for identical results.
- return int.from_bytes(mpint_data, byteorder='big', signed=False), rest
+ return _int_from_bytes(mpint_data, byteorder='big', signed=False), rest
+
+
+
+if hasattr(int, "from_bytes"):
+ _int_from_bytes = int.from_bytes
+else:
+ def _int_from_bytes(data, byteorder, signed=False):
+ assert byteorder == 'big'
+ assert not signed
- if len(mpint_data) % 4 != 0:
- mpint_data = (b'\x00' * (4 - (len(mpint_data) % 4))) + mpint_data
+ if len(data) % 4 != 0:
+ data = (b'\x00' * (4 - (len(data) % 4))) + data
- result = 0
+ result = 0
- while len(mpint_data) > 0:
- result = (result << 32) + struct.unpack('>I', mpint_data[0:4])[0]
- mpint_data = mpint_data[4:]
+ while len(data) > 0:
+ digit, = struct.unpack('>I', data[:4])
+ result = (result << 32) + digit
+ data = data[4:]
- return result, rest
+ return result
diff --git a/src/cryptography/utils.py b/src/cryptography/utils.py
index 63464dfa..78f73464 100644
--- a/src/cryptography/utils.py
+++ b/src/cryptography/utils.py
@@ -48,8 +48,9 @@ def verify_interface(iface, klass):
)
-def bit_length(x):
- if sys.version_info >= (2, 7):
+if sys.version_info >= (2, 7):
+ def bit_length(x):
return x.bit_length()
- else:
+else:
+ def bit_length(x):
return len(bin(x)) - (2 + (x <= 0))
diff --git a/tests/hazmat/primitives/test_serialization.py b/tests/hazmat/primitives/test_serialization.py
index 9180b9aa..2b9d05a7 100644
--- a/tests/hazmat/primitives/test_serialization.py
+++ b/tests/hazmat/primitives/test_serialization.py
@@ -704,53 +704,58 @@ class TestSSHSerialization(object):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_rsa_key_types_dont_match(self, backend):
- ssh_key = textwrap.dedent("""\
- ssh-bad AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk
- FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll
- PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK
- vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f
- sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy
- ///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX
- 2MzHvnbv testkey@localhost extra""").encode() # ssh-bad
+ ssh_key = (
+ b"ssh-bad AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
+ b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
+ b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
+ b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
+ b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
+ b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
+ b"2MzHvnbv testkey@localhost extra"
+ )
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_rsa_extra_string_after_comment(self, backend):
- ssh_key = textwrap.dedent("""\
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk
- FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll
- PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK
- vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f
- sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy
- ///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX
- 2MzHvnbv testkey@localhost extra""").encode() # Extra appended
+ ssh_key = (
+ b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
+ b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
+ b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
+ b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
+ b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
+ b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
+ # Extra section appended
+ b"2MzHvnbv testkey@localhost extra"
+ )
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_rsa_extra_data_after_modulo(self, backend):
- ssh_key = textwrap.dedent("""\
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk
- FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll
- PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK
- vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f
- sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy
- ///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX
- 2MzHvnbvAQ== testkey@localhost""").encode() # Extra 0x01 appended
+ ssh_key = (
+ b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
+ b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
+ b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
+ b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
+ b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
+ b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
+ b"2MzHvnbvAQ== testkey@localhost"
+ )
with pytest.raises(ValueError):
load_ssh_public_key(ssh_key, backend)
def test_load_ssh_public_key_rsa(self, backend):
- ssh_key = textwrap.dedent("""\
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk
- FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll
- PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK
- vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f
- sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy
- ///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX
- 2MzHvnbv testkey@localhost""").encode()
+ ssh_key = (
+ b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDDu/XRP1kyK6Cgt36gts9XAk"
+ b"FiiuJLW6RU0j3KKVZSs1I7Z3UmU9/9aVh/rZV43WQG8jaR6kkcP4stOR0DEtll"
+ b"PDA7ZRBnrfiHpSQYQ874AZaAoIjgkv7DBfsE6gcDQLub0PFjWyrYQUJhtOLQEK"
+ b"vY/G0vt2iRL3juawWmCFdTK3W3XvwAdgGk71i6lHt+deOPNEPN2H58E4odrZ2f"
+ b"sxn/adpDqfb2sM0kPwQs0aWvrrKGvUaustkivQE4XWiSFnB0oJB/lKK/CKVKuy"
+ b"///ImSCGHQRvhwariN2tvZ6CBNSLh3iQgeB0AkyJlng7MXB2qYq/Ci2FUOryCX"
+ b"2MzHvnbv testkey@localhost"
+ )
key = load_ssh_public_key(ssh_key, backend)