Skip to content

Commit

Permalink
fix loading new openssh private key format when no padding
Browse files Browse the repository at this point in the history
  • Loading branch information
ploxiln committed Dec 5, 2019
1 parent 5a4a0a2 commit 8b59b04
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 35 deletions.
24 changes: 2 additions & 22 deletions paramiko/ed25519key.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,32 +21,12 @@

import nacl.signing

import six

from paramiko.message import Message
from paramiko.pkey import PKey
from paramiko.pkey import PKey, OPENSSH_AUTH_MAGIC, _unpad_openssh
from paramiko.py3compat import b
from paramiko.ssh_exception import SSHException, PasswordRequiredException


OPENSSH_AUTH_MAGIC = b"openssh-key-v1\x00"


def unpad(data):
# At the moment, this is only used for unpadding private keys on disk. This
# really ought to be made constant time (possibly by upstreaming this logic
# into pyca/cryptography).
padding_length = six.indexbytes(data, -1)
if 0x20 <= padding_length < 0x7f:
return data # no padding, last byte part comment (printable ascii)
if padding_length > 15:
raise SSHException("Invalid key")
for i in range(padding_length):
if six.indexbytes(data, i - padding_length) != i + 1:
raise SSHException("Invalid key")
return data[:-padding_length]


class Ed25519Key(PKey):
"""
Representation of an `Ed25519 <https://ed25519.cr.yp.to/>`_ key.
Expand Down Expand Up @@ -155,7 +135,7 @@ def _parse_signing_key_data(self, data, password):
decryptor.update(private_ciphertext) + decryptor.finalize()
)

message = Message(unpad(private_data))
message = Message(_unpad_openssh(private_data))
if message.get_int() != message.get_int():
raise SSHException("Invalid key")

Expand Down
36 changes: 23 additions & 13 deletions paramiko/pkey.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import re
import struct

import six
import bcrypt

from cryptography.hazmat.backends import default_backend
Expand All @@ -35,18 +36,29 @@

from paramiko import util
from paramiko.common import o600
from paramiko.py3compat import (
u,
encodebytes,
decodebytes,
b,
string_types,
byte_ord,
)
from paramiko.py3compat import u, b, encodebytes, decodebytes, string_types
from paramiko.ssh_exception import SSHException, PasswordRequiredException
from paramiko.message import Message


OPENSSH_AUTH_MAGIC = b"openssh-key-v1\x00"


def _unpad_openssh(data):
# At the moment, this is only used for unpadding private keys on disk. This
# really ought to be made constant time (possibly by upstreaming this logic
# into pyca/cryptography).
padding_length = six.indexbytes(data, -1)
if 0x20 <= padding_length < 0x7f:
return data # no padding, last byte part comment (printable ascii)
if padding_length > 15:
raise SSHException("Invalid key")
for i in range(padding_length):
if six.indexbytes(data, i - padding_length) != i + 1:
raise SSHException("Invalid key")
return data[:-padding_length]


class PKey(object):
"""
Base class for public keys.
Expand Down Expand Up @@ -395,8 +407,8 @@ def _read_private_key_openssh(self, lines, password):
raise SSHException("base64 decoding error: {}".format(e))

# read data struct
auth_magic = data[:14]
if auth_magic != b("openssh-key-v1"):
auth_magic = data[:15]
if auth_magic != OPENSSH_AUTH_MAGIC:
raise SSHException("unexpected OpenSSH key header encountered")

cstruct = self._uint32_cstruct_unpack(data[15:], "sssur")
Expand Down Expand Up @@ -466,9 +478,7 @@ def _read_private_key_openssh(self, lines, password):
"OpenSSH private key file checkints do not match"
)

# Remove padding
padlen = byte_ord(keydata[len(keydata) - 1])
return keydata[: len(keydata) - padlen]
return _unpad_openssh(keydata)

def _uint32_cstruct_unpack(self, data, strformat):
"""
Expand Down

0 comments on commit 8b59b04

Please sign in to comment.