net-ssh 5.0.2 → 7.0.1

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 (122) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/config/rubocop_linter_action.yml +4 -0
  5. data/.github/workflows/ci-with-docker.yml +44 -0
  6. data/.github/workflows/ci.yml +87 -0
  7. data/.github/workflows/rubocop.yml +13 -0
  8. data/.gitignore +3 -0
  9. data/.rubocop.yml +19 -2
  10. data/.rubocop_todo.yml +623 -511
  11. data/CHANGES.txt +76 -0
  12. data/Dockerfile +27 -0
  13. data/Dockerfile.openssl3 +17 -0
  14. data/Gemfile +2 -0
  15. data/Gemfile.noed25519 +2 -0
  16. data/Manifest +0 -1
  17. data/README.md +293 -0
  18. data/Rakefile +6 -2
  19. data/appveyor.yml +4 -2
  20. data/docker-compose.yml +23 -0
  21. data/lib/net/ssh/authentication/agent.rb +36 -14
  22. data/lib/net/ssh/authentication/certificate.rb +19 -7
  23. data/lib/net/ssh/authentication/constants.rb +0 -1
  24. data/lib/net/ssh/authentication/ed25519.rb +83 -50
  25. data/lib/net/ssh/authentication/ed25519_loader.rb +5 -8
  26. data/lib/net/ssh/authentication/key_manager.rb +74 -33
  27. data/lib/net/ssh/authentication/methods/abstract.rb +12 -3
  28. data/lib/net/ssh/authentication/methods/hostbased.rb +3 -5
  29. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +5 -3
  30. data/lib/net/ssh/authentication/methods/none.rb +6 -9
  31. data/lib/net/ssh/authentication/methods/password.rb +2 -3
  32. data/lib/net/ssh/authentication/methods/publickey.rb +58 -16
  33. data/lib/net/ssh/authentication/pageant.rb +97 -97
  34. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +2 -3
  35. data/lib/net/ssh/authentication/session.rb +27 -23
  36. data/lib/net/ssh/buffer.rb +91 -40
  37. data/lib/net/ssh/buffered_io.rb +24 -26
  38. data/lib/net/ssh/config.rb +99 -53
  39. data/lib/net/ssh/connection/channel.rb +101 -87
  40. data/lib/net/ssh/connection/constants.rb +0 -4
  41. data/lib/net/ssh/connection/event_loop.rb +30 -25
  42. data/lib/net/ssh/connection/keepalive.rb +12 -12
  43. data/lib/net/ssh/connection/session.rb +115 -111
  44. data/lib/net/ssh/connection/term.rb +56 -58
  45. data/lib/net/ssh/errors.rb +12 -12
  46. data/lib/net/ssh/key_factory.rb +108 -22
  47. data/lib/net/ssh/known_hosts.rb +120 -36
  48. data/lib/net/ssh/loggable.rb +10 -11
  49. data/lib/net/ssh/packet.rb +1 -1
  50. data/lib/net/ssh/prompt.rb +9 -11
  51. data/lib/net/ssh/proxy/command.rb +1 -2
  52. data/lib/net/ssh/proxy/errors.rb +2 -4
  53. data/lib/net/ssh/proxy/http.rb +18 -20
  54. data/lib/net/ssh/proxy/https.rb +8 -10
  55. data/lib/net/ssh/proxy/jump.rb +8 -10
  56. data/lib/net/ssh/proxy/socks4.rb +2 -4
  57. data/lib/net/ssh/proxy/socks5.rb +3 -6
  58. data/lib/net/ssh/service/forward.rb +9 -8
  59. data/lib/net/ssh/test/channel.rb +24 -26
  60. data/lib/net/ssh/test/extensions.rb +37 -35
  61. data/lib/net/ssh/test/kex.rb +6 -8
  62. data/lib/net/ssh/test/local_packet.rb +0 -2
  63. data/lib/net/ssh/test/packet.rb +3 -3
  64. data/lib/net/ssh/test/remote_packet.rb +6 -8
  65. data/lib/net/ssh/test/script.rb +25 -27
  66. data/lib/net/ssh/test/socket.rb +12 -15
  67. data/lib/net/ssh/test.rb +12 -12
  68. data/lib/net/ssh/transport/algorithms.rb +177 -118
  69. data/lib/net/ssh/transport/cipher_factory.rb +34 -50
  70. data/lib/net/ssh/transport/constants.rb +13 -9
  71. data/lib/net/ssh/transport/ctr.rb +8 -14
  72. data/lib/net/ssh/transport/hmac/abstract.rb +20 -5
  73. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  74. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  75. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  76. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  77. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  78. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  79. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  80. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  81. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  82. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  83. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  84. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  85. data/lib/net/ssh/transport/hmac.rb +13 -11
  86. data/lib/net/ssh/transport/identity_cipher.rb +11 -13
  87. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  88. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  89. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  90. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +5 -19
  92. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  93. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +30 -139
  94. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +1 -8
  95. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  96. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +20 -81
  97. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +5 -4
  98. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +5 -4
  99. data/lib/net/ssh/transport/kex.rb +15 -10
  100. data/lib/net/ssh/transport/key_expander.rb +7 -8
  101. data/lib/net/ssh/transport/openssl.rb +149 -111
  102. data/lib/net/ssh/transport/packet_stream.rb +53 -22
  103. data/lib/net/ssh/transport/server_version.rb +17 -16
  104. data/lib/net/ssh/transport/session.rb +35 -11
  105. data/lib/net/ssh/transport/state.rb +44 -44
  106. data/lib/net/ssh/verifiers/accept_new.rb +7 -2
  107. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +1 -2
  108. data/lib/net/ssh/verifiers/always.rb +10 -4
  109. data/lib/net/ssh/verifiers/never.rb +4 -2
  110. data/lib/net/ssh/version.rb +2 -2
  111. data/lib/net/ssh.rb +17 -9
  112. data/net-ssh-public_cert.pem +18 -19
  113. data/net-ssh.gemspec +9 -7
  114. data/support/ssh_tunnel_bug.rb +3 -3
  115. data.tar.gz.sig +0 -0
  116. metadata +65 -41
  117. metadata.gz.sig +0 -0
  118. data/.travis.yml +0 -52
  119. data/Gemfile.noed25519.lock +0 -41
  120. data/README.rdoc +0 -169
  121. data/lib/net/ssh/ruby_compat.rb +0 -13
  122. data/support/arcfour_check.rb +0 -20
