net-ssh 2.4.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -1,4 +1,25 @@
1
1
 
2
+ === 2.5.0 / 24 May 2012
3
+
4
+ * Implement many algorithms [Ryosuke Yamazaki]
5
+ * Key Exchange
6
+ * diffie-hellman-group14-sha1
7
+ * ecdh-sha2-nistp{256,384,521}
8
+ * Host Key
9
+ * ecdsa-sha2-nistp{256,384,521}
10
+ * Authentication
11
+ * ecdsa-sha2-nistp{256,384,521}
12
+ * HMAC
13
+ * hmac-ripemd160
14
+ * Cipher:
15
+ * aes{128,192,256}-ctr
16
+ * camellia{128,192,256}-ctr
17
+ * blowfish-ctr
18
+ * cast128-ctr
19
+ * 3des-ctr
20
+ * arcfour (has problems with weak keys, and should be used with caution)
21
+ * camellia{128,192,256}-cbc
22
+
2
23
  === 2.4.0 / 17 May 2012
3
24
 
4
25
  * Support for JRuby + Pageant + Windows [arturaz]
data/Manifest CHANGED
@@ -47,11 +47,13 @@ lib/net/ssh/test/socket.rb
47
47
  lib/net/ssh/transport/algorithms.rb
48
48
  lib/net/ssh/transport/cipher_factory.rb
49
49
  lib/net/ssh/transport/constants.rb
50
+ lib/net/ssh/transport/ctr.rb
50
51
  lib/net/ssh/transport/hmac.rb
51
52
  lib/net/ssh/transport/hmac/abstract.rb
52
53
  lib/net/ssh/transport/hmac/md5.rb
53
54
  lib/net/ssh/transport/hmac/md5_96.rb
54
55
  lib/net/ssh/transport/hmac/none.rb
56
+ lib/net/ssh/transport/hmac/ripemd160.rb
55
57
  lib/net/ssh/transport/hmac/sha1.rb
56
58
  lib/net/ssh/transport/hmac/sha1_96.rb
57
59
  lib/net/ssh/transport/hmac/sha2_256.rb
@@ -62,8 +64,12 @@ lib/net/ssh/transport/identity_cipher.rb
62
64
  lib/net/ssh/transport/key_expander.rb
63
65
  lib/net/ssh/transport/kex.rb
64
66
  lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb
67
+ lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb
65
68
  lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb
66
69
  lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb
70
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb
71
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb
72
+ lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb
67
73
  lib/net/ssh/transport/openssl.rb
68
74
  lib/net/ssh/transport/packet_stream.rb
69
75
  lib/net/ssh/transport/server_version.rb
@@ -102,6 +108,7 @@ test/test_key_factory.rb
102
108
  test/transport/hmac/test_md5.rb
103
109
  test/transport/hmac/test_md5_96.rb
104
110
  test/transport/hmac/test_none.rb
111
+ test/transport/hmac/test_ripemd160.rb
105
112
  test/transport/hmac/test_sha1.rb
106
113
  test/transport/hmac/test_sha1_96.rb
107
114
  test/transport/hmac/test_sha2_256.rb
@@ -109,8 +116,12 @@ test/transport/hmac/test_sha2_256_96.rb
109
116
  test/transport/hmac/test_sha2_512.rb
110
117
  test/transport/hmac/test_sha2_512_96.rb
111
118
  test/transport/kex/test_diffie_hellman_group1_sha1.rb
119
+ test/transport/kex/test_diffie_hellman_group14_sha1.rb
112
120
  test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb
113
121
  test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb
122
+ test/transport/kex/test_ecdh_sha2_nistp256.rb
123
+ test/transport/kex/test_ecdh_sha2_nistp384.rb
124
+ test/transport/kex/test_ecdh_sha2_nistp521.rb
114
125
  test/transport/test_algorithms.rb
115
126
  test/transport/test_cipher_factory.rb
116
127
  test/transport/test_hmac.rb
@@ -222,7 +222,7 @@ module Net
222
222
  identity
223
223
  end
