net-ssh-backports 6.3.0.backports

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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +93 -0
  3. data/.gitignore +13 -0
  4. data/.rubocop.yml +21 -0
  5. data/.rubocop_todo.yml +1074 -0
  6. data/.travis.yml +51 -0
  7. data/CHANGES.txt +698 -0
  8. data/Gemfile +13 -0
  9. data/Gemfile.noed25519 +12 -0
  10. data/ISSUE_TEMPLATE.md +30 -0
  11. data/LICENSE.txt +19 -0
  12. data/Manifest +132 -0
  13. data/README.md +287 -0
  14. data/Rakefile +105 -0
  15. data/THANKS.txt +110 -0
  16. data/appveyor.yml +58 -0
  17. data/lib/net/ssh/authentication/agent.rb +284 -0
  18. data/lib/net/ssh/authentication/certificate.rb +183 -0
  19. data/lib/net/ssh/authentication/constants.rb +20 -0
  20. data/lib/net/ssh/authentication/ed25519.rb +185 -0
  21. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  22. data/lib/net/ssh/authentication/key_manager.rb +297 -0
  23. data/lib/net/ssh/authentication/methods/abstract.rb +69 -0
  24. data/lib/net/ssh/authentication/methods/hostbased.rb +72 -0
  25. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +77 -0
  26. data/lib/net/ssh/authentication/methods/none.rb +34 -0
  27. data/lib/net/ssh/authentication/methods/password.rb +80 -0
  28. data/lib/net/ssh/authentication/methods/publickey.rb +95 -0
  29. data/lib/net/ssh/authentication/pageant.rb +497 -0
  30. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  31. data/lib/net/ssh/authentication/session.rb +163 -0
  32. data/lib/net/ssh/buffer.rb +434 -0
  33. data/lib/net/ssh/buffered_io.rb +202 -0
  34. data/lib/net/ssh/config.rb +406 -0
  35. data/lib/net/ssh/connection/channel.rb +695 -0
  36. data/lib/net/ssh/connection/constants.rb +33 -0
  37. data/lib/net/ssh/connection/event_loop.rb +123 -0
  38. data/lib/net/ssh/connection/keepalive.rb +59 -0
  39. data/lib/net/ssh/connection/session.rb +712 -0
  40. data/lib/net/ssh/connection/term.rb +180 -0
  41. data/lib/net/ssh/errors.rb +106 -0
  42. data/lib/net/ssh/key_factory.rb +218 -0
  43. data/lib/net/ssh/known_hosts.rb +264 -0
  44. data/lib/net/ssh/loggable.rb +62 -0
  45. data/lib/net/ssh/packet.rb +106 -0
  46. data/lib/net/ssh/prompt.rb +62 -0
  47. data/lib/net/ssh/proxy/command.rb +123 -0
  48. data/lib/net/ssh/proxy/errors.rb +16 -0
  49. data/lib/net/ssh/proxy/http.rb +98 -0
  50. data/lib/net/ssh/proxy/https.rb +50 -0
  51. data/lib/net/ssh/proxy/jump.rb +54 -0
  52. data/lib/net/ssh/proxy/socks4.rb +67 -0
  53. data/lib/net/ssh/proxy/socks5.rb +140 -0
  54. data/lib/net/ssh/service/forward.rb +426 -0
  55. data/lib/net/ssh/test/channel.rb +147 -0
  56. data/lib/net/ssh/test/extensions.rb +173 -0
  57. data/lib/net/ssh/test/kex.rb +46 -0
  58. data/lib/net/ssh/test/local_packet.rb +53 -0
  59. data/lib/net/ssh/test/packet.rb +101 -0
  60. data/lib/net/ssh/test/remote_packet.rb +40 -0
  61. data/lib/net/ssh/test/script.rb +180 -0
  62. data/lib/net/ssh/test/socket.rb +65 -0
  63. data/lib/net/ssh/test.rb +94 -0
  64. data/lib/net/ssh/transport/algorithms.rb +502 -0
  65. data/lib/net/ssh/transport/cipher_factory.rb +103 -0
  66. data/lib/net/ssh/transport/constants.rb +40 -0
  67. data/lib/net/ssh/transport/ctr.rb +115 -0
  68. data/lib/net/ssh/transport/hmac/abstract.rb +97 -0
  69. data/lib/net/ssh/transport/hmac/md5.rb +10 -0
  70. data/lib/net/ssh/transport/hmac/md5_96.rb +9 -0
  71. data/lib/net/ssh/transport/hmac/none.rb +13 -0
  72. data/lib/net/ssh/transport/hmac/ripemd160.rb +11 -0
  73. data/lib/net/ssh/transport/hmac/sha1.rb +11 -0
  74. data/lib/net/ssh/transport/hmac/sha1_96.rb +9 -0
  75. data/lib/net/ssh/transport/hmac/sha2_256.rb +11 -0
  76. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +9 -0
  77. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  78. data/lib/net/ssh/transport/hmac/sha2_512.rb +11 -0
  79. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +9 -0
  80. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  81. data/lib/net/ssh/transport/hmac.rb +47 -0
  82. data/lib/net/ssh/transport/identity_cipher.rb +57 -0
  83. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  84. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  85. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  86. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  87. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +37 -0
  88. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  89. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +122 -0
  90. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +72 -0
  91. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +11 -0
  92. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +39 -0
  93. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +21 -0
  94. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +21 -0
  95. data/lib/net/ssh/transport/kex.rb +31 -0
  96. data/lib/net/ssh/transport/key_expander.rb +30 -0
  97. data/lib/net/ssh/transport/openssl.rb +253 -0
  98. data/lib/net/ssh/transport/packet_stream.rb +280 -0
  99. data/lib/net/ssh/transport/server_version.rb +77 -0
  100. data/lib/net/ssh/transport/session.rb +354 -0
  101. data/lib/net/ssh/transport/state.rb +208 -0
  102. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  103. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  104. data/lib/net/ssh/verifiers/always.rb +58 -0
  105. data/lib/net/ssh/verifiers/never.rb +19 -0
  106. data/lib/net/ssh/version.rb +68 -0
  107. data/lib/net/ssh.rb +330 -0
  108. data/net-ssh-public_cert.pem +20 -0
  109. data/net-ssh.gemspec +44 -0
  110. data/support/ssh_tunnel_bug.rb +65 -0
  111. metadata +271 -0
