net-ssh 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG.rdoc +21 -0
  2. data/Manifest +11 -0
  3. data/lib/net/ssh/authentication/key_manager.rb +1 -1
  4. data/lib/net/ssh/authentication/session.rb +12 -4
  5. data/lib/net/ssh/buffer.rb +12 -2
  6. data/lib/net/ssh/key_factory.rb +7 -2
  7. data/lib/net/ssh/known_hosts.rb +12 -2
  8. data/lib/net/ssh/ruby_compat.rb +8 -0
  9. data/lib/net/ssh/transport/algorithms.rb +22 -1
  10. data/lib/net/ssh/transport/cipher_factory.rb +32 -5
  11. data/lib/net/ssh/transport/constants.rb +3 -1
  12. data/lib/net/ssh/transport/ctr.rb +95 -0
  13. data/lib/net/ssh/transport/hmac.rb +8 -5
  14. data/lib/net/ssh/transport/hmac/ripemd160.rb +13 -0
  15. data/lib/net/ssh/transport/kex.rb +11 -0
  16. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +44 -0
  17. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +11 -3
  18. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +93 -0
  19. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +13 -0
  20. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +13 -0
  21. data/lib/net/ssh/transport/openssl.rb +111 -1
  22. data/lib/net/ssh/version.rb +1 -1
  23. data/net-ssh.gemspec +12 -4
  24. data/test/authentication/test_key_manager.rb +48 -1
  25. data/test/test_buffer.rb +92 -2
  26. data/test/test_key_factory.rb +42 -0
  27. data/test/transport/hmac/test_ripemd160.rb +34 -0
  28. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +13 -0
  29. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +161 -0
  30. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +37 -0
  31. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +37 -0
  32. data/test/transport/test_algorithms.rb +41 -19
  33. data/test/transport/test_cipher_factory.rb +255 -27
  34. data/test/transport/test_packet_stream.rb +1009 -0
  35. metadata +13 -4
  36. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  37. data/lib/net/ssh/authentication/agent/socket.rb +0 -170
@@ -0,0 +1,13 @@
1
+ require 'net/ssh/transport/hmac/abstract'
2
+
3
+ module Net::SSH::Transport::HMAC
4
+
5
+ # The RIPEMD-160 HMAC algorithm. This has a mac and key length of 20, and
6
+ # uses the RIPEMD-160 digest algorithm.
7
+ class RIPEMD160 < Abstract
8
+ mac_length 20
9
+ key_length 20
10
+ digest_class OpenSSL::Digest::RIPEMD160
11
+ end
12
+
13
+ end
@@ -1,4 +1,5 @@
1
1
  require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
2
+ require 'net/ssh/transport/kex/diffie_hellman_group14_sha1'
2
3
  require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha1'
3
4
  require 'net/ssh/transport/kex/diffie_hellman_group_exchange_sha256'
4
5
 
@@ -9,9 +10,19 @@ module Net::SSH::Transport
9
10
  MAP = {
10
11
  'diffie-hellman-group-exchange-sha1' => DiffieHellmanGroupExchangeSHA1,
11
12
  'diffie-hellman-group1-sha1' => DiffieHellmanGroup1SHA1,
13
+ 'diffie-hellman-group14-sha1' => DiffieHellmanGroup14SHA1,
12
14
  }
13
15
  if defined?(DiffieHellmanGroupExchangeSHA256)
14
16
  MAP['diffie-hellman-group-exchange-sha256'] = DiffieHellmanGroupExchangeSHA256
15
17
  end
18
+ if defined?(OpenSSL::PKey::EC)
19
+ require 'net/ssh/transport/kex/ecdh_sha2_nistp256'
20
+ require 'net/ssh/transport/kex/ecdh_sha2_nistp384'
21
+ require 'net/ssh/transport/kex/ecdh_sha2_nistp521'
22
+
23
+ MAP['ecdh-sha2-nistp256'] = EcdhSHA2NistP256
24
+ MAP['ecdh-sha2-nistp384'] = EcdhSHA2NistP384
25
+ MAP['ecdh-sha2-nistp521'] = EcdhSHA2NistP521
26
+ end
16
27
  end
17
28
  end
