This commit is contained in:
Kevin Jones 2021-12-19 11:43:30 -05:00
Родитель b4b7cb649a
Коммит c16b90ac63
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: A521BED5353FDD4E
5 изменённых файлов: 73 добавлений и 48 удалений

Просмотреть файл

@ -20,6 +20,14 @@ module SSHData
ALGO_ED25519, ALGO_SKECDSA256, ALGO_SKED25519 ALGO_ED25519, ALGO_SKECDSA256, ALGO_SKED25519
] ]
DEFAULT_SK_VERIFY_OPTS = {
user_presence_required: true,
user_verification_required: false
}
SK_FLAG_USER_PRESENCE = 0b001
SK_FLAG_USER_VERIFICATION = 0b100
# Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual # Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual
# page). # page).
# #
@ -78,6 +86,7 @@ module SSHData
end end
require "ssh_data/public_key/base" require "ssh_data/public_key/base"
require "ssh_data/public_key/security_key"
require "ssh_data/public_key/rsa" require "ssh_data/public_key/rsa"
require "ssh_data/public_key/dsa" require "ssh_data/public_key/dsa"
require "ssh_data/public_key/ecdsa" require "ssh_data/public_key/ecdsa"

Просмотреть файл

@ -0,0 +1,30 @@
module SSHData
module PublicKey
module SecurityKey
def build_signing_blob(application, signed_data, signature)
read = 0
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature)
read += signature_read
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
read += sk_flags_read
counter, counter_read = Encoding.decode_uint32(signature, read)
read += counter_read
if read != signature.bytesize
raise DecodeError, "unexpected trailing data"
end
application_hash = OpenSSL::Digest::SHA256.digest(application)
message_hash = OpenSSL::Digest::SHA256.digest(signed_data)
blob =
application_hash +
Encoding.encode_uint8(sk_flags) +
Encoding.encode_uint32(counter) +
message_hash
[sig_algo, raw_sig, sk_flags, blob]
end
end
end
end

Просмотреть файл

@ -1,6 +1,7 @@
module SSHData module SSHData
module PublicKey module PublicKey
class SKECDSA < ECDSA class SKECDSA < ECDSA
include SecurityKey
attr_reader :application attr_reader :application
OPENSSL_CURVE_NAME_FOR_CURVE = { OPENSSL_CURVE_NAME_FOR_CURVE = {
@ -34,34 +35,25 @@ module SSHData
) )
end end
def verify(signed_data, signature) def verify(signed_data, signature, **opts)
opts = DEFAULT_SK_VERIFY_OPTS.merge(opts)
read = 0 read = 0
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature) sig_algo, raw_sig, sk_flags, blob = build_signing_blob(application, signed_data, signature)
read += signature_read
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
read += sk_flags_read
counter, counter_read = Encoding.decode_uint32(signature, read)
read += counter_read
if read != signature.bytesize
raise DecodeError, "unexpected trailing data"
end
self.class.check_algorithm!(sig_algo, curve) self.class.check_algorithm!(sig_algo, curve)
application_hash = OpenSSL::Digest::SHA256.digest(application)
message_hash = OpenSSL::Digest::SHA256.digest(signed_data)
blob =
application_hash +
Encoding.encode_uint8(sk_flags) +
Encoding.encode_uint32(counter) +
message_hash
openssl_sig = self.class.openssl_signature(raw_sig) openssl_sig = self.class.openssl_signature(raw_sig)
digest = DIGEST_FOR_CURVE[curve] digest = DIGEST_FOR_CURVE[curve]
openssl.verify(digest.new, openssl_sig, blob) result = openssl.verify(digest.new, openssl_sig, blob)
if opts[:user_presence_required] && (sk_flags & SK_FLAG_USER_PRESENCE != SK_FLAG_USER_PRESENCE)
false
elsif opts[:user_verification_required] && (sk_flags & SK_FLAG_USER_VERIFICATION != SK_FLAG_USER_VERIFICATION)
false
else
result
end
end end
def ==(other) def ==(other)

Просмотреть файл

@ -1,6 +1,7 @@
module SSHData module SSHData
module PublicKey module PublicKey
class SKED25519 < ED25519 class SKED25519 < ED25519
include SecurityKey
attr_reader :application attr_reader :application
def initialize(algo:, pk:, application:) def initialize(algo:, pk:, application:)
@ -23,38 +24,27 @@ module SSHData
) )
end end
def verify(signed_data, signature) def verify(signed_data, signature, **opts)
self.class.ed25519_gem_required! self.class.ed25519_gem_required!
opts = DEFAULT_SK_VERIFY_OPTS.merge(opts)
read = 0 sig_algo, raw_sig, sk_flags, blob = build_signing_blob(application, signed_data, signature)
sig_algo, raw_sig, signature_read = Encoding.decode_signature(signature)
read += signature_read
sk_flags, sk_flags_read = Encoding.decode_uint8(signature, read)
read += sk_flags_read
counter, counter_read = Encoding.decode_uint32(signature, read)
read += counter_read
if read != signature.bytesize
raise DecodeError, "unexpected trailing data"
end
if sig_algo != self.class.algorithm_identifier if sig_algo != self.class.algorithm_identifier
raise DecodeError, "bad signature algorithm: #{sig_algo.inspect}" raise DecodeError, "bad signature algorithm: #{sig_algo.inspect}"
end end
application_hash = OpenSSL::Digest::SHA256.digest(application) result = begin
message_hash = OpenSSL::Digest::SHA256.digest(signed_data) ed25519_key.verify(raw_sig, blob)
rescue Ed25519::VerifyError
false
end
blob = if opts[:user_presence_required] && (sk_flags & SK_FLAG_USER_PRESENCE != SK_FLAG_USER_PRESENCE)
application_hash +
Encoding.encode_uint8(sk_flags) +
Encoding.encode_uint32(counter) +
message_hash
begin
ed25519_key.verify(raw_sig, blob)
rescue Ed25519::VerifyError
false false
elsif opts[:user_verification_required] && (sk_flags & SK_FLAG_USER_VERIFICATION != SK_FLAG_USER_VERIFICATION)
false
else
result
end end
end end

Просмотреть файл

@ -70,7 +70,7 @@ module SSHData
@signature = signature @signature = signature
end end
def verify(signed_data) def verify(signed_data, **opts)
key = public_key key = public_key
digest_algorithm = SUPPORTED_HASH_ALGORITHMS[@hash_algorithm] digest_algorithm = SUPPORTED_HASH_ALGORITHMS[@hash_algorithm]
@ -93,7 +93,11 @@ module SSHData
Encoding.encode_string(@hash_algorithm) + Encoding.encode_string(@hash_algorithm) +
Encoding.encode_string(message_digest) Encoding.encode_string(message_digest)
key.verify(blob, @signature) if key.class.include?(::SSHData::PublicKey::SecurityKey)
key.verify(blob, @signature, **opts)
else
key.verify(blob, @signature)
end
end end
def public_key def public_key