224
224
 
225
- rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError => e
225
+ rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError => e
226
226
  if ask_passphrase
227
227
  process_identity_loading_error(identity, e)
228
228
  nil
@@ -128,13 +128,21 @@ module Net; module SSH; module Authentication
128
128
 
129
129
  private
130
130
 
131
+ # Returns an array of paths to the key files usually defined
132
+ # by system default.
133
+ def default_keys
134
+ if defined?(OpenSSL::PKey::EC)
135
+ %w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh/id_ecdsa
136
+ ~/.ssh2/id_dsa ~/.ssh2/id_rsa ~/.ssh2/id_ecdsa)
137
+ else
138
+ %w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
139
+ end
140
+ end
141
+
131
142
  # Returns an array of paths to the key files that should be used when
132
143
  # attempting any key-based authentication mechanism.
133
144
  def keys
134
- Array(
135
- options[:keys] ||
136
- %w(~/.ssh/id_dsa ~/.ssh/id_rsa ~/.ssh2/id_dsa ~/.ssh2/id_rsa)
137
- )
145
+ Array(options[:keys] || default_keys)
138
146
  end
139
147
 
140
148
  # Returns an array of the key data that should be used when
@@ -240,7 +240,7 @@ module Net; module SSH
240
240
  end
241
241
 
242
242
  # Read a keyblob of the given type from the buffer, and return it as
243
- # a key. Only RSA and DSA keys are supported.
243
+ # a key. Only RSA, DSA, and ECDSA keys are supported.
244
244
  def read_keyblob(type)
245
245
  case type
246
246
  when "ssh-dss"
@@ -255,6 +255,16 @@ module Net; module SSH
255
255
  key.e = read_bignum
256
256
  key.n = read_bignum
257
257
 
258
+ when /^ecdsa\-sha2\-(\w*)$/
259
+ unless defined?(OpenSSL::PKey::EC)
260
+ raise NotImplementedError, "unsupported key type `#{type}'"
261
+ else
262
+ begin
263
+ key = OpenSSL::PKey::EC.read_keyblob($1, self)
264
+ rescue OpenSSL::PKey::ECError => e
265
+ raise NotImplementedError, "unsupported key type `#{type}'"
266
+ end
267
+ end
258
268
  else
259
269
  raise NotImplementedError, "unsupported key type `#{type}'"
260
270
  end
@@ -337,4 +347,4 @@ module Net; module SSH
337
347
  self
338
348
  end
339
349
  end
340
- end; end;
350
+ end; end;
@@ -17,8 +17,11 @@ module Net; module SSH
17
17
  MAP = {
18
18
  "dh" => OpenSSL::PKey::DH,
19
19
  "rsa" => OpenSSL::PKey::RSA,
20
- "dsa" => OpenSSL::PKey::DSA
20
+ "dsa" => OpenSSL::PKey::DSA,
21
21
  }
22
+ if defined?(OpenSSL::PKey::EC)
23
+ MAP["ecdsa"] = OpenSSL::PKey::EC
24
+ end
22
25
 
23
26
  class <<self
24
27
  include Prompt
@@ -49,6 +52,8 @@ module Net; module SSH
49
52
  key_type = OpenSSL::PKey::DSA
50
53
  elsif data.match(/-----BEGIN RSA PRIVATE KEY-----/)
51
54
  key_type = OpenSSL::PKey::RSA
55
+ elsif data.match(/-----BEGIN EC PRIVATE KEY-----/) && defined?(OpenSSL::PKey::EC)
56
+ key_type = OpenSSL::PKey::EC
52
57
  elsif data.match(/-----BEGIN (.*) PRIVATE KEY-----/)
53
58
  raise OpenSSL::PKey::PKeyError, "not a supported key type '#{$1}'"
54
59
  else
@@ -60,7 +65,7 @@ module Net; module SSH
60
65
 
61
66
  begin
62
67
  return key_type.new(data, passphrase || 'invalid')