@@ -0,0 +1,44 @@
1
+ require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
2
+
3
+ module Net; module SSH; module Transport; module Kex
4
+
5
+ # A key-exchange service implementing the "diffie-hellman-group14-sha1"
6
+ # key-exchange algorithm. (defined in RFC 4253)
7
+ class DiffieHellmanGroup14SHA1 < DiffieHellmanGroup1SHA1
8
+ include Constants, Loggable
9
+
10
+ # The value of 'P', as a string, in hexadecimal
11
+ P_s = "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" +
12
+ "C4C6628B" "80DC1CD1" "29024E08" "8A67CC74" +
13
+ "020BBEA6" "3B139B22" "514A0879" "8E3404DD" +
14
+ "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" +
15
+ "4FE1356D" "6D51C245" "E485B576" "625E7EC6" +
16
+ "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED" +
17
+ "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" +
18
+ "49286651" "ECE45B3D" "C2007CB8" "A163BF05" +
19
+ "98DA4836" "1C55D39A" "69163FA8" "FD24CF5F" +
20
+ "83655D23" "DCA3AD96" "1C62F356" "208552BB" +
21
+ "9ED52907" "7096966D" "670C354E" "4ABC9804" +
22
+ "F1746C08" "CA18217C" "32905E46" "2E36CE3B" +
23
+ "E39E772C" "180E8603" "9B2783A2" "EC07A28F" +
24
+ "B5C55DF0" "6F4C52C9" "DE2BCBF6" "95581718" +
25
+ "3995497C" "EA956AE5" "15D22618" "98FA0510" +
26
+ "15728E5A" "8AACAA68" "FFFFFFFF" "FFFFFFFF"
27
+
28
+ # The radix in which P_s represents the value of P
29
+ P_r = 16
30
+
31
+ # The group constant
32
+ G = 2
33
+
34
+ private
35
+
36
+ def get_p
37
+ OpenSSL::BN.new(P_s, P_r)
38
+ end
39
+
40
+ def get_g
41
+ G
42
+ end
43
+ end
44
+ end; end; end; end
@@ -40,8 +40,8 @@ module Net; module SSH; module Transport; module Kex
40
40
  # required by this algorithm, which was acquired during earlier
41
41
  # processing.
42
42
  def initialize(algorithms, connection, data)
43
- @p = OpenSSL::BN.new(P_s, P_r)
44
- @g = G
43
+ @p = get_p
44
+ @g = get_g
45
45
 
46
46
  @digester = OpenSSL::Digest::SHA1
47
47
  @algorithms = algorithms
@@ -76,7 +76,15 @@ module Net; module SSH; module Transport; module Kex
76
76
  end
77
77
 
78
78
  private
79
-
79
+
80
+ def get_p
81
+ OpenSSL::BN.new(P_s, P_r)
82
+ end
83
+
84
+ def get_g
85
+ G
86
+ end
87
+
80
88
  # Returns the DH key parameters for the current connection.
81
89
  def get_parameters
82
90
  [p, g]
