Skip to content

Commit

Permalink
Added a convertor for OpenSSH keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
KOLANICH committed Nov 21, 2022
1 parent bb43302 commit 6ed3ceb
Show file tree
Hide file tree
Showing 9 changed files with 163 additions and 0 deletions.
52 changes: 52 additions & 0 deletions securesystemslib/convert/ssh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
This module contains functions to import OpenSSH keys.
"""

import re
import typing

from cryptography.hazmat.primitives.serialization.ssh import (
load_ssh_private_key,
load_ssh_public_key,
)

from .hazmat import import_hazmat_key

openssh_text_format_marker_re = re.compile(
b"^-{2,}BEGIN OPENSSH PRIVATE KEY-{2,}$"
)


def import_ssh_key(
key: typing.Union[str, bytes], password: typing.Optional[bytes] = None
):
"""
<Purpose>
Imports either a public or a private key in OpenSSH format
<Arguments>
key:
A string in OpenSSH format, usually Base64-encoded.
<Exceptions>
securesystemslib.exceptions.FormatError, if the arguments are improperly
formatted.
securesystemslib.exceptions.UnsupportedAlgorithmError, if 'pem' specifies
an unsupported key type.
<Side Effects>
None.
<Returns>
A dictionary containing the keys, conforming to 'securesystemslib.formats.KEY_SCHEMA'.
"""

if isinstance(key, str):
key = key.encode("utf-8")

first_line = key.split(b"\n", 1)[0]
if openssh_text_format_marker_re.match(first_line):
return import_hazmat_key(load_ssh_private_key(key, password))

return import_hazmat_key(load_ssh_public_key(key))
9 changes: 9 additions & 0 deletions tests/data/ssh/ecdsa
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQRIz8F5gDezWgzdlRn5Upj7B1NoK43R
wP1d/oiCtNKSYDdql9ds3d+5zzEhnhWvdjGOn1sKwAFlbkz+aueExAkvAAAAqGkmJORpJi
TkAAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEjPwXmAN7NaDN2V
GflSmPsHU2grjdHA/V3+iIK00pJgN2qX12zd37nPMSGeFa92MY6fWwrAAWVuTP5q54TECS
8AAAAhAMfqco7t7Cdz3rXsPcUwOINw4CKTqyTpOCFTzjULEB6AAAAACWVjZHNhIGtleQEC
AwQFBg==
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions tests/data/ssh/ecdsa.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEjPwXmAN7NaDN2VGflSmPsHU2grjdHA/V3+iIK00pJgN2qX12zd37nPMSGeFa92MY6fWwrAAWVuTP5q54TECS8= ecdsa key
7 changes: 7 additions & 0 deletions tests/data/ssh/ed25519
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACAUMmZQY7F/6Pvhj+LQn6HLke1TI0L1qvVImeBCxKjFuAAAAJAh8wZwIfMG
cAAAAAtzc2gtZWQyNTUxOQAAACAUMmZQY7F/6Pvhj+LQn6HLke1TI0L1qvVImeBCxKjFuA
AAAED6uVRyKJZMvslMIFpm4nbqMcRlzza7VwJobiRcbLNwSBQyZlBjsX/o++GP4tCfocuR
7VMjQvWq9UiZ4ELEqMW4AAAAC2VkMjU1MTkga2V5AQI=
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions tests/data/ssh/ed25519.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBQyZlBjsX/o++GP4tCfocuR7VMjQvWq9UiZ4ELEqMW4 ed25519 key
7 changes: 7 additions & 0 deletions tests/data/ssh/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/env sh

types="ecdsa ed25519 rsa" # dsa

for t in $types; do
yes | ssh-keygen -t $t -C "$t key" -N "" -f ./$t;
done
38 changes: 38 additions & 0 deletions tests/data/ssh/rsa
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
fyozEzAWaCa90AAAAHcnNhIGtleQECAwQ=
-----END OPENSSH PRIVATE KEY-----
1 change: 1 addition & 0 deletions tests/data/ssh/rsa.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzzjkzJGZjENWuFFpjhhK7y+YpMMST18lCK28dlG3QbqbpVJggC+3DcpD4GfFVHTEUpJWplatF4nlpHrzQTc/8RhJzVg+FY3hZXRdxX5J5zJ5vW1aTQdduj0AGMQ0RRaFQo3o5fGMQdrthDUW1/9ybGF0sv4DlTH0rtR8yCvXpl0LmaCIn0MireG8SqsaxdYDb8KdbOHL8Ezo2UmqZg0+svwkphEFoFzqQYVNAhgG4+/5Yotl2PBxZrSUWEUApqvWSS5BeyT/cTnf/8XDGV64H2Qmw9nZhRTIan6GgTgzPOhaX3yUxXS4ZI5rnWRQJuOk/J6FVKsJFNVA+/BAsxjcbUpms+PUtrXe+mHMLcb9FvQAiR9oteNMWUM3X1H8hVRZ20ETTzZVXM44mbSJ+ZvBEcpsGo9RmaMnvsc+4QI9ak/wEojPGN1msNXh/R8RWnhG+sCkbM9Btf2wf1RUyxtpkpYksbcDVyQEl+Rr6x2M+sJH9KZCzS9OFL8hZHKsCAks= rsa key
47 changes: 47 additions & 0 deletions tests/test_openssh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python

"""
<Program Name>
test_openssh.py
<Author>
KOLANICH
<Started>
Nov 15, 2017
<Copyright>
See LICENSE for licensing information.
<Purpose>
Test OpenSSH-related functions.
"""

import unittest
from pathlib import Path

this_dir = Path(__file__).resolve().absolute().parent
keys_dir = this_dir / "data" / "ssh"

# pylint: disable=wrong-import-position
from securesystemslib.convert.ssh import import_ssh_key
from securesystemslib.keys import create_signature, verify_signature

TEST_DATA = b"test"


class TestOpenSSH(unittest.TestCase):
def test_openssh_import_and_sign_and_verify(self):
files = sorted(set(keys_dir.glob("*.pub")))
for pub_f in files:
sec_f = pub_f.parent / pub_f.stem
with self.subTest(pub_f=pub_f, sec_f=sec_f):
pub = import_ssh_key(pub_f.read_text(), None)
sec = import_ssh_key(sec_f.read_text(), None)
signature = create_signature(sec, TEST_DATA)
self.assertTrue(verify_signature(pub, signature, TEST_DATA))


if __name__ == "__main__":
unittest.main()

0 comments on commit 6ed3ceb

Please sign in to comment.