63
- rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError => e
68
+ rescue OpenSSL::PKey::RSAError, OpenSSL::PKey::DSAError, OpenSSL::PKey::ECError => e
64
69
  if encrypted_key && ask_passphrase
65
70
  tries += 1
66
71
  if tries <= 3
@@ -11,6 +11,16 @@ module Net; module SSH
11
11
  # by consumers of the library.
12
12
  class KnownHosts
13
13
  class <<self
14
+
15
+ if defined?(OpenSSL::PKey::EC)
16
+ SUPPORTED_TYPE = %w(ssh-rsa ssh-dss
17
+ ecdsa-sha2-nistp256
18
+ ecdsa-sha2-nistp384
19
+ ecdsa-sha2-nistp521)
20
+ else
21
+ SUPPORTED_TYPE = %w(ssh-rsa ssh-dss)
22
+ end
23
+
14
24
  # Searches all known host files (see KnownHosts.hostfiles) for all keys
15
25
  # of the given host. Returns an array of keys found.
16
26
  def search_for(host, options={})
@@ -104,7 +114,7 @@ module Net; module SSH
104
114
  scanner.skip(/\s*/)
105
115
  type = scanner.scan(/\S+/)
106
116
 
107
- next unless %w(ssh-rsa ssh-dss).include?(type)
117
+ next unless SUPPORTED_TYPE.include?(type)
108
118
 
109
119
  scanner.skip(/\s*/)
110
120
  blob = scanner.rest.unpack("m*").first
@@ -126,4 +136,4 @@ module Net; module SSH
126
136
  end
127
137
 
128
138
  end
129
- end; end
139
+ end; end
@@ -5,6 +5,14 @@ class String
5
5
  def getbyte(index)
6
6
  self[index]
7
7
  end
8
+ def setbyte(index, c)
9
+ self[index] = c
10
+ end
11
+ end
12
+ if RUBY_VERSION < "1.8.7"
13
+ def bytesize
14
+ self.size
15
+ end
8
16
  end
9
17
  end
10
18
 
@@ -25,16 +25,37 @@ module Net; module SSH; module Transport
25
25
  :host_key => %w(ssh-rsa ssh-dss),
26
26
  :kex => %w(diffie-hellman-group-exchange-sha1
27
27
  diffie-hellman-group1-sha1
28
+ diffie-hellman-group14-sha1
28
29
  diffie-hellman-group-exchange-sha256),
29
30
  :encryption => %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc
30
31
  aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se
31
- idea-cbc none arcfour128 arcfour256),
32
+ idea-cbc none arcfour128 arcfour256 arcfour
33
+ aes128-ctr aes192-ctr aes256-ctr
34
+ camellia128-cbc camellia192-cbc camellia256-cbc
35
+ camellia128-cbc@openssh.org
36
+ camellia192-cbc@openssh.org
37
+ camellia256-cbc@openssh.org
38
+ camellia128-ctr camellia192-ctr camellia256-ctr
39
+ camellia128-ctr@openssh.org
40
+ camellia192-ctr@openssh.org
41
+ camellia256-ctr@openssh.org
42
+ cast128-ctr blowfish-ctr 3des-ctr
43
+ ),
32
44
  :hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96
45
+ hmac-ripemd160 hmac-ripemd160@openssh.com
33
46
  hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96
34
47
  hmac-sha2-512-96 none),
35
48
  :compression => %w(none zlib@openssh.com zlib),
36
49
  :language => %w()
37
50
  }
51
+ if defined?(OpenSSL::PKey::EC)
52
+ ALGORITHMS[:host_key] += %w(ecdsa-sha2-nistp256
53
+ ecdsa-sha2-nistp384
54
+ ecdsa-sha2-nistp521)
55
+ ALGORITHMS[:kex] += %w(ecdh-sha2-nistp256
56
+ ecdh-sha2-nistp384
57
+ ecdh-sha2-nistp521)
58
+ end
38
59
 
39
60
  # The underlying transport layer session that supports this object
40
61
  attr_reader :session
@@ -1,4 +1,5 @@
1
1
  require 'openssl'