@@ -0,0 +1,93 @@
1
+ require 'net/ssh/transport/constants'
2
+ require 'net/ssh/transport/kex/diffie_hellman_group1_sha1'
3
+
4
+ module Net; module SSH; module Transport; module Kex
5
+
6
+ # A key-exchange service implementing the "ecdh-sha2-nistp256"
7
+ # key-exchange algorithm. (defined in RFC 5656)
8
+ class EcdhSHA2NistP256 < DiffieHellmanGroup1SHA1
9
+ include Constants, Loggable
10
+
11
+ attr_reader :ecdh
12
+
13
+ def digester
14
+ OpenSSL::Digest::SHA256
15
+ end
16
+
17
+ def curve_name
18
+ OpenSSL::PKey::EC::CurveNameAlias['nistp256']
19
+ end
20
+
21
+ def initialize(algorithms, connection, data)
22
+ @algorithms = algorithms
23
+ @connection = connection
24
+
25
+ @digester = digester
26
+ @data = data.dup
27
+ @ecdh = generate_key
28
+ @logger = @data.delete(:logger)
29
+ end
30
+
31
+ private
32
+
33
+ def get_message_types
34
+ [KEXECDH_INIT, KEXECDH_REPLY]
35
+ end
36
+
37
+ def build_signature_buffer(result)
38
+ response = Net::SSH::Buffer.new
39
+ response.write_string data[:client_version_string],
40
+ data[:server_version_string],
41
+ data[:client_algorithm_packet],
42
+ data[:server_algorithm_packet],
43
+ result[:key_blob],
44
+ ecdh.public_key.to_bn.to_s(2),
45
+ result[:server_ecdh_pubkey]
46
+ response.write_bignum result[:shared_secret]
47
+ response
48
+ end
49
+
50
+ def generate_key #:nodoc:
51
+ OpenSSL::PKey::EC.new(curve_name).generate_key
52
+ end
53
+
54
+ def send_kexinit #:nodoc:
55
+ init, reply = get_message_types
56
+
57
+ # send the KEXECDH_INIT message
58
+ ## byte SSH_MSG_KEX_ECDH_INIT
59
+ ## string Q_C, client's ephemeral public key octet string
60
+ buffer = Net::SSH::Buffer.from(:byte, init, :string, ecdh.public_key.to_bn.to_s(2))
61
+ connection.send_message(buffer)
62
+
63
+ # expect the following KEXECDH_REPLY message
64
+ ## byte SSH_MSG_KEX_ECDH_REPLY
65
+ ## string K_S, server's public host key
66
+ ## string Q_S, server's ephemeral public key octet string
67
+ ## string the signature on the exchange hash
68
+ buffer = connection.next_message
69
+ raise Net::SSH::Exception, "expected REPLY" unless buffer.type == reply
70
+
71
+ result = Hash.new
72
+ result[:key_blob] = buffer.read_string
73
+ result[:server_key] = Net::SSH::Buffer.new(result[:key_blob]).read_key
74
+ result[:server_ecdh_pubkey] = buffer.read_string
75
+
76
+ # compute shared secret from server's public key and client's private key
77
+ pk = OpenSSL::PKey::EC::Point.new(OpenSSL::PKey::EC.new(curve_name).group,
78
+ OpenSSL::BN.new(result[:server_ecdh_pubkey], 2))
79
+ result[:shared_secret] = OpenSSL::BN.new(ecdh.dh_compute_key(pk), 2)
80
+
81
+ sig_buffer = Net::SSH::Buffer.new(buffer.read_string)
82
+ sig_type = sig_buffer.read_string
83
+ if sig_type != algorithms.host_key
84
+ raise Net::SSH::Exception,
85
+ "host key algorithm mismatch for signature " +
86
+ "'#{sig_type}' != '#{algorithms.host_key}'"
87
+ end
88
+ result[:server_sig] = sig_buffer.read_string
89
+
90
+ return result
91
+ end
92
+ end
93
+ end; end; end; end
@@ -0,0 +1,13 @@
1
+ module Net; module SSH; module Transport; module Kex
2
+
3
+ # A key-exchange service implementing the "ecdh-sha2-nistp256"
4
+ # key-exchange algorithm. (defined in RFC 5656)
5
+ class EcdhSHA2NistP384 < EcdhSHA2NistP256
6
+ def digester
7
+ OpenSSL::Digest::SHA384
8
+ end
9
+ def curve_name
10
+ OpenSSL::PKey::EC::CurveNameAlias['nistp384']
11
+ end
12
+ end
13
+ end; end; end; end
@@ -0,0 +1,13 @@
1
+ module Net; module SSH; module Transport; module Kex
2
+
3
+ # A key-exchange service implementing the "ecdh-sha2-nistp521"
4
+ # key-exchange algorithm. (defined in RFC 5656)
5
+ class EcdhSHA2NistP521 < EcdhSHA2NistP256
6
+ def digester
7
+ OpenSSL::Digest::SHA512
8
+ end
9
+ def curve_name
10
+ OpenSSL::PKey::EC::CurveNameAlias['nistp521']
11
+ end
12
+ end
13
+ end; end; end; end
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require 'openssl'
2
3
 
3
4
  module OpenSSL
@@ -122,6 +123,115 @@ module OpenSSL
122
123
  end
123
124
  end
124
125
 
