Skip to content

Commit da198e4

Browse files
authored
Merge pull request #72 from MathisRosenhauer/sk-keys
sk- key types
2 parents 14bd483 + b0dbd1d commit da198e4

3 files changed

Lines changed: 48 additions & 1 deletion

File tree

sshpubkeys/keys.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from cryptography.hazmat.backends import default_backend
2020
from cryptography.hazmat.primitives.asymmetric.dsa import DSAParameterNumbers, DSAPublicNumbers
2121
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicNumbers
22+
from urllib.parse import urlparse
2223

2324
import base64
2425
import binascii
@@ -204,7 +205,7 @@ def _parse_long(cls, data):
204205
def _split_key(self, data):
205206
options_raw = None
206207
# Terribly inefficient way to remove options, but hey, it works.
207-
if not data.startswith("ssh-") and not data.startswith("ecdsa-"):
208+
if not data.startswith("ssh-") and not data.startswith("ecdsa-") and not data.startswith("sk-"):
208209
quote_open = False
209210
for i, character in enumerate(data):
210211
if character == '"': # only double quotes are allowed, no need to care about single quotes
@@ -388,6 +389,32 @@ def _process_ed25516(self, data):
388389
raise InvalidKeyLengthError("ed25519 keys must be 256 bits (was %s bits)" % self.bits)
389390
return current_position
390391

392+
def _validate_application_string(self, application):
393+
"""Validates Application string.
394+
395+
Has to be an URL starting with "ssh:". See ssh-keygen(1)."""
396+
397+
try:
398+
parsed_url = urlparse(application)
399+
except ValueError as error:
400+
raise InvalidKeyError("Application string: %s" % error)
401+
if parsed_url.scheme != b"ssh":
402+
raise InvalidKeyError('Application string must begin with "ssh:"')
403+
404+
def _process_sk_ecdsa_sha(self, data):
405+
"""Parses sk_ecdsa-sha public keys."""
406+
current_position = self._process_ecdsa_sha(data)
407+
current_position, application = self._unpack_by_int(data, current_position)
408+
self._validate_application_string(application)
409+
return current_position
410+
411+
def _process_sk_ed25519(self, data):
412+
"""Parses sk_ed25519 public keys."""
413+
current_position = self._process_ed25516(data)
414+
current_position, application = self._unpack_by_int(data, current_position)
415+
self._validate_application_string(application)
416+
return current_position
417+
391418
def _process_key(self, data):
392419
if self.key_type == b"ssh-rsa":
393420
return self._process_ssh_rsa(data)
@@ -397,6 +424,10 @@ def _process_key(self, data):
397424
return self._process_ecdsa_sha(data)
398425
if self.key_type == b"ssh-ed25519":
399426
return self._process_ed25516(data)
427+
if self.key_type.strip().startswith(b"sk-ecdsa-sha"):
428+
return self._process_sk_ecdsa_sha(data)
429+
if self.key_type.strip().startswith(b"sk-ssh-ed25519"):
430+
return self._process_sk_ed25519(data)
400431
raise NotImplementedError("Invalid key type: %s" % self.key_type.decode())
401432

402433
def parse(self, keydata=None):

tests/invalid_keys.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,12 @@
8282
'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQbdtLTII+vP98NSDlK2LXxVARELRYO0NODFYQ0imYxsmBMB7BrfljFppLJyjU6cziOT6YFj6rVd8MmCogdCR32u63EV11uT6RCFfJMQJtIi+B1JJipTxLzURsiUOOgAHJc= ojarva@ojar-laptop.local',
8383
TooShortKeyError, "rsa_771", ["strict"]
8484
],
85+
[
86+
'sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJ+CG2daFaeUC2GMvxGe5bTXRxforrL3MNOcsxbMbQeHAAAABGludjo=',
87+
InvalidKeyError, 'invalid_appid_sk-ssh-ed25519', ["loose", "strict"]
88+
],
89+
[
90+
'sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIHIoT5FA++PiJ4g4cORu3DBK4HWBO8mMjbp1Jtp4twl4AAAAB3NzaDovL1s=',
91+
InvalidKeyError, 'invalid_url_sk-ssh-ed25519', ["loose", "strict"]
92+
],
8593
]

tests/valid_keys.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,12 @@
218218
'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL5x8+1ucT6+AKQIW8u5W/FOuBvWx2fCQlSLkUakry89', 256,
219219
'MD5:0c:4e:13:0f:f3:ab:20:58:85:2e:79:9b:0f:2b:43:c8', 'SHA256:2ao9ds3IIkmXiLPRMs/47HIkHIV/qxzEHKW8p9lhRYA', "ed25516_2",
220220
["strict", "loose"]
221+
], [
222+
'sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGdtNJ7nNTVW3kXvrWpvTENCfetzI2yUb8m5WLB2kcOVqF+3orTmloZsQEt1K386hlaqNzm7MVB+xcAiNoqhiI4AAAAEc3NoOg==',
223+
256, 'MD5:ea:34:1c:a3:8b:8e:fe:07:0c:b0:36:fa:db:ce:b4:58', 'SHA256:HGA+EGN7vROCadhXckS5/hwCluETf1cPA92A9+RTgxw',
224+
'sk-ecdsa-sha2-nistp256_1', ["strict", "loose"]
225+
], [
226+
'sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAID92A9iaZ6WS0dcc4qsxuUfMgwFuFeh48faLjYlaYXswAAAABHNzaDo=',
227+
256, 'MD5:0b:87:18:2a:09:e7:a9:77:73:cd:3d:83:83:77:ea:83', 'SHA256:Uz5X82+UKm4CiOdqnfAtV/5JfnysqPHt1Is0iGnD70g',
228+
'sk-ssh-ed25519_1', ["strict", "loose"]
221229
]]

0 commit comments

Comments
 (0)