@@ -1,7 +1,6 @@
1
1
  require 'net/ssh/buffered_io'
2
2
  require 'net/ssh/errors'
3
3
  require 'net/ssh/packet'
4
- require 'net/ssh/ruby_compat'
5
4
  require 'net/ssh/transport/cipher_factory'
6
5
  require 'net/ssh/transport/hmac'
7
6
  require 'net/ssh/transport/state'
@@ -9,7 +8,6 @@ require 'net/ssh/transport/state'
9
8
  module Net
10
9
  module SSH
11
10
  module Transport
12
-
13
11
  # A module that builds additional functionality onto the Net::SSH::BufferedIo
14
12
  # module. It adds SSH encryption, compression, and packet validation, as
15
13
  # per the SSH2 protocol. It also adds an abstraction for polling packets,
@@ -81,8 +79,8 @@ module Net
81
79
  # default), then this will return immediately, whether a packet is
82
80
  # available or not, and will return nil if there is no packet ready to be
83
81
  # returned. If the mode parameter is :block, then this method will block
84
- # until a packet is available.
85
- def next_packet(mode=:nonblock)
82
+ # until a packet is available or timeout seconds have passed.
83
+ def next_packet(mode = :nonblock, timeout = nil)
86
84
  case mode
87
85
  when :nonblock then
88
86
  packet = poll_next_packet
@@ -105,11 +103,8 @@ module Net
105
103
  packet = poll_next_packet
106
104
  return packet if packet
107
105
 
108
- loop do
109
- result = IO.select([self]) or next
110
- break if result.first.any?
111
- end
112
-
106
+ result = IO.select([self], nil, nil, timeout)
107
+ raise Net::SSH::ConnectionTimeout, "timeout waiting for next packet" unless result
113
108
  raise Net::SSH::Disconnect, "connection closed by remote host" if fill <= 0
114
109
  end
115
110
 
@@ -133,7 +128,7 @@ module Net
133
128
  payload = client.compress(payload)
134
129
 
135
130
  # the length of the packet, minus the padding
136
- actual_length = 4 + payload.bytesize + 1
131
+ actual_length = (client.hmac.etm ? 0 : 4) + payload.bytesize + 1
137
132
 