125
- end
126
+ if defined?(OpenSSL::PKey::EC)
127
+ # This class is originally defined in the OpenSSL module. As needed, methods
128
+ # have been added to it by the Net::SSH module for convenience in dealing
129
+ # with SSH functionality.
130
+ class EC
131
+ CurveNameAlias = {
132
+ "nistp256" => "prime256v1",
133
+ "nistp384" => "secp384r1",
134
+ "nistp521" => "secp521r1",
135
+ }
136
+
137
+ CurveNameAliasInv = {
138
+ "prime256v1" => "nistp256",
139
+ "secp384r1" => "nistp384",
140
+ "secp521r1" => "nistp521",
141
+ }
142
+
143
+ def self.read_keyblob(curve_name_in_type, buffer)
144
+ curve_name_in_key = buffer.read_string
145
+ unless curve_name_in_type == curve_name_in_key
146
+ raise Net::SSH::Exception, "curve name mismatched (`#{curve_name_in_key}' with `#{curve_name_in_type}')"
147
+ end
148
+ public_key_oct = buffer.read_string
149
+ begin
150
+ key = OpenSSL::PKey::EC.new(OpenSSL::PKey::EC::CurveNameAlias[curve_name_in_key])
151
+ group = key.group
152
+ point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_oct, 2))
153
+ key.public_key = point
154
+
155
+ return key
156
+ rescue OpenSSL::PKey::ECError => e
157
+ raise NotImplementedError, "unsupported key type `#{type}'"
158
+ end
159
+
160
+ end
161
+
162
+ # Returns the description of this key type used by the
163
+ # SSH2 protocol, like "ecdsa-sha2-nistp256"
164
+ def ssh_type
165
+ "ecdsa-sha2-#{CurveNameAliasInv[self.group.curve_name]}"
166
+ end
126
167
 
168
+ def digester
169
+ if self.group.curve_name =~ /^[a-z]+(\d+)\w*\z/
170
+ curve_size = $1.to_i
171
+ if curve_size <= 256
172
+ OpenSSL::Digest::SHA256.new
173
+ elsif curve_size <= 384
174
+ OpenSSL::Digest::SHA384.new
175
+ else
176
+ OpenSSL::Digest::SHA512.new
177
+ end
178
+ else
179
+ OpenSSL::Digest::SHA256.new
180
+ end
181
+ end
182
+ private :digester
183
+
184
+ # Converts the key to a blob, according to the SSH2 protocol.
185
+ def to_blob
186
+ @blob ||= Net::SSH::Buffer.from(:string, ssh_type,
187
+ :string, CurveNameAliasInv[self.group.curve_name],
188
+ :string, self.public_key.to_bn.to_s(2)).to_s
189
+ @blob
190
+ end
191
+
192
+ # Verifies the given signature matches the given data.
193
+ def ssh_do_verify(sig, data)
194
+ digest = digester.digest(data)
195
+ a1sig = nil
196
+
197
+ begin
198
+ sig_r_len = sig[0,4].unpack("H*")[0].to_i(16)
199
+ sig_l_len = sig[4+sig_r_len,4].unpack("H*")[0].to_i(16)
200
+
201
+ sig_r = sig[4,sig_r_len].unpack("H*")[0]
202
+ sig_s = sig[4+sig_r_len+4,sig_l_len].unpack("H*")[0]
203
+
204
+ a1sig = OpenSSL::ASN1::Sequence([
205
+ OpenSSL::ASN1::Integer(sig_r.to_i(16)),
206
+ OpenSSL::ASN1::Integer(sig_s.to_i(16)),
207
+ ])
208
+ rescue
209
+ end
210
+
211
+ if a1sig == nil
212
+ return false
213
+ else
214
+ dsa_verify_asn1(digest, a1sig.to_der)
215
+ end
216
+ end
217
+
218
+ # Returns the signature for the given data.
219
+ def ssh_do_sign(data)
220
+ digest = digester.digest(data)
221
+ sig = dsa_sign_asn1(digest)
222
+ a1sig = OpenSSL::ASN1.decode( sig )
223
+
224
+ sig_r = a1sig.value[0].value
225
+ sig_s = a1sig.value[1].value
226
+
227
+ return Net::SSH::Buffer.from(:bignum, sig_r, :bignum, sig_s).to_s
228
+ end
229
+ end
230
+ else
231
+ class OpenSSL::PKey::ECError < RuntimeError
232
+ # for compatibility with interpreters
233
+ # without EC support (i.e. JRuby)
234
+ end
235
+ end
236
+ end
127
237
  end