2
+ require 'net/ssh/transport/ctr.rb'
2
3
  require 'net/ssh/transport/key_expander'
3
4
  require 'net/ssh/transport/identity_cipher'
4
5
 
@@ -19,9 +20,30 @@ module Net; module SSH; module Transport
19
20
  "arcfour128" => "rc4",
20
21
  "arcfour256" => "rc4",
21
22
  "arcfour512" => "rc4",
22
- "none" => "none"
23
+ "arcfour" => "rc4",
24
+ "camellia128-cbc" => "camellia-128-cbc",
25
+ "camellia192-cbc" => "camellia-192-cbc",
26
+ "camellia256-cbc" => "camellia-256-cbc",
27
+ "camellia128-cbc@openssh.org" => "camellia-128-cbc",
28
+ "camellia192-cbc@openssh.org" => "camellia-192-cbc",
29
+ "camellia256-cbc@openssh.org" => "camellia-256-cbc",
30
+
31
+ "3des-ctr" => "des-ede3",
32
+ "blowfish-ctr" => "bf-ecb",
33
+ "aes256-ctr" => "aes-256-ecb",
34
+ "aes192-ctr" => "aes-192-ecb",
35
+ "aes128-ctr" => "aes-128-ecb",
36
+ "cast128-ctr" => "cast5-ecb",
37
+ "camellia128-ctr" => "camellia-128-ecb",
38
+ "camellia192-ctr" => "camellia-192-ecb",
39
+ "camellia256-ctr" => "camellia-256-ecb",
40
+ "camellia128-ctr@openssh.org" => "camellia-128-ecb",
41
+ "camellia192-ctr@openssh.org" => "camellia-192-ecb",
42
+ "camellia256-ctr@openssh.org" => "camellia-256-ecb",
43
+
44
+ "none" => "none",
23
45
  }
24
-
46
+
25
47
  # Ruby's OpenSSL bindings always return a key length of 16 for RC4 ciphers
26
48
  # resulting in the error: OpenSSL::CipherError: key length too short.
27
49
  # The following ciphers will override this key length.
@@ -29,7 +51,8 @@ module Net; module SSH; module Transport
29
51
  "arcfour256" => 32,
30
52
  "arcfour512" => 64
31
53
  }
32
-
54
+
55
+
33
56
  # Returns true if the underlying OpenSSL library supports the given cipher,
34
57
  # and false otherwise.
35
58
  def self.supported?(name)
@@ -46,16 +69,20 @@ module Net; module SSH; module Transport
46
69
  def self.get(name, options={})
47
70
  ossl_name = SSH_TO_OSSL[name] or raise NotImplementedError, "unimplemented cipher `#{name}'"
48
71
  return IdentityCipher if ossl_name == "none"
49
-
50
72
  cipher = OpenSSL::Cipher::Cipher.new(ossl_name)
73
+
51
74
  cipher.send(options[:encrypt] ? :encrypt : :decrypt)
52
75
 
53
76
  cipher.padding = 0
77
+
78
+ cipher.extend(Net::SSH::Transport::CTR) if (name =~ /-ctr(@openssh.org)?$/)
79
+
54
80
  cipher.iv = Net::SSH::Transport::KeyExpander.expand_key(cipher.iv_len, options[:iv], options) if ossl_name != "rc4"
81
+
55
82
  key_len = KEY_LEN_OVERRIDE[name] || cipher.key_len
56
83
  cipher.key_len = key_len
57
84
  cipher.key = Net::SSH::Transport::KeyExpander.expand_key(key_len, options[:key], options)
58
- cipher.update(" " * 1536) if ossl_name == "rc4"
85
+ cipher.update(" " * 1536) if (ossl_name == "rc4" && name != "arcfour")
59
86
 
60
87
  return cipher
61
88
  end
@@ -26,5 +26,7 @@ module Net; module SSH; module Transport
26
26
  KEXDH_INIT = 30
27
27
  KEXDH_REPLY = 31
28
28
 
29
+ KEXECDH_INIT = 30
30
+ KEXECDH_REPLY = 31
29
31
  end