138
133
  # compute the padding length
139
134
  padding_length = client.block_size - (actual_length % client.block_size)
@@ -149,11 +144,32 @@ module Net
149
144
 
150
145
  padding = Array.new(padding_length) { rand(256) }.pack("C*")
151
146
 
152
- unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
153
- mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))
147
+ if client.hmac.etm
148
+ debug { "using encrypt-then-mac" }
149
+
150
+ # Encrypt padding_length, payload, and padding. Take MAC
151
+ # from the unencrypted packet_lenght and the encrypted
152
+ # data.
153
+ length_data = [packet_length].pack("N")
154
+
155
+ unencrypted_data = [padding_length, payload, padding].pack("CA*A*")
156
+
157
+ encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
158
+
159
+ mac_data = length_data + encrypted_data
160
+
161
+ mac = client.hmac.digest([client.sequence_number, mac_data].pack("NA*"))
162
+
163
+ message = mac_data + mac
164
+ else
165
+ unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
166
+
167
+ mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))
154
168
 
155
- encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
156
- message = encrypted_data + mac
169
+ encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
170
+
171
+ message = encrypted_data + mac
172
+ end
157
173
 
158
174
  debug { "queueing packet nr #{client.sequence_number} type #{payload.getbyte(0)} len #{packet_length}" }
159
175
  enqueue(message)
@@ -198,18 +214,28 @@ module Net
198
214
  # read, post-processed according to the cipher, hmac, and compression
199
215
  # algorithms specified in the server state object, and returned as a
200
216
  # new Packet object.
217
+ # rubocop:disable Metrics/AbcSize
201
218
  def poll_next_packet
219
+ aad_length = server.hmac.etm ? 4 : 0
220
+
202
221
  if @packet.nil?
203
222
  minimum = server.block_size < 4 ? 4 : server.block_size
204
- return nil if available < minimum
205
- data = read_available(minimum)
223
+ return nil if available < minimum + aad_length
224
+
225
+ data = read_available(minimum + aad_length)
206
226
 
207
227
  # decipher it
208
- @packet = Net::SSH::Buffer.new(server.update_cipher(data))
209
- @packet_length = @packet.read_long
228
+ if server.hmac.etm
229
+ @packet_length = data.unpack("N").first
230
+ @mac_data = data
231
+ @packet = Net::SSH::Buffer.new(server.update_cipher(data[aad_length..-1]))
232
+ else
233
+ @packet = Net::SSH::Buffer.new(server.update_cipher(data))
234
+ @packet_length = @packet.read_long
235
+ end
210
236
  end
211
237
 
212
- need = @packet_length + 4 - server.block_size
238
+ need = @packet_length + 4 - aad_length - server.block_size
213
239
  raise Net::SSH::Exception, "padding error, need #{need} block #{server.block_size}" if need % server.block_size != 0
214
240
 
215
241
  return nil if available < need + server.hmac.mac_length
@@ -217,6 +243,7 @@ module Net
217
243
  if need > 0
218
244
  # read the remainder of the packet and decrypt it.
219
245
  data = read_available(need)
246
+ @mac_data += data if server.hmac.etm
220
247
  @packet.append(server.update_cipher(data))
221
248
  end
222
249
 
@@ -229,8 +256,12 @@ module Net
229
256
 
230
257
  payload = @packet.read(@packet_length - padding_length - 1)
231
258
 
232
- my_computed_hmac = server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
233
- raise Net::SSH::Exception, "corrupted hmac detected" if real_hmac != my_computed_hmac
259
+ my_computed_hmac = if server.hmac.etm
260
+ server.hmac.digest([server.sequence_number, @mac_data].pack("NA*"))
261
+ else
262
+ server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
263
+ end
264
+ raise Net::SSH::Exception, "corrupted hmac detected #{server.hmac.class}" if real_hmac != my_computed_hmac
234
265
 
235
266
  # try to decompress the payload, in case compression is active
236
267
  payload = server.decompress(payload)
@@ -243,7 +274,7 @@ module Net
243
274
  return Packet.new(payload)
244
275
  end
245
276
  end
246
-
277
+ # rubocop:enable Metrics/AbcSize
247
278
  end
248
279
  end
249
280
  end
@@ -2,10 +2,9 @@ require 'net/ssh/errors'
2
2
  require 'net/ssh/loggable'
