Add Support for ED25519 ssh-certificates
This commit is contained in:
@@ -21,14 +21,16 @@ ECDH_NIST256 = 'nist256p1'
|
|||||||
ECDH_CURVE25519 = 'curve25519'
|
ECDH_CURVE25519 = 'curve25519'
|
||||||
|
|
||||||
# SSH key types
|
# SSH key types
|
||||||
|
SSH_CERT_POSTFIX = b'-cert-v01@openssh.com'
|
||||||
SSH_NIST256_DER_OCTET = b'\x04'
|
SSH_NIST256_DER_OCTET = b'\x04'
|
||||||
SSH_NIST256_KEY_PREFIX = b'ecdsa-sha2-'
|
SSH_NIST256_KEY_PREFIX = b'ecdsa-sha2-'
|
||||||
SSH_NIST256_CURVE_NAME = b'nistp256'
|
SSH_NIST256_CURVE_NAME = b'nistp256'
|
||||||
SSH_NIST256_KEY_TYPE = SSH_NIST256_KEY_PREFIX + SSH_NIST256_CURVE_NAME
|
SSH_NIST256_KEY_TYPE = SSH_NIST256_KEY_PREFIX + SSH_NIST256_CURVE_NAME
|
||||||
SSH_NIST256_CERT_POSTFIX = b'-cert-v01@openssh.com'
|
SSH_NIST256_CERT_TYPE = SSH_NIST256_KEY_TYPE + SSH_CERT_POSTFIX
|
||||||
SSH_NIST256_CERT_TYPE = SSH_NIST256_KEY_TYPE + SSH_NIST256_CERT_POSTFIX
|
|
||||||
SSH_ED25519_KEY_TYPE = b'ssh-ed25519'
|
SSH_ED25519_KEY_TYPE = b'ssh-ed25519'
|
||||||
SUPPORTED_KEY_TYPES = {SSH_NIST256_KEY_TYPE, SSH_NIST256_CERT_TYPE, SSH_ED25519_KEY_TYPE}
|
SSH_ED25519_CERT_TYPE = SSH_ED25519_KEY_TYPE + SSH_CERT_POSTFIX
|
||||||
|
SUPPORTED_KEY_TYPES = {SSH_NIST256_KEY_TYPE, SSH_NIST256_CERT_TYPE,
|
||||||
|
SSH_ED25519_KEY_TYPE, SSH_ED25519_CERT_TYPE}
|
||||||
|
|
||||||
hashfunc = hashlib.sha256
|
hashfunc = hashlib.sha256
|
||||||
|
|
||||||
@@ -43,6 +45,20 @@ def fingerprint(blob):
|
|||||||
return ':'.join('{:02x}'.format(c) for c in bytearray(digest))
|
return ':'.join('{:02x}'.format(c) for c in bytearray(digest))
|
||||||
|
|
||||||
|
|
||||||
|
def __skip_certificate_fields(s):
|
||||||
|
_serial_number = util.recv(s, '>Q')
|
||||||
|
_type = util.recv(s, '>L')
|
||||||
|
_key_id = util.read_frame(s)
|
||||||
|
_valid_principals = util.read_frame(s)
|
||||||
|
_valid_after = util.recv(s, '>Q')
|
||||||
|
_valid_before = util.recv(s, '>Q')
|
||||||
|
_critical_options = util.read_frame(s)
|
||||||
|
_extensions = util.read_frame(s)
|
||||||
|
_reserved = util.read_frame(s)
|
||||||
|
_signature_key = util.read_frame(s)
|
||||||
|
_signature = util.read_frame(s)
|
||||||
|
|
||||||
|
|
||||||
def parse_pubkey(blob):
|
def parse_pubkey(blob):
|
||||||
"""
|
"""
|
||||||
Parse SSH public key from given blob.
|
Parse SSH public key from given blob.
|
||||||
@@ -69,18 +85,7 @@ def parse_pubkey(blob):
|
|||||||
point = util.read_frame(s)
|
point = util.read_frame(s)
|
||||||
|
|
||||||
if key_type == SSH_NIST256_CERT_TYPE:
|
if key_type == SSH_NIST256_CERT_TYPE:
|
||||||
_serial_number = util.recv(s, '>Q')
|
__skip_certificate_fields(s)
|
||||||
_type = util.recv(s, '>L')
|
|
||||||
_key_id = util.read_frame(s)
|
|
||||||
_valid_principals = util.read_frame(s)
|
|
||||||
_valid_after = util.recv(s, '>Q')
|
|
||||||
_valid_before = util.recv(s, '>Q')
|
|
||||||
_critical_options = util.read_frame(s)
|
|
||||||
_extensions = util.read_frame(s)
|
|
||||||
_reserved = util.read_frame(s)
|
|
||||||
_signature_key = util.read_frame(s)
|
|
||||||
_signature = util.read_frame(s)
|
|
||||||
|
|
||||||
assert s.read() == b''
|
assert s.read() == b''
|
||||||
_type, point = point[:1], point[1:]
|
_type, point = point[:1], point[1:]
|
||||||
assert _type == SSH_NIST256_DER_OCTET
|
assert _type == SSH_NIST256_DER_OCTET
|
||||||
@@ -102,8 +107,12 @@ def parse_pubkey(blob):
|
|||||||
result.update(point=coords, curve=CURVE_NIST256,
|
result.update(point=coords, curve=CURVE_NIST256,
|
||||||
verifier=ecdsa_verifier)
|
verifier=ecdsa_verifier)
|
||||||
|
|
||||||
if key_type == SSH_ED25519_KEY_TYPE:
|
if key_type in (SSH_ED25519_KEY_TYPE, SSH_ED25519_CERT_TYPE):
|
||||||
|
if key_type == SSH_ED25519_CERT_TYPE:
|
||||||
|
_nonce = util.read_frame(s)
|
||||||
pubkey = util.read_frame(s)
|
pubkey = util.read_frame(s)
|
||||||
|
if key_type == SSH_ED25519_CERT_TYPE:
|
||||||
|
__skip_certificate_fields(s)
|
||||||
assert s.read() == b''
|
assert s.read() == b''
|
||||||
|
|
||||||
def ed25519_verify(sig, msg):
|
def ed25519_verify(sig, msg):
|
||||||
|
|||||||
@@ -43,6 +43,57 @@ _public_key_cert = (
|
|||||||
'home\n'
|
'home\n'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_public_key_ed25519_cert = (
|
||||||
|
'ssh-ed25519-cert-v01@openssh.com '
|
||||||
|
'AAAAIHNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29'
|
||||||
|
'tAAAAIK5TMdCnuxxy4rr0CTHLekAsnL4DAhFyksK5romkuw'
|
||||||
|
'xgAAAAIFBdF2tjfSO8nLIi736is+f0erq28RTc7CkM11NZt'
|
||||||
|
'TKRAAAAAAAAAAAAAAABAAAACXVuaXQtdGVzdAAAAA0AAAAJ'
|
||||||
|
'dW5pdC10ZXN0AAAAAAAAAAD//////////wAAAAAAAACCAAA'
|
||||||
|
'AFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAXcGVybW'
|
||||||
|
'l0LWFnZW50LWZvcndhcmRpbmcAAAAAAAAAFnBlcm1pdC1wb'
|
||||||
|
'3J0LWZvcndhcmRpbmcAAAAAAAAACnBlcm1pdC1wdHkAAAAA'
|
||||||
|
'AAAADnBlcm1pdC11c2VyLXJjAAAAAAAAAAAAAABoAAAAE2V'
|
||||||
|
'jZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBC'
|
||||||
|
'HF5pUcZLVlTUBzos8ojyN34KrS7TnGAZINhRsCoNuRV4NFN'
|
||||||
|
'IlEYpEvSwlumQuDx6B1y4Va+3pYzBbZInm6vwgAAABjAAAA'
|
||||||
|
'E2VjZHNhLXNoYTItbmlzdHAyNTYAAABIAAAAICUMX1taTy6'
|
||||||
|
'y+1Aa1m7kXHI/Qv7ZZIeNp7ndmCRLFCSuAAAAIBaX43k0Ye'
|
||||||
|
'Bk8a5zp6FyFCBYVOtis/DUbGm07d7miPnE '
|
||||||
|
'hello\n'
|
||||||
|
)
|
||||||
|
|
||||||
|
_public_key_ed25519_cert_BLOB = (
|
||||||
|
b'\x00\x00\x00 ssh-ed25519-cert-v01@openssh.com'
|
||||||
|
b'\x00\x00\x00 \xaeS1\xd0\xa7\xbb\x1cr\xe2\xba'
|
||||||
|
b'\xf4\t1\xcbz@,\x9c\xbe\x03\x02\x11r\x92\xc2\xb9'
|
||||||
|
b'\xae\x89\xa4\xbb\x0c`\x00\x00\x00 P]\x17kc}#'
|
||||||
|
b'\xbc\x9c\xb2"\xef~\xa2\xb3\xe7\xf4z\xba\xb6\xf1'
|
||||||
|
b'\x14\xdc\xec)\x0c\xd7SY\xb52\x91\x00\x00\x00'
|
||||||
|
b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00'
|
||||||
|
b'\x00\tunit-test\x00\x00\x00\r\x00\x00\x00\tun'
|
||||||
|
b'it-test\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff'
|
||||||
|
b'\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00'
|
||||||
|
b'\x00\x00\x82\x00\x00\x00\x15permit-X11-forwar'
|
||||||
|
b'ding\x00\x00\x00\x00\x00\x00\x00\x17permit-ag'
|
||||||
|
b'ent-forwarding\x00\x00\x00\x00\x00\x00\x00\x16'
|
||||||
|
b'permit-port-forwarding\x00\x00\x00\x00\x00\x00'
|
||||||
|
b'\x00\npermit-pty\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
b'\x0epermit-user-rc\x00\x00\x00\x00\x00\x00\x00'
|
||||||
|
b'\x00\x00\x00\x00h\x00\x00\x00\x13ecdsa-sha2-n'
|
||||||
|
b'istp256\x00\x00\x00\x08nistp256\x00\x00\x00A'
|
||||||
|
b'\x04!\xc5\xe6\x95\x1cd\xb5eM@s\xa2\xcf(\x8f#w'
|
||||||
|
b'\xe0\xaa\xd2\xed9\xc6\x01\x92\r\x85\x1b\x02\xa0'
|
||||||
|
b'\xdb\x91W\x83E4\x89Db\x91/K\tn\x99\x0b\x83\xc7'
|
||||||
|
b'\xa0u\xcb\x85Z\xfbzX\xcc\x16\xd9"y\xba\xbf\x08'
|
||||||
|
b'\x00\x00\x00c\x00\x00\x00\x13ecdsa-sha2-nistp'
|
||||||
|
b'256\x00\x00\x00H\x00\x00\x00 %\x0c_[ZO.\xb2\xfb'
|
||||||
|
b'P\x1a\xd6n\xe4\\r?B\xfe\xd9d\x87\x8d\xa7\xb9'
|
||||||
|
b'\xdd\x98$K\x14$\xae\x00\x00\x00 \x16\x97\xe3y'
|
||||||
|
b'4a\xe0d\xf1\xaes\xa7\xa1r\x14 XT\xebb\xb3\xf0'
|
||||||
|
b'\xd4li\xb4\xed\xde\xe6\x88\xf9\xc4'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_parse_public_key():
|
def test_parse_public_key():
|
||||||
key = formats.import_public_key(_public_key)
|
key = formats.import_public_key(_public_key)
|
||||||
@@ -86,6 +137,16 @@ def test_parse_ed25519():
|
|||||||
assert p['type'] == b'ssh-ed25519'
|
assert p['type'] == b'ssh-ed25519'
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_ed25519_cert():
|
||||||
|
p = formats.import_public_key(_public_key_ed25519_cert)
|
||||||
|
assert p['name'] == b'hello'
|
||||||
|
assert p['curve'] == 'ed25519'
|
||||||
|
|
||||||
|
assert p['blob'] == _public_key_ed25519_cert_BLOB
|
||||||
|
assert p['fingerprint'] == '86:b6:17:3e:e1:5c:ba:e0:dc:86:80:b2:47:b4:ad:50' # nopep8
|
||||||
|
assert p['type'] == b'ssh-ed25519-cert-v01@openssh.com'
|
||||||
|
|
||||||
|
|
||||||
def test_export_ed25519():
|
def test_export_ed25519():
|
||||||
pub = (b'\x00P]\x17kc}#\xbc\x9c\xb2"\xef~\xa2\xb3\xe7\xf4'
|
pub = (b'\x00P]\x17kc}#\xbc\x9c\xb2"\xef~\xa2\xb3\xe7\xf4'
|
||||||
b'z\xba\xb6\xf1\x14\xdc\xec)\x0c\xd7SY\xb52\x91')
|
b'z\xba\xb6\xf1\x14\xdc\xec)\x0c\xd7SY\xb52\x91')
|
||||||
|
|||||||
Reference in New Issue
Block a user