30
- end; end; end
32
+ end; end; end
@@ -0,0 +1,95 @@
1
+ require 'openssl'
2
+
3
+ module Net::SSH::Transport
4
+
5
+ # Pure-Ruby implementation of Stateful Decryption Counter(SDCTR) Mode
6
+ # for Block Ciphers. See RFC4344 for detail.
7
+ module CTR
8
+ def self.extended(orig)
9
+ orig.instance_eval {
10
+ @remaining = ""
11
+ @counter = nil
12
+ @counter_len = orig.block_size
13
+ orig.encrypt
14
+ orig.padding = 0
15
+ }
16
+
17
+ class <<orig
18
+ alias :_update :update
19
+ private :_update
20
+ undef :update
21
+
22
+ def iv
23
+ @counter
24
+ end
25
+
26
+ def iv_len
27
+ block_size
28
+ end
29
+
30
+ def iv=(iv_s)
31
+ @counter = iv_s if @counter.nil?
32
+ end
33
+
34
+ def encrypt
35
+ # DO NOTHING (always set to "encrypt")
36
+ end
37
+
38
+ def decrypt
39
+ # DO NOTHING (always set to "encrypt")
40
+ end
41
+
42
+ def padding=(pad)
43
+ # DO NOTHING (always 0)
44
+ end
45
+
46
+ def reset
47
+ @remaining = ""
48
+ end
49
+
50
+ def update(data)
51
+ @remaining += data
52
+
53
+ encrypted = ""
54
+
55
+ while @remaining.bytesize >= block_size
56
+ encrypted += xor!(@remaining.slice!(0, block_size),
57
+ _update(@counter))
58
+ increment_counter!
59
+ end
60
+
61
+ encrypted
62
+ end
63
+
64
+ def final
65
+ unless @remaining.empty?
66
+ s = xor!(@remaining, _update(@counter))
67
+ else
68
+ s = ""
69
+ end
70
+
71
+ @remaining = ""
72
+
73
+ s
74
+ end
75
+
76
+ private
77
+
78
+ def xor!(s1, s2)
79
+ s = []
80
+ s1.unpack('Q*').zip(s2.unpack('Q*')) {|a,b| s.push(a^b) }
81
+ s.pack('Q*')
82
+ end
83
+
84
+ def increment_counter!
85
+ c = @counter_len
86
+ while ((c -= 1) > 0)
87
+ if @counter.setbyte(c, (@counter.getbyte(c) + 1) & 0xff) != 0
88
+ break
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -7,6 +7,7 @@ require 'net/ssh/transport/hmac/sha2_256'
7
7
  require 'net/ssh/transport/hmac/sha2_256_96'
8
8
  require 'net/ssh/transport/hmac/sha2_512'
9
9
  require 'net/ssh/transport/hmac/sha2_512_96'
10
+ require 'net/ssh/transport/hmac/ripemd160'
10
11
  require 'net/ssh/transport/hmac/none'
11
12
 
12
13
  # Implements a simple factory interface for fetching hmac implementations, or
@@ -14,11 +15,13 @@ require 'net/ssh/transport/hmac/none'
14
15
  module Net::SSH::Transport::HMAC
15
16
  # The mapping of SSH hmac algorithms to their implementations
16
17
  MAP = {
17
- 'hmac-md5' => MD5,
18
- 'hmac-md5-96' => MD5_96,
19
- 'hmac-sha1' => SHA1,
20
- 'hmac-sha1-96' => SHA1_96,
21
- 'none' => None
18
+ 'hmac-md5' => MD5,
19
+ 'hmac-md5-96' => MD5_96,
20
+ 'hmac-sha1' => SHA1,
21
+ 'hmac-sha1-96' => SHA1_96,
22
+ 'hmac-ripemd160' => RIPEMD160,
23
+ 'hmac-ripemd160@openssh.com' => RIPEMD160,
24
+ 'none' => None
22
25
  }
23
26
 
24
27
  # add mapping to sha2 hmac algorithms if they're available