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
@@ -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