3
3
  require 'net/ssh/version'
4
4
 
5
- module Net
6
- module SSH
5
+ module Net
6
+ module SSH
7
7
  module Transport
8
-
9
8
  # Negotiates the SSH protocol version and trades information about server
10
9
  # and client. This is never used directly--it is always called by the
11
10
  # transport layer as part of the initialization process of the transport
@@ -15,40 +14,41 @@ module Net
15
14
  # the authoritative reference for any queries regarding the version in effect.
16
15
  class ServerVersion
17
16
  include Loggable
18
-
17
+
19
18
  # The SSH version string as reported by Net::SSH
20
19
  PROTO_VERSION = "SSH-2.0-Ruby/Net::SSH_#{Net::SSH::Version::CURRENT} #{RUBY_PLATFORM}"
21
-
20
+
22
21
  # Any header text sent by the server prior to sending the version.
23
22
  attr_reader :header
24
-
23
+
25
24
  # The version string reported by the server.
26
25
  attr_reader :version
27
-
26
+
28
27
  # Instantiates a new ServerVersion and immediately (and synchronously)
29
28
  # negotiates the SSH protocol in effect, using the given socket.
30
29
  def initialize(socket, logger, timeout = nil)
31
- @header = ""
30
+ @header = String.new
32
31
  @version = nil
33
32
  @logger = logger
34
33
  negotiate!(socket, timeout)
35
34
  end
36
-
35
+
37
36
  private
38
-
37
+
39
38
  # Negotiates the SSH protocol to use, via the given socket. If the server
40
39
  # reports an incompatible SSH version (e.g., SSH1), this will raise an
41
40
  # exception.
42
41
  def negotiate!(socket, timeout)
43
42
  info { "negotiating protocol version" }
44
-
43
+
45
44
  debug { "local is `#{PROTO_VERSION}'" }
46
45
  socket.write "#{PROTO_VERSION}\r\n"
47
46
  socket.flush
48
-
47
+
49
48
  raise Net::SSH::ConnectionTimeout, "timeout during server version negotiating" if timeout && !IO.select([socket], nil, nil, timeout)
49
+
50
50
  loop do
51
- @version = ""
51
+ @version = String.new
52
52
  loop do
53
53
  begin
54
54
  b = socket.readpartial(1)
@@ -60,14 +60,15 @@ module Net
60
60
  break if b == "\n"
61
61
  end
62
62
  break if @version.match(/^SSH-/)
63
+
63
64
  @header << @version
64
65
  end
65
-
66
+
66
67
  @version.chomp!
67
68
  debug { "remote is `#{@version}'" }
68
-
69
+
69
70
  raise Net::SSH::Exception, "incompatible SSH version `#{@version}'" unless @version.match(/^SSH-(1\.99|2\.0)-/)
70
-
71
+
71
72
  raise Net::SSH::ConnectionTimeout, "timeout during client version negotiating" if timeout && !IO.select(nil, [socket], nil, timeout)
72
73
  end
73
74
  end
@@ -15,7 +15,6 @@ require 'net/ssh/verifiers/never'
15
15
  module Net
16
16
  module SSH
17
17
  module Transport
18
-
19
18
  # The transport layer represents the lowest level of the SSH protocol, and
20
19
  # implements basic message exchanging and protocol initialization. It will
21
20
  # never be instantiated directly (unless you really know what you're about),
@@ -56,7 +55,7 @@ module Net
56
55
  # Instantiates a new transport layer abstraction. This will block until
57
56
  # the initial key exchange completes, leaving you with a ready-to-use
58
57
  # transport session.
59
- def initialize(host, options={})
58
+ def initialize(host, options = {})
60
59
  self.logger = options[:logger]
61
60
 
62
61
  @host = host
@@ -160,6 +159,7 @@ module Net
160
159
  # one is performed, causing this method to block until it completes.
161
160
  def rekey_as_needed
162
161
  return if algorithms.pending?
162
+
163
163
  socket.if_needs_rekey? { rekey! }
164
164
  end
165
165
 
@@ -186,11 +186,11 @@ module Net
186
186
  # received, it will be enqueued and otherwise ignored. When a key-exchange
187
187
  # is not in process, and consume_queue is true, packets will be first
188
188
  # read from the queue before the socket is queried.
