Skip to content

Commit c16b90a

Browse files
committed
Support checking the sk_flags
1 parent b4b7cb6 commit c16b90a

File tree

5 files changed

+73
-48
lines changed

5 files changed

+73
-48
lines changed

lib/ssh_data/public_key.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@ module PublicKey
2020
ALGO_ED25519, ALGO_SKECDSA256, ALGO_SKED25519
2121
]
2222

23+
DEFAULT_SK_VERIFY_OPTS = {
24+
user_presence_required: true,
25+
user_verification_required: false
26+
}
27+
28+
SK_FLAG_USER_PRESENCE = 0b001
29+
SK_FLAG_USER_VERIFICATION = 0b100
30+
2331
# Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual
2432
# page).
2533
#
@@ -78,6 +86,7 @@ def self.from_data(data)
7886
end
7987

8088
require "ssh_data/public_key/base"
89+
require "ssh_data/public_key/security_key"
8190
require "ssh_data/public_key/rsa"
8291
require "ssh_data/public_key/dsa"
8392
require "ssh_data/public_key/ecdsa"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module SSHData
2+
module PublicKey
3+
module SecurityKey
4+
def build_signing_blob(application, signed_data, signature)
5+
read = 0
6+
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature)
7+
read += signature_read
8+
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
9+
read += sk_flags_read
10+
counter, counter_read = Encoding.decode_uint32(signature, read)
11+
read += counter_read
12+
13+
if read != signature.bytesize
14+
raise DecodeError, "unexpected trailing data"
15+
end
16+
17+
application_hash = OpenSSL::Digest::SHA256.digest(application)
18+
message_hash = OpenSSL::Digest::SHA256.digest(signed_data)
19+
20+
blob =
21+
application_hash +
22+
Encoding.encode_uint8(sk_flags) +
23+
Encoding.encode_uint32(counter) +
24+
message_hash
25+
26+
[sig_algo, raw_sig, sk_flags, blob]
27+
end
28+
end
29+
end
30+
end

lib/ssh_data/public_key/skecdsa.rb

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SSHData
22
module PublicKey
33
class SKECDSA < ECDSA
4+
include SecurityKey
45
attr_reader :application
56

67
OPENSSL_CURVE_NAME_FOR_CURVE = {
@@ -34,34 +35,25 @@ def rfc4253
3435
)
3536
end
3637

37-
def verify(signed_data, signature)
38-
read = 0
39-
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature)
40-
read += signature_read
41-
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
42-
read += sk_flags_read
43-
counter, counter_read = Encoding.decode_uint32(signature, read)
44-
read += counter_read
45-
46-
if read != signature.bytesize
47-
raise DecodeError, "unexpected trailing data"
48-
end
38+
def verify(signed_data, signature, **opts)
39+
opts = DEFAULT_SK_VERIFY_OPTS.merge(opts)
4940

41+
read = 0
42+
sig_algo, raw_sig, sk_flags, blob = build_signing_blob(application, signed_data, signature)
5043
self.class.check_algorithm!(sig_algo, curve)
5144

52-
application_hash = OpenSSL::Digest::SHA256.digest(application)
53-
message_hash = OpenSSL::Digest::SHA256.digest(signed_data)
54-
55-
blob =
56-
application_hash +
57-
Encoding.encode_uint8(sk_flags) +
58-
Encoding.encode_uint32(counter) +
59-
message_hash
60-
6145
openssl_sig = self.class.openssl_signature(raw_sig)
6246
digest = DIGEST_FOR_CURVE[curve]
6347

64-
openssl.verify(digest.new, openssl_sig, blob)
48+
result = openssl.verify(digest.new, openssl_sig, blob)
49+
50+
if opts[:user_presence_required] && (sk_flags & SK_FLAG_USER_PRESENCE != SK_FLAG_USER_PRESENCE)
51+
false
52+
elsif opts[:user_verification_required] && (sk_flags & SK_FLAG_USER_VERIFICATION != SK_FLAG_USER_VERIFICATION)
53+
false
54+
else
55+
result
56+
end
6557
end
6658

6759
def ==(other)

lib/ssh_data/public_key/sked25519.rb

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
module SSHData
22
module PublicKey
33
class SKED25519 < ED25519
4+
include SecurityKey
45
attr_reader :application
56

67
def initialize(algo:, pk:, application:)
@@ -23,38 +24,27 @@ def rfc4253
2324
)
2425
end
2526

26-
def verify(signed_data, signature)
27+
def verify(signed_data, signature, **opts)
2728
self.class.ed25519_gem_required!
28-
29-
read = 0
30-
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature)
31-
read += signature_read
32-
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
33-
read += sk_flags_read
34-
counter, counter_read = Encoding.decode_uint32(signature, read)
35-
read += counter_read
36-
37-
if read != signature.bytesize
38-
raise DecodeError, "unexpected trailing data"
39-
end
29+
opts = DEFAULT_SK_VERIFY_OPTS.merge(opts)
30+
sig_algo, raw_sig, sk_flags, blob = build_signing_blob(application, signed_data, signature)
4031

4132
if sig_algo != self.class.algorithm_identifier
4233
raise DecodeError, "bad signature algorithm: #{sig_algo.inspect}"
4334
end
4435

45-
application_hash = OpenSSL::Digest::SHA256.digest(application)
46-
message_hash = OpenSSL::Digest::SHA256.digest(signed_data)
36+
result = begin
37+
ed25519_key.verify(raw_sig, blob)
38+
rescue Ed25519::VerifyError
39+
false
40+
end
4741

48-
blob =
49-
application_hash +
50-
Encoding.encode_uint8(sk_flags) +
51-
Encoding.encode_uint32(counter) +
52-
message_hash
53-
54-
begin
55-
ed25519_key.verify(raw_sig, blob)
56-
rescue Ed25519::VerifyError
42+
if opts[:user_presence_required] && (sk_flags & SK_FLAG_USER_PRESENCE != SK_FLAG_USER_PRESENCE)
43+
false
44+
elsif opts[:user_verification_required] && (sk_flags & SK_FLAG_USER_VERIFICATION != SK_FLAG_USER_VERIFICATION)
5745
false
46+
else
47+
result
5848
end
5949
end
6050

lib/ssh_data/signature.rb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def initialize(sigversion:, publickey:, namespace:, reserved:, hash_algorithm:,
7070
@signature = signature
7171
end
7272

73-
def verify(signed_data)
73+
def verify(signed_data, **opts)
7474
key = public_key
7575
digest_algorithm = SUPPORTED_HASH_ALGORITHMS[@hash_algorithm]
7676

@@ -93,7 +93,11 @@ def verify(signed_data)
9393
Encoding.encode_string(@hash_algorithm) +
9494
Encoding.encode_string(message_digest)
9595

96-
key.verify(blob, @signature)
96+
if key.class.include?(::SSHData::PublicKey::SecurityKey)
97+
key.verify(blob, @signature, **opts)
98+
else
99+
key.verify(blob, @signature)
100+
end
97101
end
98102

99103
def public_key

0 commit comments

Comments
 (0)