mirror of
https://github.com/saymrwulf/cryptography.git
synced 2026-05-14 20:37:55 +00:00
Adding support for OpenSSH ecdsa-sk & ed25519-sk public keys (#10608)
* Adding support for OpenSSH ecdsa-sk & ed25519-sk public keys fixes #10604 * Revert changing the keygen * Add application string to sk key generation * Typing - fix load_application return value annotation * fix sk keys skipping loading in the tests * fix ruff E509 * Fix ruff … * comment wording Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com> * requested changes * no subclassing * fix SyntaxError: annotated name '_KEY_FORMATS' can't be global in python 3.7 c.f. https://github.com/python/cpython/issues/79120 * typo * Update src/cryptography/hazmat/primitives/serialization/ssh.py Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com> * Update src/cryptography/hazmat/primitives/serialization/ssh.py Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com> --------- Co-authored-by: Alex Gaynor <alex.gaynor@gmail.com>
This commit is contained in:
parent
089039d0f6
commit
51a6dd28cc
11 changed files with 138 additions and 5 deletions
|
|
@ -64,6 +64,10 @@ _ECDSA_NISTP384 = b"ecdsa-sha2-nistp384"
|
|||
_ECDSA_NISTP521 = b"ecdsa-sha2-nistp521"
|
||||
_CERT_SUFFIX = b"-cert-v01@openssh.com"
|
||||
|
||||
# U2F application string suffixed pubkey
|
||||
_SK_SSH_ED25519 = b"sk-ssh-ed25519@openssh.com"
|
||||
_SK_SSH_ECDSA_NISTP256 = b"sk-ecdsa-sha2-nistp256@openssh.com"
|
||||
|
||||
# These are not key types, only algorithms, so they cannot appear
|
||||
# as a public key type
|
||||
_SSH_RSA_SHA256 = b"rsa-sha2-256"
|
||||
|
|
@ -572,6 +576,56 @@ class _SSHFormatEd25519:
|
|||
f_priv.put_sshstr(f_keypair)
|
||||
|
||||
|
||||
def load_application(data) -> tuple[memoryview, memoryview]:
|
||||
"""
|
||||
U2F application strings
|
||||
"""
|
||||
application, data = _get_sshstr(data)
|
||||
if not application.tobytes().startswith(b"ssh:"):
|
||||
raise ValueError(
|
||||
"U2F application string does not start with b'ssh:' "
|
||||
f"({application})"
|
||||
)
|
||||
return application, data
|
||||
|
||||
|
||||
class _SSHFormatSKEd25519:
|
||||
"""
|
||||
The format of a sk-ssh-ed25519@openssh.com public key is:
|
||||
|
||||
string "sk-ssh-ed25519@openssh.com"
|
||||
string public key
|
||||
string application (user-specified, but typically "ssh:")
|
||||
"""
|
||||
|
||||
def load_public(
|
||||
self, data: memoryview
|
||||
) -> tuple[ed25519.Ed25519PublicKey, memoryview]:
|
||||
"""Make Ed25519 public key from data."""
|
||||
public_key, data = _lookup_kformat(_SSH_ED25519).load_public(data)
|
||||
application, data = load_application(data)
|
||||
return public_key, data
|
||||
|
||||
|
||||
class _SSHFormatSKECDSA:
|
||||
"""
|
||||
The format of a sk-ecdsa-sha2-nistp256@openssh.com public key is:
|
||||
|
||||
string "sk-ecdsa-sha2-nistp256@openssh.com"
|
||||
string curve name
|
||||
ec_point Q
|
||||
string application (user-specified, but typically "ssh:")
|
||||
"""
|
||||
|
||||
def load_public(
|
||||
self, data: memoryview
|
||||
) -> tuple[ec.EllipticCurvePublicKey, memoryview]:
|
||||
"""Make Ed25519 public key from data."""
|
||||
public_key, data = _lookup_kformat(_ECDSA_NISTP256).load_public(data)
|
||||
application, data = load_application(data)
|
||||
return public_key, data
|
||||
|
||||
|
||||
_KEY_FORMATS = {
|
||||
_SSH_RSA: _SSHFormatRSA(),
|
||||
_SSH_DSA: _SSHFormatDSA(),
|
||||
|
|
@ -579,6 +633,8 @@ _KEY_FORMATS = {
|
|||
_ECDSA_NISTP256: _SSHFormatECDSA(b"nistp256", ec.SECP256R1()),
|
||||
_ECDSA_NISTP384: _SSHFormatECDSA(b"nistp384", ec.SECP384R1()),
|
||||
_ECDSA_NISTP521: _SSHFormatECDSA(b"nistp521", ec.SECP521R1()),
|
||||
_SK_SSH_ED25519: _SSHFormatSKEd25519(),
|
||||
_SK_SSH_ECDSA_NISTP256: _SSHFormatSKECDSA(),
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ class TestOpenSSHSerialization:
|
|||
("ecdsa-nopsw.key.pub", "ecdsa-nopsw.key-cert.pub"),
|
||||
("ed25519-psw.key.pub", None),
|
||||
("ed25519-nopsw.key.pub", "ed25519-nopsw.key-cert.pub"),
|
||||
("sk-ecdsa-psw.key.pub", None),
|
||||
("sk-ecdsa-nopsw.key.pub", None),
|
||||
("sk-ed25519-psw.key.pub", None),
|
||||
("sk-ed25519-nopsw.key.pub", None),
|
||||
],
|
||||
)
|
||||
def test_load_ssh_public_key(self, key_file, cert_file, backend):
|
||||
|
|
@ -80,10 +84,14 @@ class TestOpenSSHSerialization:
|
|||
)
|
||||
else:
|
||||
public_key = load_ssh_public_key(pub_data, backend)
|
||||
assert (
|
||||
public_key.public_bytes(Encoding.OpenSSH, PublicFormat.OpenSSH)
|
||||
== nocomment_data
|
||||
)
|
||||
if not key_file.startswith("sk-"):
|
||||
# SK keys do not round-trip
|
||||
assert (
|
||||
public_key.public_bytes(
|
||||
Encoding.OpenSSH, PublicFormat.OpenSSH
|
||||
)
|
||||
== nocomment_data
|
||||
)
|
||||
|
||||
self.run_partial_pubkey(pub_data, backend)
|
||||
|
||||
|
|
@ -1800,3 +1808,20 @@ class TestSSHCertificateBuilder:
|
|||
b"t8yRa8IRbxvOyA9TZYDGG1dRE3DiR0fuudU20v6vqfTd1gx0S5QyEdECXLl9ZI3"
|
||||
b"AwZgc="
|
||||
)
|
||||
|
||||
|
||||
class TestSSHSK:
|
||||
@staticmethod
|
||||
def ssh_str(application):
|
||||
data = (
|
||||
len(application).to_bytes(length=4, byteorder="big")
|
||||
+ application.encode()
|
||||
)
|
||||
return memoryview(data)
|
||||
|
||||
def test_load_application(self):
|
||||
ssh.load_application(self.ssh_str("ssh:test"))
|
||||
|
||||
def test_load_application_valueerror(self):
|
||||
with pytest.raises(ValueError):
|
||||
ssh.load_application(self.ssh_str("hss:test"))
|
||||
|
|
|
|||
|
|
@ -19,10 +19,13 @@ getecbits() {
|
|||
genkey() {
|
||||
fn="$1"
|
||||
args="-f $fn -C $fn"
|
||||
sk="-O application=ssh:the-application-string"
|
||||
case "$fn" in
|
||||
sk-ecdsa-*) args="$args -t ecdsa-sk -b $(getecbits) $sk" ;;
|
||||
ecdsa-*) args="$args -t ecdsa -b $(getecbits)" ;;
|
||||
rsa-*) args="$args -t rsa" ;;
|
||||
dsa-*) args="$args -t dsa" ;;
|
||||
sk-ed25519-*) args="$args -t ed25519-sk $sk" ;;
|
||||
ed25519-*) args="$args -t ed25519" ;;
|
||||
esac
|
||||
password=''
|
||||
|
|
@ -33,12 +36,13 @@ genkey() {
|
|||
}
|
||||
|
||||
# generate private key files
|
||||
for ktype in rsa dsa ecdsa ed25519; do
|
||||
for ktype in rsa dsa ecdsa sk-ecdsa ed25519 sk-ed25519; do
|
||||
for psw in nopsw psw; do
|
||||
genkey "${ktype}-${psw}.key"
|
||||
done
|
||||
done
|
||||
|
||||
|
||||
# generate public key files
|
||||
for fn in *.key; do
|
||||
ssh-keygen -q -y -f "$fn" > /dev/null
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlQAAACJzay1lY2
|
||||
RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQQ7XunI8QRf
|
||||
myT0PKWJXtaE0lA6+Hy5HTfIDfHexsZV68AGAj0nYyf2+mAK/vPp6IyVBALJqdzdJYiyeX
|
||||
p/3neLAAAAGnNzaDp0aGUtYXBwbGljYXRpb24tc3RyaW5nAAABAOGdI7jhnSO4AAAAInNr
|
||||
LWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBDte6c
|
||||
jxBF+bJPQ8pYle1oTSUDr4fLkdN8gN8d7GxlXrwAYCPSdjJ/b6YAr+8+nojJUEAsmp3N0l
|
||||
iLJ5en/ed4sAAAAac3NoOnRoZS1hcHBsaWNhdGlvbi1zdHJpbmcBAAAAQDkL+WvhalaEJi
|
||||
Lf/MaFsFeYzwvC06GZVqUXgCnzyutZzMB9a1deF9uFke1ib56tgZR9iVsskIJeWuwiAIg0
|
||||
es4AAAAAAAAAEnNrLWVjZHNhLW5vcHN3LmtleQECAwQ=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBDte6cjxBF+bJPQ8pYle1oTSUDr4fLkdN8gN8d7GxlXrwAYCPSdjJ/b6YAr+8+nojJUEAsmp3N0liLJ5en/ed4sAAAAac3NoOnRoZS1hcHBsaWNhdGlvbi1zdHJpbmc= sk-ecdsa-nopsw.key
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDIj2qUG3
|
||||
LdljUMp0/4zuFuAAAAEAAAAAEAAACVAAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3Bl
|
||||
bnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBACdJuKxgDLk+a1NeeCtRqCropd0hXume/cTdO
|
||||
vV/B4lmupr9viNQsUT09wbKRflnOc9jxPAiQOzZbXTkmnV8kkAAAAac3NoOnRoZS1hcHBs
|
||||
aWNhdGlvbi1zdHJpbmcAAAEAO6Vsfb59XIe524NKbXMjA0xleAi3lcZ5EF0dF48yRO2LfA
|
||||
12B948LzsKOrgo+Cdq7BMLkCCA1z2811yvKtvy/7cR3D/p31cW7VEun4OAn+QoPCHmv25r
|
||||
WVfUAv5PC5Ofdm7dtExTcMmyNUMcziovirTyhnlpc/wHD+wgp2oQGpcm+rjQlqX96cLJ7H
|
||||
PM3wls38biP3wh2QWkoKWPyq7tMR4PiJOw9h6YNeZY3M1JnC9b2b0iHD6Ra/5LBBqV/Uyu
|
||||
irkHWLB7ASchamexxRqu4fLFK4tjijhLV8hc/XLsQGeDNBHf4QSvZJP0usSSP37F1Ai+XM
|
||||
stjM1iCsk1UEV9aA==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBACdJuKxgDLk+a1NeeCtRqCropd0hXume/cTdOvV/B4lmupr9viNQsUT09wbKRflnOc9jxPAiQOzZbXTkmnV8kkAAAAac3NoOnRoZS1hcHBsaWNhdGlvbi1zdHJpbmc= sk-ecdsa-psw.key
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAYAAAABpzay1zc2
|
||||
gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACB6auRr7BwVOqTawgDOxUpaUFcN8SZ7SWzoR2Vs
|
||||
ubbk3wAAABpzc2g6dGhlLWFwcGxpY2F0aW9uLXN0cmluZwAAARCWIPLyliDy8gAAABpzay
|
||||
1zc2gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACB6auRr7BwVOqTawgDOxUpaUFcN8SZ7SWzo
|
||||
R2Vsubbk3wAAABpzc2g6dGhlLWFwcGxpY2F0aW9uLXN0cmluZwEAAACAQPv/aY2F3YN1kD
|
||||
1FHPa1HpEHOGAbsYj/2b6h8Rn+N4pU6hdTD5v19Efdz5jlt8Y84c61+8HKDPCI/g5Cbcvd
|
||||
3uuGHuFUdgiarOZqKyuwBj3Kll9Whb/yV4wGo/NVXtCHa2SnWr2wjYtRTGPNNCgGPsLU05
|
||||
/KTNCStsNhEcsNDjEAAAAAAAAAFHNrLWVkMjU1MTktbm9wc3cua2V5AQIDBAUGBw==
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHpq5GvsHBU6pNrCAM7FSlpQVw3xJntJbOhHZWy5tuTfAAAAGnNzaDp0aGUtYXBwbGljYXRpb24tc3RyaW5n sk-ed25519-nopsw.key
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABBZQIE5S+
|
||||
fq0J5esB3Jo4smAAAAEAAAAAEAAABgAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29t
|
||||
AAAAIHf0iiNQTiR7NNAbeAwY+READVx9G0mP6idSAZ7bPTrMAAAAGnNzaDp0aGUtYXBwbG
|
||||
ljYXRpb24tc3RyaW5nAAABEEeyENyjnVry24AKkT0cC6nRakzHeBY7nSmDiy3MX7sQNRze
|
||||
illy4uWLZyv022QlMR4GqnXwnQ9bPqcPD0S/SAhuYnFRWI6PPUXkNqiqiS/ZsMkaSKDvBS
|
||||
UKv5EXjBBk3Sh9IjNXXK8tt0+WIIR973hVEtolcgxvFZpc1IJuRl9gkpKlQFNzwcANTuwB
|
||||
kr6t0qad/fp0bZldBL/zRtqfgMHTSFzNoITTaxA8ZQZ1Zm585u0NIX4ZDrTaoZVaO8t7Z5
|
||||
3r1784oCk6h/lomf9Qsg2eBf6CHMGlTHVFPop5VtGDKFVlgIxQCdwt0V1e6dWK6j5zOzBh
|
||||
mNA7qT0q3quRLBqUADN698q5fLRFR1PzQ5bx
|
||||
-----END OPENSSH PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1 @@
|
|||
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHf0iiNQTiR7NNAbeAwY+READVx9G0mP6idSAZ7bPTrMAAAAGnNzaDp0aGUtYXBwbGljYXRpb24tc3RyaW5n sk-ed25519-psw.key
|
||||
Loading…
Reference in a new issue