diff options
author | Miklós Fazekas <mfazekas@szemafor.com> | 2018-03-21 15:36:44 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-03-21 15:36:44 +0100 |
commit | d294e0c1645778395ba071f731043bbf8b8554e3 (patch) | |
tree | 8d091966789caef15f39deaa1d9e4bff17bab768 | |
parent | 9463579e6e875d255ce93a0a1cc893b927672a13 (diff) | |
parent | 8f545802bbf05931dfcb46434a54c1fdfdfb7fb4 (diff) | |
download | net-ssh-d294e0c1645778395ba071f731043bbf8b8554e3.tar.gz |
Merge pull request #585 from mfazekas/sha-fingerprint
Sha fingerprint
-rw-r--r-- | lib/net/ssh/authentication/ed25519.rb | 75 | ||||
-rw-r--r-- | lib/net/ssh/authentication/pub_key_fingerprint.rb | 41 | ||||
-rw-r--r-- | lib/net/ssh/transport/openssl.rb | 5 | ||||
-rw-r--r-- | lib/net/ssh/version.rb | 29 | ||||
-rw-r--r-- | test/authentication/test_ed25519.rb | 44 | ||||
-rw-r--r-- | test/test_key_factory.rb | 90 |
6 files changed, 217 insertions, 67 deletions
diff --git a/lib/net/ssh/authentication/ed25519.rb b/lib/net/ssh/authentication/ed25519.rb index bcb7fd1..2f98fa1 100644 --- a/lib/net/ssh/authentication/ed25519.rb +++ b/lib/net/ssh/authentication/ed25519.rb @@ -6,67 +6,66 @@ require 'ed25519' require 'base64' require 'net/ssh/transport/cipher_factory' +require 'net/ssh/authentication/pub_key_fingerprint' require 'bcrypt_pbkdf' unless RUBY_PLATFORM == "java" -module Net - module SSH +module Net + module SSH module Authentication module ED25519 class SigningKeyFromFile < SimpleDelegator def initialize(pk,sk) key = ::Ed25519::SigningKey.from_keypair(sk) raise ArgumentError, "pk does not match sk" unless pk == key.verify_key.to_bytes - + super(key) end end - + class PubKey + include Net::SSH::Authentication::PubKeyFingerprint + attr_reader :verify_key - + def initialize(data) @verify_key = ::Ed25519::VerifyKey.new(data) end - + def self.read_keyblob(buffer) PubKey.new(buffer.read_string) end - + def to_blob Net::SSH::Buffer.from(:mstring,"ssh-ed25519",:string,@verify_key.to_bytes).to_s end - + def ssh_type "ssh-ed25519" end - + def ssh_signature_type ssh_type end - + def ssh_do_verify(sig,data) @verify_key.verify(sig,data) end - + def to_pem # TODO this is not pem ssh_type + Base64.encode64(@verify_key.to_bytes) end - - def fingerprint - @fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":") - end end - + class PrivKey CipherFactory = Net::SSH::Transport::CipherFactory - + MBEGIN = "-----BEGIN OPENSSH PRIVATE KEY-----\n" MEND = "-----END OPENSSH PRIVATE KEY-----\n" MAGIC = "openssh-key-v1" - + attr_reader :sign_key - + def initialize(datafull,password) raise ArgumentError.new("Expected #{MBEGIN} at start of private key") unless datafull.start_with?(MBEGIN) raise ArgumentError.new("Expected #{MEND} at end of private key") unless datafull.end_with?(MEND) @@ -74,75 +73,75 @@ module Net data = Base64.decode64(datab64) raise ArgumentError.new("Expected #{MAGIC} at start of decoded private key") unless data.start_with?(MAGIC) buffer = Net::SSH::Buffer.new(data[MAGIC.size + 1..-1]) - + ciphername = buffer.read_string raise ArgumentError.new("#{ciphername} in private key is not supported") unless CipherFactory.supported?(ciphername) - + kdfname = buffer.read_string raise ArgumentError.new("Expected #{kdfname} to be or none or bcrypt") unless %w[none bcrypt].include?(kdfname) - + kdfopts = Net::SSH::Buffer.new(buffer.read_string) num_keys = buffer.read_long raise ArgumentError.new("Only 1 key is supported in ssh keys #{num_keys} was in private key") unless num_keys == 1 _pubkey = buffer.read_string - + len = buffer.read_long - + keylen, blocksize, ivlen = CipherFactory.get_lengths(ciphername, iv_len: true) raise ArgumentError.new("Private key len:#{len} is not a multiple of #{blocksize}") if ((len < blocksize) || ((blocksize > 0) && (len % blocksize) != 0)) - + if kdfname == 'bcrypt' salt = kdfopts.read_string rounds = kdfopts.read_long - + raise "BCryptPbkdf is not implemented for jruby" if RUBY_PLATFORM == "java" key = BCryptPbkdf::key(password, salt, keylen + ivlen, rounds) else key = '\x00' * (keylen + ivlen) end - + cipher = CipherFactory.get(ciphername, key: key[0...keylen], iv:key[keylen...keylen + ivlen], decrypt: true) - + decoded = cipher.update(buffer.remainder_as_buffer.to_s) decoded << cipher.final - + decoded = Net::SSH::Buffer.new(decoded) check1 = decoded.read_long check2 = decoded.read_long - + raise ArgumentError, "Decrypt failed on private key" if (check1 != check2) - + _type_name = decoded.read_string pk = decoded.read_string sk = decoded.read_string _comment = decoded.read_string - + @pk = pk @sign_key = SigningKeyFromFile.new(pk,sk) end - + def to_blob public_key.to_blob end - + def ssh_type "ssh-ed25519" end - + def ssh_signature_type ssh_type end - + def public_key PubKey.new(@pk) end - + def ssh_do_sign(data) @sign_key.sign(data) end - + def self.read(data,password) self.new(data,password) end diff --git a/lib/net/ssh/authentication/pub_key_fingerprint.rb b/lib/net/ssh/authentication/pub_key_fingerprint.rb new file mode 100644 index 0000000..e06aeef --- /dev/null +++ b/lib/net/ssh/authentication/pub_key_fingerprint.rb @@ -0,0 +1,41 @@ + +require 'openssl' + +module Net + module SSH + module Authentication + # Public key fingerprinting utility module - internal not part of API. + # This is included in pubkey classes and called from there. All RSA, DSA, and ECC keys + # are supported. + # + # require 'net/ssh' + # my_pubkey_text = File.read('/path/to/id_ed25519.pub') + # #=> "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDB2NBh4GJPPUN1kXPMu8b633Xcv55WoKC3OkBjFAbzJ alice@example.com" + # my_pubkey = Net::SSH::KeyFactory.load_data_public_key(my_pubkey_text) + # #=> #<Net::SSH::Authentication::ED25519::PubKey:0x00007fc8e91819b0 + # my_pubkey.fingerprint + # #=> "2f:7f:97:21:76:a4:0f:38:c4:fe:d8:b4:6a:39:72:30" + # my_pubkey.fingerprint('SHA256') + # #=> "SHA256:u6mXnY8P1b0FODGp8mckqOB33u8+jvkSCtJbD5Q9klg" + module PubKeyFingerprint # :nodoc: + # Return the key's fingerprint. Algorithm may be either +MD5+ (default), + # or +SHA256+. For +SHA256+, fingerprints are in the same format + # returned by OpenSSH's <tt>`ssh-add -l -E SHA256`</tt>, i.e., + # trailing base64 padding '=' characters are stripped and the + # literal string +SHA256:+ is prepended. + def fingerprint(algorithm='MD5') + @fingerprint ||= {} + @fingerprint[algorithm] ||= + case algorithm.to_s.upcase + when 'MD5' + OpenSSL::Digest.hexdigest(algorithm, to_blob).scan(/../).join(":") + when 'SHA256' + "SHA256:#{Base64.encode64(OpenSSL::Digest.digest(algorithm, to_blob)).chomp.gsub(/=+\z/, '')}" + else + raise OpenSSL::Digest::DigestError, "unsupported ssh key digest #{algorithm}" + end + end + end + end + end +end diff --git a/lib/net/ssh/transport/openssl.rb b/lib/net/ssh/transport/openssl.rb index 9135ae0..15715f4 100644 --- a/lib/net/ssh/transport/openssl.rb +++ b/lib/net/ssh/transport/openssl.rb @@ -1,4 +1,5 @@ require 'openssl' +require 'net/ssh/authentication/pub_key_fingerprint' module OpenSSL @@ -25,9 +26,7 @@ module OpenSSL module PKey class PKey - def fingerprint - @fingerprint ||= OpenSSL::Digest::MD5.hexdigest(to_blob).scan(/../).join(":") - end + include Net::SSH::Authentication::PubKeyFingerprint end # This class is originally defined in the OpenSSL module. As needed, methods diff --git a/lib/net/ssh/version.rb b/lib/net/ssh/version.rb index fcd5db8..c1a6cca 100644 --- a/lib/net/ssh/version.rb +++ b/lib/net/ssh/version.rb @@ -1,4 +1,4 @@ -module Net +module Net module SSH # A class for describing the current version of a library. The version # consists of three parts: the +major+ number, the +minor+ number, and the @@ -14,54 +14,55 @@ module Net # end class Version include Comparable - + # A convenience method for instantiating a new Version instance with the # given +major+, +minor+, and +tiny+ components. def self.[](major, minor, tiny, pre = nil) new(major, minor, tiny, pre) end - + attr_reader :major, :minor, :tiny - + # Create a new Version object with the given components. def initialize(major, minor, tiny, pre = nil) @major, @minor, @tiny, @pre = major, minor, tiny, pre end - + # Compare this version to the given +version+ object. def <=>(version) to_i <=> version.to_i end - + # Converts this version object to a string, where each of the three # version components are joined by the '.' character. E.g., 2.0.0. def to_s @to_s ||= [@major, @minor, @tiny, @pre].compact.join(".") end - + # Converts this version to a canonical integer that may be compared # against other version objects. def to_i @to_i ||= @major * 1_000_000 + @minor * 1_000 + @tiny end - + # The major component of this version of the Net::SSH library MAJOR = 5 - + # The minor component of this version of the Net::SSH library MINOR = 0 - + # The tiny component of this version of the Net::SSH library TINY = 0 - + # The prerelease component of this version of the Net::SSH library # nil allowed PRE = "beta1" - + # The current version of the Net::SSH library as a Version instance CURRENT = new(*[MAJOR, MINOR, TINY, PRE].compact) - + # The current version of the Net::SSH library as a String STRING = CURRENT.to_s end -end; end + end +end diff --git a/test/authentication/test_ed25519.rb b/test/authentication/test_ed25519.rb index 620942b..6c0bca5 100644 --- a/test/authentication/test_ed25519.rb +++ b/test/authentication/test_ed25519.rb @@ -5,27 +5,29 @@ unless ENV['NET_SSH_NO_ED25519'] require 'base64' module Authentication - + class TestED25519 < NetSSHTest def setup raise "No ED25519 set NET_SSH_NO_ED25519 to ignore this test" unless Net::SSH::Authentication::ED25519Loader::LOADED end - + def test_no_pwd_key pub = Net::SSH::Buffer.new(Base64.decode64(public_key_no_pwd.split(' ')[1])) _type = pub.read_string pub_data = pub.read_string priv = private_key_no_pwd - + pub_key = Net::SSH::Authentication::ED25519::PubKey.new(pub_data) priv_key = Net::SSH::Authentication::ED25519::PrivKey.new(priv,nil) - + shared_secret = "Hello" signed = priv_key.ssh_do_sign(shared_secret) self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret)) self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint) + self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_no_pwd) + self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_no_pwd) end - + def test_pwd_key if defined?(JRUBY_VERSION) puts "Skipping password protected ED25519 for JRuby" @@ -35,16 +37,18 @@ unless ENV['NET_SSH_NO_ED25519'] _type = pub.read_string pub_data = pub.read_string priv = private_key_pwd - + pub_key = Net::SSH::Authentication::ED25519::PubKey.new(pub_data) priv_key = Net::SSH::Authentication::ED25519::PrivKey.new(priv,'pwd') - + shared_secret = "Hello" signed = priv_key.ssh_do_sign(shared_secret) self.assert_equal(true,pub_key.ssh_do_verify(signed,shared_secret)) self.assert_equal(priv_key.public_key.fingerprint, pub_key.fingerprint) + self.assert_equal(pub_key.fingerprint, key_fingerprint_md5_pwd) + self.assert_equal(pub_key.fingerprint('sha256'), key_fingerprint_sha256_pwd) end - + def private_key_pwd @pwd_key = <<-EOF -----BEGIN OPENSSH PRIVATE KEY----- @@ -57,11 +61,19 @@ oPcTikV1iWH5Xc+GxRFRRGTN/6HvBf0AKDB1kMXlDhGnBnHGeNH1pk44xG -----END OPENSSH PRIVATE KEY----- EOF end - + def public_key_pwd 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICaHkFaGXqYhUVFcaZ10TPUbkIvmaFXwYRoOS5qE8Mci vagrant@vagrant-ubuntu-trusty-64' end - + + def key_fingerprint_md5_pwd + 'c8:89:92:60:12:1b:01:5e:ca:58:55:68:7e:5e:1a:f1' + end + + def key_fingerprint_sha256_pwd + 'SHA256:Uz5Qk/fB+f8Bu7FTxNcDh7+atpB29Q3tBBJX/gnUfGw' + end + def private_key_no_pwd @anonymous_key = <<-EOF -----BEGIN OPENSSH PRIVATE KEY----- @@ -74,12 +86,20 @@ IDBAU= -----END OPENSSH PRIVATE KEY----- EOF end - + def public_key_no_pwd 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDB2NBh4GJPPUN1kXPMu8b633Xcv55WoKC3OkBjFAbzJ vagrant@vagrant-ubuntu-trusty-64' end + + def key_fingerprint_md5_no_pwd + '2f:7f:97:21:76:a4:0f:38:c4:fe:d8:b4:6a:39:72:30' + end + + def key_fingerprint_sha256_no_pwd + 'SHA256:u6mXnY8P1b0FODGp8mckqOB33u8+jvkSCtJbD5Q9klg' + end end - + end end diff --git a/test/test_key_factory.rb b/test/test_key_factory.rb index 9e0d85e..0780868 100644 --- a/test/test_key_factory.rb +++ b/test/test_key_factory.rb @@ -11,11 +11,31 @@ class TestKeyFactory < NetSSHTest assert_equal rsa_key.to_der, Net::SSH::KeyFactory.load_private_key(@key_file).to_der end + def test_load_unencrypted_private_RSA_key_should_have_fp_md5 + File.expects(:read).with(@key_file).returns(rsa_key.export) + assert_equal rsa_key_fingerprint_md5, Net::SSH::KeyFactory.load_private_key(@key_file).fingerprint + end + + def test_load_unencrypted_private_RSA_key_should_have_fp_sha256 + File.expects(:read).with(@key_file).returns(rsa_key.export) + assert_equal rsa_key_fingerprint_sha256, Net::SSH::KeyFactory.load_private_key(@key_file).fingerprint('sha256') + end + def test_load_unencrypted_private_DSA_key_should_return_key File.expects(:read).with(@key_file).returns(dsa_key.export) assert_equal dsa_key.to_der, Net::SSH::KeyFactory.load_private_key(@key_file).to_der end + def test_load_unencrypted_private_DSA_key_should_have_fp_md5 + File.expects(:read).with(@key_file).returns(dsa_key.export) + assert_equal dsa_key_fingerprint_md5, Net::SSH::KeyFactory.load_private_key(@key_file).fingerprint + end + + def test_load_unencrypted_private_DSA_key_should_have_fp_sha256 + File.expects(:read).with(@key_file).returns(dsa_key.export) + assert_equal dsa_key_fingerprint_sha256, Net::SSH::KeyFactory.load_private_key(@key_file).fingerprint('sha256') + end + def test_load_encrypted_private_RSA_key_should_prompt_for_password_and_return_key prompt = MockPrompt.new File.expects(:read).with(@key_file).returns(encrypted(rsa_key, "password")) @@ -100,6 +120,36 @@ class TestKeyFactory < NetSSHTest assert_equal ecdsa_sha2_nistp521_key.to_der, Net::SSH::KeyFactory.load_private_key("/key-file").to_der end + def test_load_unencrypted_private_ecdsa_sha2_nistp256_key_should_have_fp_md5 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp256_key.to_pem) + assert_equal ecdsa_sha2_nistp256_key_fingerprint_md5, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint + end + + def test_load_unencrypted_private_ecdsa_sha2_nistp256_key_should_have_fp_sha256 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp256_key.to_pem) + assert_equal ecdsa_sha2_nistp256_key_fingerprint_sha256, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint('sha256') + end + + def test_load_unencrypted_private_ecdsa_sha2_nistp384_key_should_have_fp_md5 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp384_key.to_pem) + assert_equal ecdsa_sha2_nistp384_key_fingerprint_md5, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint + end + + def test_load_unencrypted_private_ecdsa_sha2_nistp384_key_should_have_fp_sha256 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp384_key.to_pem) + assert_equal ecdsa_sha2_nistp384_key_fingerprint_sha256, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint('sha256') + end + + def test_load_unencrypted_private_ecdsa_sha2_nistp521_key_should_have_fp_md5 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp521_key.to_pem) + assert_equal ecdsa_sha2_nistp521_key_fingerprint_md5, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint + end + + def test_load_unencrypted_private_ecdsa_sha2_nistp521_key_should_have_fp_sha256 + File.expects(:read).with(@key_file).returns(ecdsa_sha2_nistp521_key.to_pem) + assert_equal ecdsa_sha2_nistp521_key_fingerprint_sha256, Net::SSH::KeyFactory.load_private_key("/key-file").fingerprint('sha256') + end + def test_load_public_ecdsa_sha2_nistp256_key_should_return_key File.expects(:read).with(@key_file).returns(public(ecdsa_sha2_nistp256_key)) assert_equal ecdsa_sha2_nistp256_key.to_blob, Net::SSH::KeyFactory.load_public_key("/key-file").to_blob @@ -127,6 +177,14 @@ class TestKeyFactory < NetSSHTest private + def rsa_key_fingerprint_md5 + '32:00:44:78:bf:91:02:c1:00:25:0f:f9:0a:f9:aa:c7' + end + + def rsa_key_fingerprint_sha256 + 'SHA256:1XFnG2UY/fBunFk1vviHPVV5ruqbL6ZBfGVVOf9mRMk' + end + def rsa_key # 512 bits @rsa_key ||= OpenSSL::PKey::RSA.new("0\202\001;\002\001\000\002A\000\235\236\374N\e@2E\321\3757\003\354c\276N\f\003\3479Ko\005\317\0027\a\255=\345!\306\220\340\211;\027u\331\260\362\2063x\332\301y4\353\v%\032\214v\312\304\212\271GJ\353\2701\031\002\003\001\000\001\002@\022Y\306*\031\306\031\224Cde\231QV3{\306\256U\2477\377\017\000\020\323\363R\332\027\351\034\224OU\020\227H|pUS\n\263+%\304\341\321\273/\271\e\004L\250\273\020&,\t\304By\002!\000\311c\246%a\002\305\277\262R\266\244\250\025V_\351]\264\016\265\341\355\305\223\347Z$8\205#\023\002!\000\310\\\367|\243I\363\350\020\307\246\302\365\ed\212L\273\2158M\223w\a\367 C\t\224A4\243\002!\000\262]+}\327\231\331\002\2331^\312\036\204'g\363\f&\271\020\245\365-\024}\306\374e\202\2459\002 }\231\341\276\3551\277\307{5\\\361\233\353G\024wS\237\fk}\004\302&\205\277\340rb\211\327\002!\000\223\307\025I:\215_\260\370\252\3757\256Y&X\364\354\342\215\350\203E8\227|\f\237M\375D|") @@ -137,18 +195,50 @@ class TestKeyFactory < NetSSHTest @dsa_key ||= OpenSSL::PKey::DSA.new("0\201\367\002\001\000\002A\000\203\316/\037u\272&J\265\003l3\315d\324h\372{\t8\252#\331_\026\006\035\270\266\255\343\353Z\302\276\335\336\306\220\375\202L\244\244J\206>\346\b\315\211\302L\246x\247u\a\376\366\345\302\016#\002\025\000\244\274\302\221Og\275/\302+\356\346\360\024\373wI\2573\361\002@\027\215\270r*\f\213\350C\245\021:\350 \006\\\376\345\022`\210b\262\3643\023XLKS\320\370\002\276\347A\nU\204\276\324\256`=\026\240\330\306J\316V\213\024\e\030\215\355\006\037q\337\356ln\002@\017\257\034\f\260\333'S\271#\237\230E\321\312\027\021\226\331\251Vj\220\305\316\036\v\266+\000\230\270\177B\003?t\a\305]e\344\261\334\023\253\323\251\223M\2175)a(\004\"lI8\312\303\307\a\002\024_\aznW\345\343\203V\326\246ua\203\376\201o\350\302\002") end + def dsa_key_fingerprint_md5 + '8c:3a:e7:ea:34:cd:75:7a:fd:c9:b8:48:ce:4a:2f:97' + end + + def dsa_key_fingerprint_sha256 + 'SHA256:9+7rXHxjuAmxm3UjuZ3T1qTF/UZUrmZQMJC8kNMr7J8' + end + if defined?(OpenSSL::PKey::EC) def ecdsa_sha2_nistp256_key @ecdsa_sha2_nistp256_key ||= OpenSSL::PKey::EC.new("-----BEGIN EC PRIVATE KEY-----\nMHcCAQEEINv6pPVLlkqvT1v5MJlWgaSWGwqupISG4U79bUXQDNCaoAoGCCqGSM49\nAwEHoUQDQgAElqubvi/GkSme+bwtncU1NiE0dWQ0EO07VufUQg8lUJ5+Fi6f96qa\n95T1zwOMQhY1h8PP9rQIZr4S48vN/ZnQLw==\n-----END EC PRIVATE KEY-----\n") end + def ecdsa_sha2_nistp256_key_fingerprint_md5 + 'ed:9e:cd:74:41:a4:37:ae:99:9e:9a:c3:de:04:c9:e1' + end + + def ecdsa_sha2_nistp256_key_fingerprint_sha256 + 'SHA256:yGdFZAf5Mbg5+EPA802cn4lo+uoBEj3RBK4DLG9WK1Y' + end + def ecdsa_sha2_nistp384_key @ecdsa_sha2_nistp384_key ||= OpenSSL::PKey::EC.new("-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDBxwkmydCn4mP4KMhlMpeBvIroQolWKVNoRPXpG7brFgK+Yiikqw8wd\nIZW5OlL4y3mgBwYFK4EEACKhZANiAARkoIR1oABi+aQJbKcmvzeYSKURQOyXM0HU\nR4T68v4hd/lJE4fFQRczj3wAaECe9u3CWI/oDlow4Vr0vab82ZGjIoblxblKQWYl\nyzENgzl226waGg1bLBo8Auilyf1B5yI=\n-----END EC PRIVATE KEY-----\n") end + def ecdsa_sha2_nistp384_key_fingerprint_md5 + '87:5a:c0:a0:23:55:22:05:ca:16:4d:cc:0c:e5:e7:74' + end + + def ecdsa_sha2_nistp384_key_fingerprint_sha256 + 'SHA256:l8ZS7aKnquF8VUXAbHj9wPEEenUjyKIiuUSgOWbWqUw' + end + def ecdsa_sha2_nistp521_key @ecdsa_sha2_nistp521_key ||= OpenSSL::PKey::EC.new("-----BEGIN EC PRIVATE KEY-----\nMIHbAgEBBEHQ2i7kjEGQHQB4pUQW9a2eCLWR2S5Go8U3CDyfbRCrYEp/pTSgI8uu\nMXyR3bf3SjqFQgZ6MZk5lkyrissJuwmvZKAHBgUrgQQAI6GBiQOBhgAEAN14FACK\nbs/KTqw4rxijeozGTVJTh1hNzBl2XaIhM4Fv8o3fE/pvogymyFu53GCng6gC4dmx\n/hycF41iIM29xVKPAeBnRNl6MdFBjuthOmE8eCRezgk1Bak8aBDUrzNT8OQssscw\npvQK4nc6ga/wTDaQGy5kV8tCOHNs2wKH+p2LpWTJ\n-----END EC PRIVATE KEY-----\n") end + + def ecdsa_sha2_nistp521_key_fingerprint_md5 + '6d:5f:10:80:18:4a:69:f3:e3:70:a3:87:90:81:9a:11' + end + + def ecdsa_sha2_nistp521_key_fingerprint_sha256 + 'SHA256:gxtS/gn7iVn6rGgH3EZCInzxN2/hiONcaRSyBJ/Nr4U' + end end def anonymous_private_key |