Коммит
1c4cacb58f
|
@ -51,3 +51,6 @@ build-iPhoneSimulator/
|
|||
|
||||
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
||||
.rvmrc
|
||||
|
||||
# macOS generated files
|
||||
.DS_Store
|
||||
|
|
|
@ -12,16 +12,18 @@ module SSHData
|
|||
TYPE_HOST = 2
|
||||
|
||||
# Certificate algorithm identifiers
|
||||
ALGO_RSA = "ssh-rsa-cert-v01@openssh.com"
|
||||
ALGO_DSA = "ssh-dss-cert-v01@openssh.com"
|
||||
ALGO_ECDSA256 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
ALGO_ECDSA384 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
|
||||
ALGO_ECDSA521 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
ALGO_ED25519 = "ssh-ed25519-cert-v01@openssh.com"
|
||||
ALGO_RSA = "ssh-rsa-cert-v01@openssh.com"
|
||||
ALGO_DSA = "ssh-dss-cert-v01@openssh.com"
|
||||
ALGO_ECDSA256 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
ALGO_ECDSA384 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
|
||||
ALGO_ECDSA521 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
|
||||
ALGO_ED25519 = "ssh-ed25519-cert-v01@openssh.com"
|
||||
ALGO_SKECDSA256 = "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com"
|
||||
ALGO_SKED25519 = "sk-ssh-ed25519-cert-v01@openssh.com"
|
||||
|
||||
ALGOS = [
|
||||
ALGO_RSA, ALGO_DSA, ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521,
|
||||
ALGO_ED25519
|
||||
ALGO_ED25519, ALGO_SKECDSA256, ALGO_SKED25519
|
||||
]
|
||||
|
||||
CRITICAL_OPTION_FORCE_COMMAND = "force-command"
|
||||
|
|
|
@ -62,27 +62,44 @@ module SSHData
|
|||
[:public_key, :string]
|
||||
]
|
||||
|
||||
# Fields in an SK-ECDSA public key
|
||||
SKECDSA_KEY_FIELDS = [
|
||||
[:curve, :string],
|
||||
[:public_key, :string],
|
||||
[:application, :string]
|
||||
]
|
||||
|
||||
# Fields in a ED25519 public key
|
||||
ED25519_KEY_FIELDS = [
|
||||
[:pk, :string]
|
||||
]
|
||||
|
||||
# Fields in a SK-ED25519 public key
|
||||
SKED25519_KEY_FIELDS = [
|
||||
[:pk, :string],
|
||||
[:application, :string]
|
||||
]
|
||||
|
||||
PUBLIC_KEY_ALGO_BY_CERT_ALGO = {
|
||||
Certificate::ALGO_RSA => PublicKey::ALGO_RSA,
|
||||
Certificate::ALGO_DSA => PublicKey::ALGO_DSA,
|
||||
Certificate::ALGO_ECDSA256 => PublicKey::ALGO_ECDSA256,
|
||||
Certificate::ALGO_ECDSA384 => PublicKey::ALGO_ECDSA384,
|
||||
Certificate::ALGO_ECDSA521 => PublicKey::ALGO_ECDSA521,
|
||||
Certificate::ALGO_ED25519 => PublicKey::ALGO_ED25519,
|
||||
Certificate::ALGO_RSA => PublicKey::ALGO_RSA,
|
||||
Certificate::ALGO_DSA => PublicKey::ALGO_DSA,
|
||||
Certificate::ALGO_ECDSA256 => PublicKey::ALGO_ECDSA256,
|
||||
Certificate::ALGO_ECDSA384 => PublicKey::ALGO_ECDSA384,
|
||||
Certificate::ALGO_ECDSA521 => PublicKey::ALGO_ECDSA521,
|
||||
Certificate::ALGO_ED25519 => PublicKey::ALGO_ED25519,
|
||||
Certificate::ALGO_SKECDSA256 => PublicKey::ALGO_SKECDSA256,
|
||||
Certificate::ALGO_SKED25519 => PublicKey::ALGO_SKED25519,
|
||||
}
|
||||
|
||||
CERT_ALGO_BY_PUBLIC_KEY_ALGO = {
|
||||
PublicKey::ALGO_RSA => Certificate::ALGO_RSA,
|
||||
PublicKey::ALGO_DSA => Certificate::ALGO_DSA,
|
||||
PublicKey::ALGO_ECDSA256 => Certificate::ALGO_ECDSA256,
|
||||
PublicKey::ALGO_ECDSA384 => Certificate::ALGO_ECDSA384,
|
||||
PublicKey::ALGO_ECDSA521 => Certificate::ALGO_ECDSA521,
|
||||
PublicKey::ALGO_ED25519 => Certificate::ALGO_ED25519,
|
||||
PublicKey::ALGO_RSA => Certificate::ALGO_RSA,
|
||||
PublicKey::ALGO_DSA => Certificate::ALGO_DSA,
|
||||
PublicKey::ALGO_ECDSA256 => Certificate::ALGO_ECDSA256,
|
||||
PublicKey::ALGO_ECDSA384 => Certificate::ALGO_ECDSA384,
|
||||
PublicKey::ALGO_ECDSA521 => Certificate::ALGO_ECDSA521,
|
||||
PublicKey::ALGO_ED25519 => Certificate::ALGO_ED25519,
|
||||
PublicKey::ALGO_SKECDSA256 => Certificate::ALGO_SKECDSA256,
|
||||
PublicKey::ALGO_SKED25519 => Certificate::ALGO_SKED25519,
|
||||
}
|
||||
|
||||
KEY_FIELDS_BY_PUBLIC_KEY_ALGO = {
|
||||
|
@ -92,6 +109,8 @@ module SSHData
|
|||
PublicKey::ALGO_ECDSA384 => ECDSA_KEY_FIELDS,
|
||||
PublicKey::ALGO_ECDSA521 => ECDSA_KEY_FIELDS,
|
||||
PublicKey::ALGO_ED25519 => ED25519_KEY_FIELDS,
|
||||
PublicKey::ALGO_SKED25519 => SKED25519_KEY_FIELDS,
|
||||
PublicKey::ALGO_SKECDSA256 => SKECDSA_KEY_FIELDS,
|
||||
}
|
||||
|
||||
KEY_FIELDS_BY_PRIVATE_KEY_ALGO = {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
module SSHData
|
||||
Error = Class.new(StandardError)
|
||||
DecodeError = Class.new(Error)
|
||||
VerifyError = Class.new(Error)
|
||||
AlgorithmError = Class.new(Error)
|
||||
DecryptError = Class.new(Error)
|
||||
Error = Class.new(StandardError)
|
||||
DecodeError = Class.new(Error)
|
||||
VerifyError = Class.new(Error)
|
||||
AlgorithmError = Class.new(Error)
|
||||
DecryptError = Class.new(Error)
|
||||
UnsupportedError = Class.new(Error)
|
||||
end
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
module SSHData
|
||||
module PublicKey
|
||||
# Public key algorithm identifiers
|
||||
ALGO_RSA = "ssh-rsa"
|
||||
ALGO_DSA = "ssh-dss"
|
||||
ALGO_ECDSA256 = "ecdsa-sha2-nistp256"
|
||||
ALGO_ECDSA384 = "ecdsa-sha2-nistp384"
|
||||
ALGO_ECDSA521 = "ecdsa-sha2-nistp521"
|
||||
ALGO_ED25519 = "ssh-ed25519"
|
||||
ALGO_RSA = "ssh-rsa"
|
||||
ALGO_DSA = "ssh-dss"
|
||||
ALGO_ECDSA256 = "ecdsa-sha2-nistp256"
|
||||
ALGO_ECDSA384 = "ecdsa-sha2-nistp384"
|
||||
ALGO_ECDSA521 = "ecdsa-sha2-nistp521"
|
||||
ALGO_ED25519 = "ssh-ed25519"
|
||||
ALGO_SKED25519 = "sk-ssh-ed25519@openssh.com"
|
||||
ALGO_SKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
|
||||
|
||||
# RSA SHA2 *signature* algorithms used with ALGO_RSA keys.
|
||||
# https://tools.ietf.org/html/draft-rsa-dsa-sha2-256-02
|
||||
|
@ -15,7 +17,7 @@ module SSHData
|
|||
|
||||
ALGOS = [
|
||||
ALGO_RSA, ALGO_DSA, ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521,
|
||||
ALGO_ED25519
|
||||
ALGO_ED25519, ALGO_SKECDSA256, ALGO_SKED25519
|
||||
]
|
||||
|
||||
# Parse an OpenSSH public key in authorized_keys format (see sshd(8) manual
|
||||
|
@ -64,6 +66,10 @@ module SSHData
|
|||
ECDSA.new(**data)
|
||||
when ALGO_ED25519
|
||||
ED25519.new(**data)
|
||||
when ALGO_SKED25519
|
||||
SKED25519.new(**data)
|
||||
when ALGO_SKECDSA256
|
||||
SKECDSA.new(**data)
|
||||
else
|
||||
raise DecodeError, "unkown algo: #{data[:algo].inspect}"
|
||||
end
|
||||
|
@ -76,3 +82,5 @@ require "ssh_data/public_key/rsa"
|
|||
require "ssh_data/public_key/dsa"
|
||||
require "ssh_data/public_key/ecdsa"
|
||||
require "ssh_data/public_key/ed25519"
|
||||
require "ssh_data/public_key/sked25519"
|
||||
require "ssh_data/public_key/skecdsa"
|
||||
|
|
|
@ -65,7 +65,7 @@ module SSHData
|
|||
[Encoding.encode_mpint(r.value), Encoding.encode_mpint(s.value)].join
|
||||
end
|
||||
|
||||
def initialize(algo:, curve:, public_key:)
|
||||
def self.check_algorithm!(algo, curve)
|
||||
unless [ALGO_ECDSA256, ALGO_ECDSA384, ALGO_ECDSA521].include?(algo)
|
||||
raise DecodeError, "bad algorithm: #{algo.inspect}"
|
||||
end
|
||||
|
@ -73,6 +73,10 @@ module SSHData
|
|||
unless algo == "ecdsa-sha2-#{curve}"
|
||||
raise DecodeError, "bad curve: #{curve.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(algo:, curve:, public_key:)
|
||||
self.class.check_algorithm!(algo, curve)
|
||||
|
||||
@curve = curve
|
||||
@public_key_bytes = public_key
|
||||
|
|
|
@ -16,8 +16,12 @@ module SSHData
|
|||
raise AlgorithmError, "the ed25519 gem is not loaded" unless enabled?
|
||||
end
|
||||
|
||||
def self.algorithm_identifier
|
||||
ALGO_ED25519
|
||||
end
|
||||
|
||||
def initialize(algo:, pk:)
|
||||
unless algo == ALGO_ED25519
|
||||
unless algo == self.class.algorithm_identifier
|
||||
raise DecodeError, "bad algorithm: #{algo.inspect}"
|
||||
end
|
||||
|
||||
|
@ -40,7 +44,7 @@ module SSHData
|
|||
self.class.ed25519_gem_required!
|
||||
|
||||
sig_algo, raw_sig, _ = Encoding.decode_signature(signature)
|
||||
if sig_algo != ALGO_ED25519
|
||||
if sig_algo != self.class.algorithm_identifier
|
||||
raise DecodeError, "bad signature algorithm: #{sig_algo.inspect}"
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
module SSHData
|
||||
module PublicKey
|
||||
class SKECDSA < ECDSA
|
||||
attr_reader :application
|
||||
|
||||
OPENSSL_CURVE_NAME_FOR_CURVE = {
|
||||
NISTP256 => "prime256v1",
|
||||
}
|
||||
|
||||
def self.check_algorithm!(algo, curve)
|
||||
unless algo == ALGO_SKECDSA256
|
||||
raise DecodeError, "bad algorithm: #{algo.inspect}"
|
||||
end
|
||||
|
||||
unless algo == "sk-ecdsa-sha2-#{curve}@openssh.com"
|
||||
raise DecodeError, "bad curve: #{curve.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(algo:, curve:, public_key:, application:)
|
||||
@application = application
|
||||
super(algo: algo, curve: curve, public_key: public_key)
|
||||
end
|
||||
|
||||
# RFC4253 binary encoding of the public key.
|
||||
#
|
||||
# Returns a binary String.
|
||||
def rfc4253
|
||||
Encoding.encode_fields(
|
||||
[:string, algo],
|
||||
[:string, curve],
|
||||
[:string, public_key_bytes],
|
||||
[:string, application],
|
||||
)
|
||||
end
|
||||
|
||||
def verify(signed_data, signature)
|
||||
raise UnsupportedError, "SK-ECDSA verification is not supported."
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
super && other.application == application
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,35 @@
|
|||
module SSHData
|
||||
module PublicKey
|
||||
class SKED25519 < ED25519
|
||||
attr_reader :application
|
||||
|
||||
def initialize(algo:, pk:, application:)
|
||||
@application = application
|
||||
super(algo: algo, pk: pk)
|
||||
end
|
||||
|
||||
def self.algorithm_identifier
|
||||
ALGO_SKED25519
|
||||
end
|
||||
|
||||
# RFC4253 binary encoding of the public key.
|
||||
#
|
||||
# Returns a binary String.
|
||||
def rfc4253
|
||||
Encoding.encode_fields(
|
||||
[:string, algo],
|
||||
[:string, pk],
|
||||
[:string, application],
|
||||
)
|
||||
end
|
||||
|
||||
def verify(signed_data, signature)
|
||||
raise UnsupportedError, "SK-Ed25519 verification is not supported."
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
super && other.application == application
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -265,6 +265,22 @@ describe SSHData::Certificate do
|
|||
SSHData::PublicKey::ED25519 # ca key type
|
||||
]
|
||||
|
||||
test_cases << [
|
||||
:skecdsa_leaf_for_rsa_ca, # name
|
||||
"skecdsa_leaf_for_rsa_ca-cert.pub", # fixture
|
||||
SSHData::Certificate::ALGO_SKECDSA256, # algo
|
||||
SSHData::PublicKey::SKECDSA, # public key type
|
||||
SSHData::PublicKey::RSA # ca key type
|
||||
]
|
||||
|
||||
test_cases << [
|
||||
:sked25519_leaf_for_rsa_ca, # name
|
||||
"sked25519_leaf_for_rsa_ca-cert.pub", # fixture
|
||||
SSHData::Certificate::ALGO_SKED25519, # algo
|
||||
SSHData::PublicKey::SKED25519, # public key type
|
||||
SSHData::PublicKey::RSA # ca key type
|
||||
]
|
||||
|
||||
test_cases.each do |name, fixture_name, algo, public_key_class, ca_key_class|
|
||||
describe(name) do
|
||||
let(:openssh) { fixture(fixture_name).strip }
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
#!/bin/bash
|
||||
|
||||
generate_security_keys=0
|
||||
read -p "Generated security key-backed keys (Requires key and user interaction)? [yN] " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
generate_security_keys=1
|
||||
fi
|
||||
|
||||
ssh-keygen -trsa -N "passw0rd" -f ./encrypted_rsa
|
||||
|
||||
ssh-keygen -trsa -N "" -f ./rsa_ca
|
||||
|
@ -34,6 +42,15 @@ ssh-keygen -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O
|
|||
ssh-keygen -ted25519 -N "" -f ./ed25519_leaf_for_rsa_ca
|
||||
ssh-keygen -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding ed25519_leaf_for_rsa_ca.pub
|
||||
|
||||
if [[ $generate_security_keys -eq 1 ]]
|
||||
then
|
||||
ssh-keygen -t ed25519-sk -N "" -f ./sked25519_leaf_for_rsa_ca
|
||||
ssh-keygen -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding sked25519_leaf_for_rsa_ca.pub
|
||||
|
||||
ssh-keygen -t ecdsa-sk -N "" -f ./skecdsa_leaf_for_rsa_ca
|
||||
ssh-keygen -s rsa_ca -z 123 -n p1,p2 -O clear -I my-ident -O critical:foo=bar -O extension:baz=qwer -O permit-X11-forwarding skecdsa_leaf_for_rsa_ca.pub
|
||||
fi
|
||||
|
||||
# critical opts
|
||||
ssh-keygen -trsa -N "" -f ./valid_force_command
|
||||
ssh-keygen -s rsa_ca -z 123 -O clear -I my-ident -O force-command=asdf valid_force_command.pub
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAfwAAACJzay1lY2
|
||||
RzYS1zaGEyLW5pc3RwMjU2QG9wZW5zc2guY29tAAAACG5pc3RwMjU2AAAAQQSqeZ1z1lJp
|
||||
zAnH15AFievReD+0b8sNYzAILAPYAmiXcZp9J390Lt76EEgkTT9oTsscV73g+4nMAIT6Dk
|
||||
g4dMAHAAAABHNzaDoAAAD4p3ZrwKd2a8AAAAAic2stZWNkc2Etc2hhMi1uaXN0cDI1NkBv
|
||||
cGVuc3NoLmNvbQAAAAhuaXN0cDI1NgAAAEEEqnmdc9ZSacwJx9eQBYnr0Xg/tG/LDWMwCC
|
||||
wD2AJol3GafSd/dC7e+hBIJE0/aE7LHFe94PuJzACE+g5IOHTABwAAAARzc2g6AQAAAEAk
|
||||
NPI6juY+SUhu48d8HVCtsGi27CPrZgW48J1ECJ4F7kzuKMtltkWG5P9Xyt4f2/OWTaIosx
|
||||
Nqx+fKOOdMSsJ7AAAAAAAAACF2Y3Nqb25lc0BLZXZpbnMtTWFjQm9vay1Qcm8ubG9jYWwB
|
||||
AgM=
|
||||
-----END OPENSSH PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
|||
sk-ecdsa-sha2-nistp256-cert-v01@openssh.com AAAAK3NrLWVjZHNhLXNoYTItbmlzdHAyNTYtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgy+rVqT5sFrUgijvmuGitZs9CDcGHoO3MrxXdAUCrXFIAAAAIbmlzdHAyNTYAAABBBKp5nXPWUmnMCcfXkAWJ69F4P7Rvyw1jMAgsA9gCaJdxmn0nf3Qu3voQSCRNP2hOyxxXveD7icwAhPoOSDh0wAcAAAAEc3NoOgAAAAAAAAB7AAAAAQAAAAhteS1pZGVudAAAAAwAAAACcDEAAAACcDIAAAAAAAAAAP//////////AAAAEgAAAANmb28AAAAHAAAAA2JhcgAAADAAAAADYmF6AAAACAAAAARxd2VyAAAAFXBlcm1pdC1YMTEtZm9yd2FyZGluZwAAAAAAAAAAAAABFwAAAAdzc2gtcnNhAAAAAwEAAQAAAQEAzwdtEkuEctGoVSRiH+WmEVPNT8LVIgy49goVJzH2LQmHprnCEY5H01Krh83j23nFGlsfzR19Bh0b+3ODTvk2Mf1DwwuntmZkYQ0cv6XOarckbu36gUrK4QQLwHb9dxeS8zJUb/qGVyBAXjTPGXdzSIGqc7THcZARfi7DZLG4rIPYsUyXDm94kmVc0D+L5kB9cL4jtP1hWI/q0t066E+oD8VLmn804XFxbcS1gFwDPn/Wyz/XCR1twABn6IcpUSk3FbMUu8e2JY6ytBMHwIeCr40wJ5OYKW3Sx2j8HkazetnmHyEWcQrm3XnQ1bmdz1ZVJkFgIZ7R1JCJwfppZD/x7wAAARQAAAAMcnNhLXNoYTItNTEyAAABAACAK/gx7srkr1AiUtS206W/UzvBHL+SkoG80mgEu9IAOyNv+h5fmIsxGCCYce9z7+36ujLnU/+FoROkS3F0zkyxBzCk4U1zgeHMNLAJdPGrLuapsEyeUJkLtLpiFnvaOiXYwXgmUONEtOUBsaJqXOLChUBjuMxg6Me4joab8Ir3HU065J45lmHBbPdiG4GU7AP/dVadTe4gWv5RkZU30NGI8NxapEFN4im4rSw7EisXyNVvK/lIAX0xC8n8FmCxtE5h/87MvVziJRgI+AeenhRqcLInl2fg6OQk1ziWg8FOBVRVt2/FA+SGqzWq7uHInfwTx1ZGE8GtqKTsfK30qis= vcsjones@Kevins-MacBook-Pro.local
|
|
@ -0,0 +1 @@
|
|||
sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBKp5nXPWUmnMCcfXkAWJ69F4P7Rvyw1jMAgsA9gCaJdxmn0nf3Qu3voQSCRNP2hOyxxXveD7icwAhPoOSDh0wAcAAAAEc3NoOg== vcsjones@Kevins-MacBook-Pro.local
|
|
@ -0,0 +1,10 @@
|
|||
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAASgAAABpzay1zc2
|
||||
gtZWQyNTUxOUBvcGVuc3NoLmNvbQAAACA3xPtT9yVKAyJr3fhB105GFoG3NInJdsfe91aN
|
||||
GHBqhgAAAARzc2g6AAAA+NhG/FXYRvxVAAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY2
|
||||
9tAAAAIDfE+1P3JUoDImvd+EHXTkYWgbc0icl2x973Vo0YcGqGAAAABHNzaDoBAAAAgPM8
|
||||
JGbyftt6rqAO8cPWw0rXW394+heb5h07rtW/bkxM7SpTYbuKS/Z2ETwv9iX6u3NIqxQDlj
|
||||
71iWawf/VFsBYGT4GBf2dVsmH5Bd2yAl7kuljFzqkWPbWlENwScPjlfK2ZfgtcWMJz2wU1
|
||||
CLUNNhqorCTvRUZbsb7Dw0aOh9gjAAAAAAAAABN2Y3Nqb25lc0BLZXZpbnMtTUJQAQIDBA
|
||||
UG
|
||||
-----END OPENSSH PRIVATE KEY-----
|
|
@ -0,0 +1 @@
|
|||
sk-ssh-ed25519-cert-v01@openssh.com AAAAI3NrLXNzaC1lZDI1NTE5LWNlcnQtdjAxQG9wZW5zc2guY29tAAAAIA9W0s0HknrDboFqbQQ8bqPF78qPEyB5fAGrTRufG/dsAAAAIDfE+1P3JUoDImvd+EHXTkYWgbc0icl2x973Vo0YcGqGAAAABHNzaDoAAAAAAAAAewAAAAEAAAAIbXktaWRlbnQAAAAMAAAAAnAxAAAAAnAyAAAAAAAAAAD//////////wAAABIAAAADZm9vAAAABwAAAANiYXIAAAAwAAAAA2JhegAAAAgAAAAEcXdlcgAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAAAAAARcAAAAHc3NoLXJzYQAAAAMBAAEAAAEBAM8HbRJLhHLRqFUkYh/lphFTzU/C1SIMuPYKFScx9i0Jh6a5whGOR9NSq4fN49t5xRpbH80dfQYdG/tzg075NjH9Q8MLp7ZmZGENHL+lzmq3JG7t+oFKyuEEC8B2/XcXkvMyVG/6hlcgQF40zxl3c0iBqnO0x3GQEX4uw2SxuKyD2LFMlw5veJJlXNA/i+ZAfXC+I7T9YViP6tLdOuhPqA/FS5p/NOFxcW3EtYBcAz5/1ss/1wkdbcAAZ+iHKVEpNxWzFLvHtiWOsrQTB8CHgq+NMCeTmClt0sdo/B5Gs3rZ5h8hFnEK5t150NW5nc9WVSZBYCGe0dSQicH6aWQ/8e8AAAEUAAAADHJzYS1zaGEyLTUxMgAAAQCoT7uBIJWX3Hs/ofiCB/p/XaVGbLq3unStZ7h+Goy6VhT0GcRl/CkJER0P5wbrCvf2KQQL9u6TgcXjs+JQzMk/yEdXUfNsIisMFh/KgF7XB08Rs/Gkralggz2aCUOCnCS4h323fwNpsbSf5SMfqWnwx8qGe7wgOkhxvgYZGQ8P10+46JpZMjRkVAevJU/toWL5VdvtO99OUtDZ/RJ+bx4j4/zh4xcuCCiq2e/iE7HFZjuiVOSYTQbNIb/KQT1M+8aJQyMQz/lble2ZOXG0Q3VrlWsZzgNQUZtqjFxIf2p8ghjUir4nCbCZdihJIl5/Uc0kVGdulGrFJt1OHKWPJijs vcsjones@Kevins-MBP
|
|
@ -0,0 +1 @@
|
|||
sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIDfE+1P3JUoDImvd+EHXTkYWgbc0icl2x973Vo0YcGqGAAAABHNzaDo= vcsjones@Kevins-MBP
|
|
@ -1,7 +1,7 @@
|
|||
require_relative "./spec_helper"
|
||||
|
||||
describe SSHData::PrivateKey do
|
||||
(Dir["spec/fixtures/*for_rsa_ca"] + Dir["spec/fixtures/*.plaintext.pem"]).each do |path|
|
||||
(Dir["spec/fixtures/*for_rsa_ca"].reject { |p| p =~ /skecdsa|sked25519/ } + Dir["spec/fixtures/*.plaintext.pem"]).each do |path|
|
||||
name = File.basename(path)
|
||||
|
||||
describe name do
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
require_relative "../spec_helper"
|
||||
|
||||
describe SSHData::PublicKey::SKECDSA do
|
||||
let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("skecdsa_leaf_for_rsa_ca.pub")) }
|
||||
let(:ec_p384_publickey) { OpenSSL::PKey::EC.new('secp384r1').tap { |k|
|
||||
k.generate_key
|
||||
k.private_key = nil
|
||||
}
|
||||
}
|
||||
|
||||
it "can parse openssh-generate keys" do
|
||||
expect { openssh_key }.not_to raise_error
|
||||
end
|
||||
|
||||
it "can be rencoded" do
|
||||
expect(openssh_key.rfc4253).to eq(fixture("skecdsa_leaf_for_rsa_ca.pub", binary: true))
|
||||
end
|
||||
|
||||
it "blows up if the inner key identifier is not a security key" do
|
||||
# outer layer claims to be SK-ECDSA256, but inner key is plain ECDSA256
|
||||
malformed = [SSHData::PublicKey::ALGO_SKECDSA256, Base64.strict_encode64([
|
||||
SSHData::Encoding.encode_string(SSHData::PublicKey::ALGO_ECDSA256),
|
||||
SSHData::Encoding.encode_string(openssh_key.curve),
|
||||
SSHData::Encoding.encode_string(openssh_key.public_key_bytes),
|
||||
SSHData::Encoding.encode_string('ssh:'),
|
||||
].join)].join(" ")
|
||||
|
||||
expect {
|
||||
SSHData::PublicKey.parse_openssh(malformed)
|
||||
}.to raise_error(SSHData::DecodeError)
|
||||
end
|
||||
|
||||
it "blows up if the inner key identifier has a mismatched curve" do
|
||||
# outer layer claims to be SK-ECDSA256, but inner key is SK-ECDSA256 with a P384 curve
|
||||
malformed = [SSHData::PublicKey::ALGO_SKECDSA256, Base64.strict_encode64([
|
||||
SSHData::Encoding.encode_string(SSHData::PublicKey::ALGO_SKECDSA256),
|
||||
SSHData::Encoding.encode_string('nistp384'),
|
||||
SSHData::Encoding.encode_string(ec_p384_publickey.to_der),
|
||||
SSHData::Encoding.encode_string('ssh:'),
|
||||
].join)].join(" ")
|
||||
|
||||
expect {
|
||||
SSHData::PublicKey.parse_openssh(malformed)
|
||||
}.to raise_error(SSHData::DecodeError)
|
||||
end
|
||||
|
||||
described_class::OPENSSL_CURVE_NAME_FOR_CURVE.each do |ssh_curve, openssl_curve|
|
||||
describe openssl_curve do
|
||||
let(:algo) { "sk-ecdsa-sha2-#{ssh_curve}@openssh.com" }
|
||||
|
||||
let(:private_key) { OpenSSL::PKey::EC.new(openssl_curve).tap(&:generate_key) }
|
||||
let(:public_key) { OpenSSL::PKey::EC.new(private_key.to_der).tap { |k| k.private_key = nil } }
|
||||
|
||||
let(:msg) { "hello, world!" }
|
||||
let(:digest) { described_class::DIGEST_FOR_CURVE[ssh_curve].new }
|
||||
let(:openssl_sig) { private_key.sign(digest, msg) }
|
||||
let(:ssh_sig) { described_class.ssh_signature(openssl_sig) }
|
||||
let(:sig) { SSHData::Encoding.encode_signature(algo, ssh_sig) }
|
||||
let(:application) { "ssh:" }
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
algo: algo,
|
||||
curve: ssh_curve,
|
||||
public_key: public_key.public_key.to_bn.to_s(2),
|
||||
application: application,
|
||||
)
|
||||
end
|
||||
|
||||
it "is equal to keys with the same params" do
|
||||
expect(subject).to eq(described_class.new(
|
||||
algo: algo,
|
||||
curve: ssh_curve,
|
||||
public_key: public_key.public_key.to_bn.to_s(2),
|
||||
application: application,
|
||||
))
|
||||
end
|
||||
|
||||
it "isnt equal to keys with different params" do
|
||||
other_key = OpenSSL::PKey::EC.new(openssl_curve).tap(&:generate_key)
|
||||
|
||||
expect(subject).not_to eq(described_class.new(
|
||||
algo: algo,
|
||||
curve: ssh_curve,
|
||||
public_key: other_key.public_key.to_bn.to_s(2),
|
||||
application: application,
|
||||
))
|
||||
end
|
||||
|
||||
it "has an algo" do
|
||||
expect(subject.algo).to eq(algo)
|
||||
end
|
||||
|
||||
it "has parameters" do
|
||||
expect(subject.curve).to eq(ssh_curve)
|
||||
expect(subject.public_key_bytes).to eq(public_key.public_key.to_bn.to_s(2))
|
||||
end
|
||||
|
||||
it "has an openssl representation" do
|
||||
expect(subject.openssl).to be_a(OpenSSL::PKey::EC)
|
||||
expect(subject.openssl.public_key).to eq(public_key.public_key)
|
||||
end
|
||||
|
||||
it "can encode/decode signatures" do
|
||||
round_tripped = described_class.openssl_signature(
|
||||
described_class.ssh_signature(openssl_sig)
|
||||
)
|
||||
|
||||
expect(round_tripped).to eq(openssl_sig)
|
||||
end
|
||||
|
||||
it "can not verify signatures" do
|
||||
expect { subject.verify(msg, sig) }.to raise_error(SSHData::UnsupportedError)
|
||||
end
|
||||
|
||||
it "blows up parsing malformed keys" do
|
||||
malformed = [algo, Base64.strict_encode64([
|
||||
SSHData::Encoding.encode_string(algo),
|
||||
SSHData::Encoding.encode_string(ssh_curve),
|
||||
SSHData::Encoding.encode_string(subject.public_key_bytes[0...-1]),
|
||||
].join)].join(" ")
|
||||
|
||||
expect {
|
||||
SSHData::PublicKey.parse_openssh(malformed)
|
||||
}.to raise_error(SSHData::DecodeError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,67 @@
|
|||
require_relative "../spec_helper"
|
||||
|
||||
describe SSHData::PublicKey::SKED25519 do
|
||||
let(:signing_key) { Ed25519::SigningKey.generate }
|
||||
let(:verify_key) { signing_key.verify_key }
|
||||
|
||||
let(:msg) { "hello, world!" }
|
||||
let(:raw_sig) { signing_key.sign(msg) }
|
||||
let(:sig) { SSHData::Encoding.encode_signature(SSHData::PublicKey::ALGO_SKED25519, raw_sig) }
|
||||
let(:application) { "ssh:" }
|
||||
|
||||
let(:openssh_key) { SSHData::PublicKey.parse_openssh(fixture("sked25519_leaf_for_rsa_ca.pub")) }
|
||||
|
||||
subject do
|
||||
described_class.new(
|
||||
algo: SSHData::PublicKey::ALGO_SKED25519,
|
||||
pk: verify_key.to_bytes,
|
||||
application: application
|
||||
)
|
||||
end
|
||||
|
||||
it "is equal to keys with the same params" do
|
||||
expect(subject).to eq(described_class.new(
|
||||
algo: SSHData::PublicKey::ALGO_SKED25519,
|
||||
pk: verify_key.to_bytes,
|
||||
application: application
|
||||
))
|
||||
end
|
||||
|
||||
it "isnt equal to keys with different params" do
|
||||
expect(subject).not_to eq(described_class.new(
|
||||
algo: SSHData::PublicKey::ALGO_SKED25519,
|
||||
pk: verify_key.to_bytes.reverse,
|
||||
application: application
|
||||
))
|
||||
expect(subject).not_to eq(described_class.new(
|
||||
algo: SSHData::PublicKey::ALGO_SKED25519,
|
||||
pk: verify_key.to_bytes,
|
||||
application: "something else"
|
||||
))
|
||||
end
|
||||
|
||||
it "has an algo" do
|
||||
expect(subject.algo).to eq(SSHData::PublicKey::ALGO_SKED25519)
|
||||
end
|
||||
|
||||
it "has parameters" do
|
||||
expect(subject.pk).to eq(verify_key.to_bytes)
|
||||
end
|
||||
|
||||
it "has application" do
|
||||
expect(subject.application).to eq(application)
|
||||
end
|
||||
|
||||
it "has an Ed25519 representation" do
|
||||
expect(subject.ed25519_key).to be_a(Ed25519::VerifyKey)
|
||||
expect(subject.ed25519_key.to_bytes).to eq(verify_key.to_bytes)
|
||||
end
|
||||
|
||||
it "can not verify signatures" do
|
||||
expect { subject.verify(msg, sig) }.to raise_error(SSHData::UnsupportedError)
|
||||
end
|
||||
|
||||
it "can be rencoded" do
|
||||
expect(openssh_key.rfc4253).to eq(fixture("sked25519_leaf_for_rsa_ca.pub", binary: true))
|
||||
end
|
||||
end
|
Загрузка…
Ссылка в новой задаче