189
- def poll_message(mode=:nonblock, consume_queue=true)
189
+ def poll_message(mode = :nonblock, consume_queue = true)
190
190
  loop do
191
191
  return @queue.shift if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
192
192
 
193
- packet = socket.next_packet(mode)
193
+ packet = socket.next_packet(mode, options[:timeout])
194
194
  return nil if packet.nil?
195
195
 
196
196
  case packet.type
@@ -211,6 +211,7 @@ module Net
211
211
 
212
212
  else
213
213
  return packet if algorithms.allow?(packet)
214
+
214
215
  push(packet)
215
216
  end
216
217
  end
@@ -222,6 +223,7 @@ module Net
222
223
  def wait
223
224
  loop do
224
225
  break if block_given? && yield
226
+
225
227
  message = poll_message(:nonblock, false)
226
228
  push(message) if message
227
229
  break if !block_given?
@@ -250,30 +252,47 @@ module Net
250
252
  # Configure's the packet stream's client state with the given set of
251
253
  # options. This is typically used to define the cipher, compression, and
252
254
  # hmac algorithms to use when sending packets to the server.
253
- def configure_client(options={})
255
+ def configure_client(options = {})
254
256
  socket.client.set(options)
255
257
  end
256
258
 
257
259
  # Configure's the packet stream's server state with the given set of
258
260
  # options. This is typically used to define the cipher, compression, and
259
261
  # hmac algorithms to use when reading packets from the server.
260
- def configure_server(options={})
262
+ def configure_server(options = {})
261
263
  socket.server.set(options)
262
264
  end
263
265
 
264
266
  # Sets a new hint for the packet stream, which the packet stream may use
265
267
  # to change its behavior. (See PacketStream#hints).
266
- def hint(which, value=true)
268
+ def hint(which, value = true)
267
269
  socket.hints[which] = value
268
270
  end
269
271
 
270
272
  public
271
273
 
272
274
  # this method is primarily for use in tests
273
- attr_reader :queue #:nodoc:
275
+ attr_reader :queue # :nodoc:
274
276
 
275
277
  private
276
278
 
279
+ # Compatibility verifier which allows users to keep using
280
+ # custom verifier code without adding new :verify_signature
281
+ # method.
282
+ class CompatibleVerifier
283
+ def initialize(verifier)
284
+ @verifier = verifier
285
+ end
286
+
287
+ def verify(arguments)
288
+ @verifier.verify(arguments)
289
+ end
290
+
291
+ def verify_signature(&block)
292
+ yield
293
+ end
294
+ end
295
+
277
296
  # Instantiates a new host-key verification class, based on the value of
278
297
  # the parameter.
279
298
  #
@@ -285,8 +304,8 @@ module Net
285
304
  # - :accept_new (insecure)
286
305
  # - :always (secure)
287
306
  #
288
- # If the argument happens to respond to :verify, it is returned
289
- # directly. Otherwise, an exception is raised.
307
+ # If the argument happens to respond to :verify and :verify_signature,
308
+ # it is returned directly. Otherwise, an exception is raised.
290
309
  #
291
310
  # Values false, true, and :very were deprecated in
292
311
  # [#595](https://github.com/net-ssh/net-ssh/pull/595)
@@ -314,7 +333,12 @@ module Net
314
333
  Net::SSH::Verifiers::Always.new
315
334
  else
316
335
  if verifier.respond_to?(:verify)
317
- verifier
336
+ if verifier.respond_to?(:verify_signature)
337
+ verifier
338
+ else
339
+ Kernel.warn("Warning: verifier without :verify_signature is deprecated")
340
+ CompatibleVerifier.new(verifier)
341
+ end
318
342
  else