@@ -0,0 +1,354 @@
1
+ require 'socket'
2
+
3
+ require 'net/ssh/errors'
4
+ require 'net/ssh/loggable'
5
+ require 'net/ssh/version'
6
+ require 'net/ssh/transport/algorithms'
7
+ require 'net/ssh/transport/constants'
8
+ require 'net/ssh/transport/packet_stream'
9
+ require 'net/ssh/transport/server_version'
10
+ require 'net/ssh/verifiers/accept_new_or_local_tunnel'
11
+ require 'net/ssh/verifiers/accept_new'
12
+ require 'net/ssh/verifiers/always'
13
+ require 'net/ssh/verifiers/never'
14
+
15
+ module Net
16
+ module SSH
17
+ module Transport
18
+ # The transport layer represents the lowest level of the SSH protocol, and
19
+ # implements basic message exchanging and protocol initialization. It will
20
+ # never be instantiated directly (unless you really know what you're about),
21
+ # but will instead be created for you automatically when you create a new
22
+ # SSH session via Net::SSH.start.
23
+ class Session
24
+ include Loggable
25
+ include Constants
26
+
27
+ # The standard port for the SSH protocol.
28
+ DEFAULT_PORT = 22
29
+
30
+ # The host to connect to, as given to the constructor.
31
+ attr_reader :host
32
+
33
+ # The port number to connect to, as given in the options to the constructor.
34
+ # If no port number was given, this will default to DEFAULT_PORT.
35
+ attr_reader :port
36
+
37
+ # The underlying socket object being used to communicate with the remote
38
+ # host.
39
+ attr_reader :socket
40
+
41
+ # The ServerVersion instance that encapsulates the negotiated protocol
42
+ # version.
43
+ attr_reader :server_version
44
+
45
+ # The Algorithms instance used to perform key exchanges.
46
+ attr_reader :algorithms
47
+
48
+ # The host-key verifier object used to verify host keys, to ensure that
49
+ # the connection is not being spoofed.
50
+ attr_reader :host_key_verifier
51
+
52
+ # The hash of options that were given to the object at initialization.
53
+ attr_reader :options
54
+
55
+ # Instantiates a new transport layer abstraction. This will block until
56
+ # the initial key exchange completes, leaving you with a ready-to-use
57
+ # transport session.
58
+ def initialize(host, options={})
59
+ self.logger = options[:logger]
60
+
61
+ @host = host
62
+ @port = options[:port] || DEFAULT_PORT
63
+ @bind_address = options[:bind_address] || nil
64
+ @options = options
65
+
66
+ @socket =
67
+ if (factory = options[:proxy])
68
+ debug { "establishing connection to #{@host}:#{@port} through proxy" }
69
+ factory.open(@host, @port, options)
70
+ else
71
+ debug { "establishing connection to #{@host}:#{@port}" }
72
+ Socket.tcp(@host, @port, @bind_address, nil,
73
+ connect_timeout: options[:timeout])
74
+ end
75
+
76
+ @socket.extend(PacketStream)
77
+ @socket.logger = @logger
78
+
79
+ debug { "connection established" }
80
+
81
+ @queue = []
82
+
83
+ @host_key_verifier = select_host_key_verifier(options[:verify_host_key])
84
+
85
+ @server_version = ServerVersion.new(socket, logger, options[:timeout])
86
+
87
+ @algorithms = Algorithms.new(self, options)
88
+ @algorithms.start
89
+ wait { algorithms.initialized? }
90
+ rescue Errno::ETIMEDOUT
91
+ raise Net::SSH::ConnectionTimeout
92
+ end
93
+
94
+ def host_keys
95
+ @host_keys ||= begin
96
+ known_hosts = options.fetch(:known_hosts, KnownHosts)
97
+ known_hosts.search_for(options[:host_key_alias] || host_as_string, options)
98
+ end
99
+ end
100
+
101
+ # Returns the host (and possibly IP address) in a format compatible with
102
+ # SSH known-host files.
103
+ def host_as_string
104
+ @host_as_string ||= begin
105
+ string = "#{host}"
106
+ string = "[#{string}]:#{port}" if port != DEFAULT_PORT
107
+
108
+ peer_ip = socket.peer_ip
109
+
110
+ if peer_ip != Net::SSH::Transport::PacketStream::PROXY_COMMAND_HOST_IP &&
111
+ peer_ip != host
112
+ string2 = peer_ip
113
+ string2 = "[#{string2}]:#{port}" if port != DEFAULT_PORT
114
+ string << "," << string2
115
+ end
116
+
117
+ string
118
+ end
119
+ end
120
+
121
+ # Returns true if the underlying socket has been closed.
122
+ def closed?
123
+ socket.closed?
124
+ end
125
+
126
+ # Cleans up (see PacketStream#cleanup) and closes the underlying socket.
127
+ def close
128
+ socket.cleanup
129
+ socket.close
130
+ end
131
+
132
+ # Performs a "hard" shutdown of the connection. In general, this should
133
+ # never be done, but it might be necessary (in a rescue clause, for instance,
134
+ # when the connection needs to close but you don't know the status of the
135
+ # underlying protocol's state).
136
+ def shutdown!
137
+ error { "forcing connection closed" }
138
+ socket.close
139
+ end
140
+
141
+ # Returns a new service_request packet for the given service name, ready
142
+ # for sending to the server.
143
+ def service_request(service)
144
+ Net::SSH::Buffer.from(:byte, SERVICE_REQUEST, :string, service)
145
+ end
146
+
147
+ # Requests a rekey operation, and blocks until the operation completes.
148
+ # If a rekey is already pending, this returns immediately, having no
149
+ # effect.
150
+ def rekey!
151
+ if !algorithms.pending?
152
+ algorithms.rekey!
153
+ wait { algorithms.initialized? }
154
+ end
155
+ end
156
+
157
+ # Returns immediately if a rekey is already in process. Otherwise, if a
158
+ # rekey is needed (as indicated by the socket, see PacketStream#if_needs_rekey?)
159
+ # one is performed, causing this method to block until it completes.
160
+ def rekey_as_needed
161
+ return if algorithms.pending?
162
+
163
+ socket.if_needs_rekey? { rekey! }
164
+ end
165
+
166
+ # Returns a hash of information about the peer (remote) side of the socket,
167
+ # including :ip, :port, :host, and :canonized (see #host_as_string).
168
+ def peer
169
+ @peer ||= { ip: socket.peer_ip, port: @port.to_i, host: @host, canonized: host_as_string }
170
+ end
171
+
172
+ # Blocks until a new packet is available to be read, and returns that
173
+ # packet. See #poll_message.
174
+ def next_message
175
+ poll_message(:block)
176
+ end
177
+
178
+ # Tries to read the next packet from the socket. If mode is :nonblock (the
179
+ # default), this will not block and will return nil if there are no packets
180
+ # waiting to be read. Otherwise, this will block until a packet is
181
+ # available. Note that some packet types (DISCONNECT, IGNORE, UNIMPLEMENTED,
182
+ # DEBUG, and KEXINIT) are handled silently by this method, and will never
183
+ # be returned.
184
+ #
185
+ # If a key-exchange is in process and a disallowed packet type is
186
+ # received, it will be enqueued and otherwise ignored. When a key-exchange
187
+ # is not in process, and consume_queue is true, packets will be first
188
+ # read from the queue before the socket is queried.
189
+ def poll_message(mode=:nonblock, consume_queue=true)
190
+ loop do
191
+ return @queue.shift if consume_queue && @queue.any? && algorithms.allow?(@queue.first)
192
+
193
+ packet = socket.next_packet(mode, options[:timeout])
194
+ return nil if packet.nil?
195
+
196
+ case packet.type
197
+ when DISCONNECT
198
+ raise Net::SSH::Disconnect, "disconnected: #{packet[:description]} (#{packet[:reason_code]})"
199
+
200
+ when IGNORE
201
+ debug { "IGNORE packet received: #{packet[:data].inspect}" }
202
+
203
+ when UNIMPLEMENTED
204
+ lwarn { "UNIMPLEMENTED: #{packet[:number]}" }
205
+
206
+ when DEBUG
207
+ send(packet[:always_display] ? :fatal : :debug) { packet[:message] }
208
+
209
+ when KEXINIT
210
+ algorithms.accept_kexinit(packet)
211
+
212
+ else
213
+ return packet if algorithms.allow?(packet)
214
+
215
+ push(packet)
216
+ end
217
+ end
218
+ end
219
+
220
+ # Waits (blocks) until the given block returns true. If no block is given,
221
+ # this just waits long enough to see if there are any pending packets. Any
222
+ # packets read are enqueued (see #push).
223
+ def wait
224
+ loop do
225
+ break if block_given? && yield
226
+
227
+ message = poll_message(:nonblock, false)
228
+ push(message) if message
229
+ break if !block_given?
230
+ end
231
+ end
232
+
233
+ # Adds the given packet to the packet queue. If the queue is non-empty,
234
+ # #poll_message will return packets from the queue in the order they
235
+ # were received.
236
+ def push(packet)
237
+ @queue.push(packet)
238
+ end
239
+
240
+ # Sends the given message via the packet stream, blocking until the
241
+ # entire message has been sent.
242
+ def send_message(message)
243
+ socket.send_packet(message)
244
+ end
245
+
246
+ # Enqueues the given message, such that it will be sent at the earliest
247
+ # opportunity. This does not block, but returns immediately.
248
+ def enqueue_message(message)
249
+ socket.enqueue_packet(message)
250
+ end
251
+
252
+ # Configure's the packet stream's client state with the given set of
253
+ # options. This is typically used to define the cipher, compression, and
254
+ # hmac algorithms to use when sending packets to the server.
255
+ def configure_client(options={})
256
+ socket.client.set(options)
257
+ end
258
+
259
+ # Configure's the packet stream's server state with the given set of
260
+ # options. This is typically used to define the cipher, compression, and
261
+ # hmac algorithms to use when reading packets from the server.
262
+ def configure_server(options={})
263
+ socket.server.set(options)
264
+ end
265
+
266
+ # Sets a new hint for the packet stream, which the packet stream may use
267
+ # to change its behavior. (See PacketStream#hints).
268
+ def hint(which, value=true)
269
+ socket.hints[which] = value
270
+ end
271
+
272
+ public
273
+
274
+ # this method is primarily for use in tests
275
+ attr_reader :queue #:nodoc:
276
+
277
+ private
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
+
296
+ # Instantiates a new host-key verification class, based on the value of
297
+ # the parameter.
298
+ #
299
+ # Usually, the argument is a symbol like `:never` which corresponds to
300
+ # a verifier, like `::Net::SSH::Verifiers::Never`.
301
+ #
302
+ # - :never (very insecure)
303
+ # - :accept_new_or_local_tunnel (insecure)
304
+ # - :accept_new (insecure)
305
+ # - :always (secure)
306
+ #
307
+ # If the argument happens to respond to :verify and :verify_signature,
308
+ # it is returned directly. Otherwise, an exception is raised.
309
+ #
310
+ # Values false, true, and :very were deprecated in
311
+ # [#595](https://github.com/net-ssh/net-ssh/pull/595)
312
+ def select_host_key_verifier(verifier)
313
+ case verifier
314
+ when false
315
+ Kernel.warn('verify_host_key: false is deprecated, use :never')
316
+ Net::SSH::Verifiers::Never.new
317
+ when :never then
318
+ Net::SSH::Verifiers::Never.new
319
+ when true
320
+ Kernel.warn('verify_host_key: true is deprecated, use :accept_new_or_local_tunnel')
321
+ Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
322
+ when :accept_new_or_local_tunnel, nil then
323
+ Net::SSH::Verifiers::AcceptNewOrLocalTunnel.new
324
+ when :very
325
+ Kernel.warn('verify_host_key: :very is deprecated, use :accept_new')
326
+ Net::SSH::Verifiers::AcceptNew.new
327
+ when :accept_new then
328
+ Net::SSH::Verifiers::AcceptNew.new
329
+ when :secure then
330
+ Kernel.warn('verify_host_key: :secure is deprecated, use :always')
331
+ Net::SSH::Verifiers::Always.new
332
+ when :always then
333
+ Net::SSH::Verifiers::Always.new
334
+ else
335
+ if verifier.respond_to?(:verify)
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
342
+ else
343
+ raise(
344
+ ArgumentError,
345
+ "Invalid argument to :verify_host_key (or deprecated " \
346
+ ":paranoid): #{verifier.inspect}"
347
+ )
348
+ end
349
+ end
350
+ end
351
+ end
352
+ end
353
+ end
354
+ end
@@ -0,0 +1,208 @@
1
+ require 'zlib'
2
+ require 'net/ssh/transport/cipher_factory'
3
+ require 'net/ssh/transport/hmac'
4
+
5
+ module Net
6
+ module SSH
7
+ module Transport
8
+ # Encapsulates state information about one end of an SSH connection. Such
9
+ # state includes the packet sequence number, the algorithms in use, how
10
+ # many packets and blocks have been processed since the last reset, and so
11
+ # forth. This class will never be instantiated directly, but is used as
12
+ # part of the internal state of the PacketStream module.
13
+ class State
14
+ # The socket object that owns this state object.
15
+ attr_reader :socket
16
+
17
+ # The next packet sequence number for this socket endpoint.
18
+ attr_reader :sequence_number
19
+
20
+ # The hmac algorithm in use for this endpoint.
21
+ attr_reader :hmac
22
+
23
+ # The compression algorithm in use for this endpoint.
24
+ attr_reader :compression
25
+
26
+ # The compression level to use when compressing data (or nil, for the default).
27
+ attr_reader :compression_level
28
+
29
+ # The number of packets processed since the last call to #reset!
30
+ attr_reader :packets
31
+
32
+ # The number of data blocks processed since the last call to #reset!
33
+ attr_reader :blocks
34
+
35
+ # The cipher algorithm in use for this socket endpoint.
36
+ attr_reader :cipher
37
+
38
+ # The block size for the cipher
39
+ attr_reader :block_size
40
+
41
+ # The role that this state plays (either :client or :server)
42
+ attr_reader :role
43
+
44
+ # The maximum number of packets that this endpoint wants to process before
45
+ # needing a rekey.
46
+ attr_accessor :max_packets
47
+
48
+ # The maximum number of blocks that this endpoint wants to process before
49
+ # needing a rekey.
50
+ attr_accessor :max_blocks
51
+
52
+ # The user-specified maximum number of bytes that this endpoint ought to
53
+ # process before needing a rekey.
54
+ attr_accessor :rekey_limit
55
+
56
+ # Creates a new state object, belonging to the given socket. Initializes
57
+ # the algorithms to "none".
58
+ def initialize(socket, role)
59
+ @socket = socket
60
+ @role = role
61
+ @sequence_number = @packets = @blocks = 0
62
+ @cipher = CipherFactory.get("none")
63
+ @block_size = 8
64
+ @hmac = HMAC.get("none")
65
+ @compression = nil
66
+ @compressor = @decompressor = nil
67
+ @next_iv = String.new
68
+ end
69
+
70
+ # A convenience method for quickly setting multiple values in a single
71
+ # command.
72
+ def set(values)
73
+ values.each do |key, value|
74
+ instance_variable_set("@#{key}", value)
75
+ end
76
+ reset!
77
+ end
78
+
79
+ def update_cipher(data)
80
+ result = cipher.update(data)
81
+ update_next_iv(role == :client ? result : data)
82
+ return result
83
+ end
84
+
85
+ def final_cipher
86
+ result = cipher.final
87
+ update_next_iv(role == :client ? result : "", true)
88
+ return result
89
+ end
90
+
91
+ # Increments the counters. The sequence number is incremented (and remapped
92
+ # so it always fits in a 32-bit integer). The number of packets and blocks
93
+ # are also incremented.
94
+ def increment(packet_length)
95
+ @sequence_number = (@sequence_number + 1) & 0xFFFFFFFF
96
+ @packets += 1
97
+ @blocks += (packet_length + 4) / @block_size
98
+ end
99
+
100
+ # The compressor object to use when compressing data. This takes into account
101
+ # the desired compression level.
102
+ def compressor
103
+ @compressor ||= Zlib::Deflate.new(compression_level || Zlib::DEFAULT_COMPRESSION)
104
+ end
105
+
106
+ # The decompressor object to use when decompressing data.
107
+ def decompressor
108
+ @decompressor ||= Zlib::Inflate.new(nil)
109
+ end
110
+
111
+ # Returns true if data compression/decompression is enabled. This will
112
+ # return true if :standard compression is selected, or if :delayed
113
+ # compression is selected and the :authenticated hint has been received
114
+ # by the socket.
115
+ def compression?
116
+ compression == :standard || (compression == :delayed && socket.hints[:authenticated])
117
+ end
118
+
119
+ # Compresses the data. If no compression is in effect, this will just return
120
+ # the data unmodified, otherwise it uses #compressor to compress the data.
121
+ def compress(data)
122
+ data = data.to_s
123
+ return data unless compression?
124
+
125
+ compressor.deflate(data, Zlib::SYNC_FLUSH)
126
+ end
127
+
128
+ # Deompresses the data. If no compression is in effect, this will just return
129
+ # the data unmodified, otherwise it uses #decompressor to decompress the data.
130
+ def decompress(data)
131
+ data = data.to_s
132
+ return data unless compression?
133
+
134
+ decompressor.inflate(data)
135
+ end
136
+
137
+ # Resets the counters on the state object, but leaves the sequence_number
138
+ # unchanged. It also sets defaults for and recomputes the max_packets and
139
+ # max_blocks values.
140
+ def reset!
141
+ @packets = @blocks = 0
142
+
143
+ @max_packets ||= 1 << 31
144
+
145
+ @block_size = cipher.block_size
146
+
147
+ if max_blocks.nil?
148
+ # cargo-culted from openssh. the idea is that "the 2^(blocksize*2)
149
+ # limit is too expensive for 3DES, blowfish, etc., so enforce a 1GB
150
+ # limit for small blocksizes."
151
+ if @block_size >= 16
152
+ @max_blocks = 1 << (@block_size * 2)
153
+ else
154
+ @max_blocks = (1 << 30) / @block_size
155
+ end
156
+
157
+ # if a limit on the # of bytes has been given, convert that into a
158
+ # minimum number of blocks processed.
159
+
160
+ @max_blocks = [@max_blocks, rekey_limit / @block_size].min if rekey_limit
161
+ end
162
+
163
+ cleanup
164
+ end
165
+
166
+ # Closes any the compressor and/or decompressor objects that have been
167
+ # instantiated.
168
+ def cleanup
169
+ if @compressor
170
+ @compressor.finish if !@compressor.finished?
171
+ @compressor.close
172
+ end
173
+
174
+ if @decompressor
175
+ # we call reset here so that we don't get warnings when we try to
176
+ # close the decompressor
177
+ @decompressor.reset
178
+ @decompressor.close
179
+ end
180
+
181
+ @compressor = @decompressor = nil
182
+ end
183
+
184
+ # Returns true if the number of packets processed exceeds the maximum
185
+ # number of packets, or if the number of blocks processed exceeds the
186
+ # maximum number of blocks.
187
+ def needs_rekey?
188
+ max_packets && packets > max_packets ||
189
+ max_blocks && blocks > max_blocks
190
+ end
191
+
192
+ private
193
+
194
+ def update_next_iv(data, reset=false)
195
+ @next_iv << data
196
+ @next_iv = @next_iv[@next_iv.size - cipher.iv_len..-1]
197
+
198
+ if reset
199
+ cipher.reset
200
+ cipher.iv = @next_iv
201
+ end
202
+
203
+ return data
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,33 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/known_hosts'
3
+ require 'net/ssh/verifiers/always'
4
+
5
+ module Net
6
+ module SSH
7
+ module Verifiers
8
+ # Does a strict host verification, looking the server up in the known
9
+ # host files to see if a key has already been seen for this server. If this
10
+ # server does not appear in any host file, this will silently add the
11
+ # server. If the server does appear at least once, but the key given does
12
+ # not match any known for the server, an exception will be raised (HostKeyMismatch).
13
+ # Otherwise, this returns true.
14
+ class AcceptNew < Always
15
+ def verify(arguments)
16
+ begin
17
+ super
18
+ rescue HostKeyUnknown => err
19
+ err.remember_host!
20
+ return true
21
+ end
22
+ end
23
+
24
+ def verify_signature(&block)
25
+ yield
26
+ rescue HostKeyUnknown => err
27
+ err.remember_host!
28
+ return true
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'net/ssh/verifiers/accept_new'
2
+
3
+ module Net
4
+ module SSH
5
+ module Verifiers
6
+ # Basically the same as the AcceptNew verifier, but does not try to actually
7
+ # verify a connection if the server is the localhost and the port is a
8
+ # nonstandard port number. Those two conditions will typically mean the
9
+ # connection is being tunnelled through a forwarded port, so the known-hosts
10
+ # file will not be helpful (in general).
11
+ class AcceptNewOrLocalTunnel < AcceptNew
12
+ # Tries to determine if the connection is being tunnelled, and if so,
13
+ # returns true. Otherwise, performs the standard strict verification.
14
+ def verify(arguments)
15
+ return true if tunnelled?(arguments)
16
+
17
+ super
18
+ end
19
+
20
+ private
21
+
22
+ # A connection is potentially being tunnelled if the port is not 22,
23
+ # and the ip refers to the localhost.
24
+ def tunnelled?(args)
25
+ return false if args[:session].port == Net::SSH::Transport::Session::DEFAULT_PORT
26
+
27
+ ip = args[:session].peer[:ip]
28
+ return ip == "127.0.0.1" || ip == "::1"
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,58 @@
1
+ require 'net/ssh/errors'
2
+ require 'net/ssh/known_hosts'
3
+
4
+ module Net
5
+ module SSH
6
+ module Verifiers
7
+ # Does a strict host verification, looking the server up in the known
8
+ # host files to see if a key has already been seen for this server. If this
9
+ # server does not appear in any host file, an exception will be raised
10
+ # (HostKeyUnknown). This is in contrast to the "Strict" class, which will
11
+ # silently add the key to your known_hosts file. If the server does appear at
12
+ # least once, but the key given does not match any known for the server, an
13
+ # exception will be raised (HostKeyMismatch).
14
+ # Otherwise, this returns true.
15
+ class Always
16
+ def verify(arguments)
17
+ host_keys = arguments[:session].host_keys
18
+
19
+ # We've never seen this host before, so raise an exception.
20
+ process_cache_miss(host_keys, arguments, HostKeyUnknown, "is unknown") if host_keys.empty?
21
+
22
+ # If we found any matches, check to see that the key type and
23
+ # blob also match.
24
+
25
+ found = host_keys.any? do |key|
26
+ if key.respond_to?(:matches_key?)
27
+ key.matches_key?(arguments[:key])
28
+ else
29
+ key.ssh_type == arguments[:key].ssh_type && key.to_blob == arguments[:key].to_blob
30
+ end
31
+ end
32
+
33
+ # If a match was found, return true. Otherwise, raise an exception
34
+ # indicating that the key was not recognized.
35
+ process_cache_miss(host_keys, arguments, HostKeyMismatch, "does not match") unless found
36
+
37
+ found
38
+ end
39
+
40
+ def verify_signature(&block)
41
+ yield
42
+ end
43
+
44
+ private
45
+
46
+ def process_cache_miss(host_keys, args, exc_class, message)
47
+ exception = exc_class.new("fingerprint #{args[:fingerprint]} " +
48
+ "#{message} for #{host_keys.host.inspect}")
49
+ exception.data = args
50
+ exception.callback = Proc.new do
51
+ host_keys.add_host_key(args[:key])
52
+ end
53
+ raise exception
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end