@@ -48,7 +48,7 @@ module Net; module SSH
48
48
  MAJOR = 2
49
49
 
50
50
  # The minor component of this version of the Net::SSH library
51
- MINOR = 4
51
+ MINOR = 5
52
52
 
53
53
  # The tiny component of this version of the Net::SSH library
54
54
  TINY = 0
@@ -1,7 +1,7 @@
1
1
  @spec = Gem::Specification.new do |s|
2
2
  s.name = "net-ssh"
3
3
  s.rubyforge_project = 'net-ssh'
4
- s.version = "2.4.0"
4
+ s.version = "2.5.0"
5
5
  s.summary = "Net::SSH: a pure-Ruby implementation of the SSH2 client protocol."
6
6
  s.description = s.summary + " It allows you to write programs that invoke and interact with processes on remote servers, via SSH2."
7
7
  s.authors = ["Jamis Buck", "Delano Mandelbaum"]
@@ -31,8 +31,6 @@
31
31
  THANKS.rdoc
32
32
  lib/net/ssh.rb
33
33
  lib/net/ssh/authentication/agent.rb
34
- lib/net/ssh/authentication/agent/java_pageant.rb
35
- lib/net/ssh/authentication/agent/socket.rb
36
34
  lib/net/ssh/authentication/constants.rb
37
35
  lib/net/ssh/authentication/key_manager.rb
38
36
  lib/net/ssh/authentication/methods/abstract.rb
@@ -74,11 +72,13 @@
74
72
  lib/net/ssh/transport/algorithms.rb
75
73
  lib/net/ssh/transport/cipher_factory.rb
76
74
  lib/net/ssh/transport/constants.rb
75
+ lib/net/ssh/transport/ctr.rb
77
76
  lib/net/ssh/transport/hmac.rb
78
77
  lib/net/ssh/transport/hmac/abstract.rb
79
78
  lib/net/ssh/transport/hmac/md5.rb
80
79
  lib/net/ssh/transport/hmac/md5_96.rb
81
80
  lib/net/ssh/transport/hmac/none.rb
81
+ lib/net/ssh/transport/hmac/ripemd160.rb
82
82
  lib/net/ssh/transport/hmac/sha1.rb
83
83
  lib/net/ssh/transport/hmac/sha1_96.rb
84
84
  lib/net/ssh/transport/hmac/sha2_256.rb
@@ -89,8 +89,12 @@
89
89
  lib/net/ssh/transport/key_expander.rb
90
90
  lib/net/ssh/transport/kex.rb
91
91
  lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
92
+ lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
92
93
  lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
93
94
  lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb
95
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
96
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb
97
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb
94
98
  lib/net/ssh/transport/openssl.rb
95
99
  lib/net/ssh/transport/packet_stream.rb
96
100
  lib/net/ssh/transport/server_version.rb
@@ -129,6 +133,7 @@
129
133
  test/transport/hmac/test_md5.rb
130
134
  test/transport/hmac/test_md5_96.rb
131
135
  test/transport/hmac/test_none.rb
136
+ test/transport/hmac/test_ripemd160.rb
132
137
  test/transport/hmac/test_sha1.rb
133
138
  test/transport/hmac/test_sha1_96.rb
134
139
  test/transport/hmac/test_sha2_256.rb
@@ -136,8 +141,12 @@
136
141
  test/transport/hmac/test_sha2_512.rb
137
142
  test/transport/hmac/test_sha2_512_96.rb
138
143
  test/transport/kex/test_diffie_hellman_group1_sha1.rb
144
+ test/transport/kex/test_diffie_hellman_group14_sha1.rb
139
145
  test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
140
146
  test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
147
+ test/transport/kex/test_ecdh_sha2_nistp256.rb
148
+ test/transport/kex/test_ecdh_sha2_nistp384.rb
149
+ test/transport/kex/test_ecdh_sha2_nistp521.rb
141
150
  test/transport/test_algorithms.rb