319
343
  raise(
320
344
  ArgumentError,
@@ -2,10 +2,9 @@ require 'zlib'
2
2
  require 'net/ssh/transport/cipher_factory'
3
3
  require 'net/ssh/transport/hmac'
4
4
 
5
- module Net
6
- module SSH
5
+ module Net
6
+ module SSH
7
7
  module Transport
8
-
9
8
  # Encapsulates state information about one end of an SSH connection. Such
10
9
  # state includes the packet sequence number, the algorithms in use, how
11
10
  # many packets and blocks have been processed since the last reset, and so
@@ -14,46 +13,46 @@ module Net
14
13
  class State
15
14
  # The socket object that owns this state object.
16
15
  attr_reader :socket
17
-
16
+
18
17
  # The next packet sequence number for this socket endpoint.
19
18
  attr_reader :sequence_number
20
-
19
+
21
20
  # The hmac algorithm in use for this endpoint.
22
21
  attr_reader :hmac
23
-
22
+
24
23
  # The compression algorithm in use for this endpoint.
25
24
  attr_reader :compression
26
-
25
+
27
26
  # The compression level to use when compressing data (or nil, for the default).
28
27
  attr_reader :compression_level
29
-
28
+
30
29
  # The number of packets processed since the last call to #reset!
31
30
  attr_reader :packets
32
-
31
+
33
32
  # The number of data blocks processed since the last call to #reset!
34
33
  attr_reader :blocks
35
-
34
+
36
35
  # The cipher algorithm in use for this socket endpoint.
37
36
  attr_reader :cipher
38
-
37
+
39
38
  # The block size for the cipher
40
39
  attr_reader :block_size
41
-
40
+
42
41
  # The role that this state plays (either :client or :server)
43
42
  attr_reader :role
44
-
43
+
45
44
  # The maximum number of packets that this endpoint wants to process before
46
45
  # needing a rekey.
47
46
  attr_accessor :max_packets
48
-
47
+
49
48
  # The maximum number of blocks that this endpoint wants to process before
50
49
  # needing a rekey.
51
50
  attr_accessor :max_blocks
52
-
51
+
53
52
  # The user-specified maximum number of bytes that this endpoint ought to
54
53
  # process before needing a rekey.
55
54
  attr_accessor :rekey_limit
56
-
55
+
57
56
  # Creates a new state object, belonging to the given socket. Initializes
58
57
  # the algorithms to "none".
59
58
  def initialize(socket, role)
@@ -65,9 +64,9 @@ module Net
65
64
  @hmac = HMAC.get("none")
66
65
  @compression = nil
67
66
  @compressor = @decompressor = nil
68
- @next_iv = ""
67
+ @next_iv = String.new
69
68
  end
70
-
69
+
71
70
  # A convenience method for quickly setting multiple values in a single
72
71
  # command.
73
72
  def set(values)
@@ -76,19 +75,19 @@ module Net
76
75
  end
77
76
  reset!
78
77
  end
79
-
78
+
80
79
  def update_cipher(data)
81
80
  result = cipher.update(data)
82
81
  update_next_iv(role == :client ? result : data)
83
82
  return result
84
83
  end
85
-
84
+
86
85
  def final_cipher
87
86
  result = cipher.final
88
87
  update_next_iv(role == :client ? result : "", true)
89
88
  return result
90
89
  end
91
-
90
+
92
91
  # Increments the counters. The sequence number is incremented (and remapped
93
92
  # so it always fits in a 32-bit integer). The number of packets and blocks
94
93
  # are also incremented.
@@ -97,18 +96,18 @@ module Net
97
96
  @packets += 1
98
97
  @blocks += (packet_length + 4) / @block_size
99
98
  end
100
-
99
+
101
100
  # The compressor object to use when compressing data. This takes into account
102
101
  # the desired compression level.
103
102
  def compressor
104
103
  @compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
105
104
  end
106
-
105
+
107
106
  # The decompressor object to use when decompressing data.
108
107
  def decompressor
109
108
  @decompressor ||= Zlib::Inflate.new(nil)
110
109
  end
111
-
110
+
112
111
  # Returns true if data compression/decompression is enabled. This will
113
112
  # return true if :standard compression is selected, or if :delayed
114
113
  # compression is selected and the :authenticated hint has been received
@@ -116,33 +115,35 @@ module Net
116
115
  def compression?
117
116
  compression == :standard || (compression == :delayed && socket.hints[:authenticated])
118
117
  end
119
-
118
+
120
119
  # Compresses the data. If no compression is in effect, this will just return
121
120
  # the data unmodified, otherwise it uses #compressor to compress the data.
122
121
  def compress(data)
123
122
  data = data.to_s
124
123
  return data unless compression?
124
+
125
125
  compressor.deflate(data, Zlib::SYNC_FLUSH)
126
126
  end
127
-
127
+
128
128
  # Deompresses the data. If no compression is in effect, this will just return
129
129
  # the data unmodified, otherwise it uses #decompressor to decompress the data.
130
130
  def decompress(data)
131
131
  data = data.to_s
132
132
  return data unless compression?
133
+
133
134
  decompressor.inflate(data)
134
135
  end
135
-
136
+
136
137
  # Resets the counters on the state object, but leaves the sequence_number
137
138
  # unchanged. It also sets defaults for and recomputes the max_packets and
138
139
  # max_blocks values.
139
140
  def reset!
140
141
  @packets = @blocks = 0
141
-
142
+
142
143
  @max_packets ||= 1 << 31
143
-
144
- @block_size = cipher.name == "RC4" ? 8 : cipher.block_size
145
-
144
+
145
+ @block_size = cipher.block_size
146
+
146
147
  if max_blocks.nil?
147
148
  # cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
148
149
  # limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
@@ -152,16 +153,16 @@ module Net
152
153
  else
153
154
  @max_blocks = (1 << 30) / @block_size
154
155
  end
155
-
156
+
156
157
  # if a limit on the # of bytes has been given, convert that into a
157
158
  # minimum number of blocks processed.
158
-
159
+
159
160
  @max_blocks = [@max_blocks, rekey_limit / @block_size].min if rekey_limit
160
161
  end
161
-
162
+
162
163
  cleanup
163
164
  end
164
-
165
+
165
166
  # Closes any the compressor and/or decompressor objects that have been
166
167
  # instantiated.
167
168
  def cleanup
@@ -169,17 +170,17 @@ module Net
169
170
  @compressor.finish if !@compressor.finished?
170
171
  @compressor.close
171
172
  end
172
-
173
+
173
174
  if @decompressor
174
175
  # we call reset here so that we don't get warnings when we try to
175
176
  # close the decompressor
176
177
  @decompressor.reset
177
178
  @decompressor.close
178
179
  end
179
-
180
+
180
181
  @compressor = @decompressor = nil
181
182
  end
182
-
183
+
183
184
  # Returns true if the number of packets processed exceeds the maximum
184
185
  # number of packets, or if the number of blocks processed exceeds the
185
186
  # maximum number of blocks.
@@ -187,22 +188,21 @@ module Net
187
188
  max_packets && packets > max_packets ||
188
189
  max_blocks && blocks > max_blocks
189
190
  end
190
-
191
+
191
192
  private
192
-
193
- def update_next_iv(data, reset=false)
193
+
194
+ def update_next_iv(data, reset = false)
194
195
  @next_iv << data
195
196
  @next_iv = @next_iv[@next_iv.size - cipher.iv_len..-1]
196
-
197
+
197
198
  if reset
198
199
  cipher.reset
199
200
  cipher.iv = @next_iv
200
201
  end
201
-
202
+
202
203
  return data
203
204
  end
204
205
  end
205
-
206
206
  end
207
207
  end
208
208
  end
@@ -5,7 +5,6 @@ require 'net/ssh/verifiers/always'
5
5
  module Net
6
6
  module SSH
7
7
  module Verifiers
8
-
9
8
  # Does a strict host verification, looking the server up in the known
10
9
  # host files to see if a key has already been seen for this server. If this
11
10
  # server does not appear in any host file, this will silently add the
@@ -21,8 +20,14 @@ module Net
21
20
  return true
22
21
  end
23
22
  end
24
- end
25
23
 
24
+ def verify_signature(&block)
25
+ yield
26
+ rescue HostKeyUnknown => err
27
+ err.remember_host!
28
+ return true
29
+ end
30
+ end
26
31
  end
27
32
  end
28
33
  end
@@ -3,7 +3,6 @@ require 'net/ssh/verifiers/accept_new'
3
3
  module Net
4
4
  module SSH
5
5
  module Verifiers
6
-
7
6
  # Basically the same as the AcceptNew verifier, but does not try to actually
8
7
  # verify a connection if the server is the localhost and the port is a
9
8
  # nonstandard port number. Those two conditions will typically mean the
@@ -14,6 +13,7 @@ module Net
14
13
  # returns true. Otherwise, performs the standard strict verification.
15
14
  def verify(arguments)
16
15
  return true if tunnelled?(arguments)
16
+
17
17
  super
18
18
  end
19
19
 
@@ -28,7 +28,6 @@ module Net
28
28
  return ip == "127.0.0.1" || ip == "::1"
29
29
  end
30
30
  end
31
-
32
31
  end
33
32
  end
34
33
  end