142
151
  test/transport/test_cipher_factory.rb
143
152
  test/transport/test_hmac.rb
@@ -148,5 +157,4 @@
148
157
  test/transport/test_state.rb
149
158
  )
150
159
 
151
-
152
160
  end
@@ -62,6 +62,28 @@ module Authentication
62
62
  assert_equal({:from => :agent}, manager.known_identities[dsa])
63
63
  end
64
64
 
65
+ if defined?(OpenSSL::PKey::EC)
66
+ def test_identities_with_ecdsa_should_load_from_agent
67
+ manager.stubs(:agent).returns(agent_with_ecdsa_keys)
68
+
69
+ identities = []
70
+ manager.each_identity { |identity| identities << identity }
71
+ assert_equal 5, identities.length
72
+
73
+ assert_equal rsa.to_blob, identities[0].to_blob
74
+ assert_equal dsa.to_blob, identities[1].to_blob
75
+ assert_equal ecdsa_sha2_nistp256.to_blob, identities[2].to_blob
76
+ assert_equal ecdsa_sha2_nistp384.to_blob, identities[3].to_blob
77
+ assert_equal ecdsa_sha2_nistp521.to_blob, identities[4].to_blob
78
+
79
+ assert_equal({:from => :agent}, manager.known_identities[rsa])
80
+ assert_equal({:from => :agent}, manager.known_identities[dsa])
81
+ assert_equal({:from => :agent}, manager.known_identities[ecdsa_sha2_nistp256])
82
+ assert_equal({:from => :agent}, manager.known_identities[ecdsa_sha2_nistp384])
83
+ assert_equal({:from => :agent}, manager.known_identities[ecdsa_sha2_nistp521])
84
+ end
85
+ end
86
+
65
87
  def test_only_identities_with_key_files_should_load_from_agent_of_keys_only_set
66
88
  manager(:keys_only => true).stubs(:agent).returns(agent)
67
89
 
@@ -139,7 +161,11 @@ module Authentication
139
161
  Net::SSH::KeyFactory.expects(:load_private_key).with(name, nil, any_of(true, false)).returns(key).at_least_once
140
162
  end
141
163
 
142
- key.stubs(:public_key).returns(key)
164
+ # do not override OpenSSL::PKey::EC#public_key
165
+ # (it will be called in transport/openssl.rb.)
166
+ unless defined?(OpenSSL::PKey::EC) && key.public_key.kind_of?(OpenSSL::PKey::EC::Point)
167
+ key.stubs(:public_key).returns(key)
168
+ end
143
169
  end
144
170
 
145
171
  def stub_file_public_key(name, key)
@@ -158,10 +184,31 @@ module Authentication
158
184
  @dsa ||= OpenSSL::PKey::DSA.new(512)
159
185
  end
160
186
 
187
+ if defined?(OpenSSL::PKey::EC)
188
+ def ecdsa_sha2_nistp256
189
+ @ecdsa_sha2_nistp256 ||= OpenSSL::PKey::EC.new("prime256v1").generate_key
190
+ end
191
+
192
+ def ecdsa_sha2_nistp384
193
+ @ecdsa_sha2_nistp384 ||= OpenSSL::PKey::EC.new("secp384r1").generate_key
194
+ end
195
+
196
+ def ecdsa_sha2_nistp521
197
+ @ecdsa_sha2_nistp521 ||= OpenSSL::PKey::EC.new("secp521r1").generate_key
198
+ end
199
+ end
200
+
161
201
  def agent
162
202
  @agent ||= stub("agent", :identities => [rsa, dsa])
163
203
  end
164
204
 
205
+ def agent_with_ecdsa_keys
206
+ @agent ||= stub("agent", :identities => [rsa, dsa,
207
+ ecdsa_sha2_nistp256,
208
+ ecdsa_sha2_nistp384,
209
+ ecdsa_sha2_nistp521])
210
+ end
211
+
165
212
  def manager(options = {})
166
213
  @manager ||= Net::SSH::Authentication::KeyManager.new(nil, options)
167
214
  end