net-ssh 4.1.0 → 6.1.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 (111) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +5 -0
  5. data/.rubocop.yml +8 -2
  6. data/.rubocop_todo.yml +405 -552
  7. data/.travis.yml +23 -22
  8. data/CHANGES.txt +112 -1
  9. data/Gemfile +1 -7
  10. data/{Gemfile.norbnacl → Gemfile.noed25519} +1 -1
  11. data/Manifest +4 -5
  12. data/README.md +287 -0
  13. data/Rakefile +40 -29
  14. data/appveyor.yml +12 -6
  15. data/lib/net/ssh.rb +68 -32
  16. data/lib/net/ssh/authentication/agent.rb +234 -222
  17. data/lib/net/ssh/authentication/certificate.rb +175 -164
  18. data/lib/net/ssh/authentication/constants.rb +17 -14
  19. data/lib/net/ssh/authentication/ed25519.rb +162 -141
  20. data/lib/net/ssh/authentication/ed25519_loader.rb +32 -29
  21. data/lib/net/ssh/authentication/key_manager.rb +40 -9
  22. data/lib/net/ssh/authentication/methods/abstract.rb +53 -47
  23. data/lib/net/ssh/authentication/methods/hostbased.rb +32 -33
  24. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +1 -1
  25. data/lib/net/ssh/authentication/methods/none.rb +10 -10
  26. data/lib/net/ssh/authentication/methods/password.rb +13 -13
  27. data/lib/net/ssh/authentication/methods/publickey.rb +56 -55
  28. data/lib/net/ssh/authentication/pageant.rb +468 -465
  29. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  30. data/lib/net/ssh/authentication/session.rb +130 -122
  31. data/lib/net/ssh/buffer.rb +345 -312
  32. data/lib/net/ssh/buffered_io.rb +163 -163
  33. data/lib/net/ssh/config.rb +316 -238
  34. data/lib/net/ssh/connection/channel.rb +670 -650
  35. data/lib/net/ssh/connection/constants.rb +30 -26
  36. data/lib/net/ssh/connection/event_loop.rb +108 -105
  37. data/lib/net/ssh/connection/keepalive.rb +54 -50
  38. data/lib/net/ssh/connection/session.rb +682 -671
  39. data/lib/net/ssh/connection/term.rb +180 -176
  40. data/lib/net/ssh/errors.rb +101 -99
  41. data/lib/net/ssh/key_factory.rb +195 -108
  42. data/lib/net/ssh/known_hosts.rb +161 -152
  43. data/lib/net/ssh/loggable.rb +57 -55
  44. data/lib/net/ssh/packet.rb +82 -78
  45. data/lib/net/ssh/prompt.rb +55 -53
  46. data/lib/net/ssh/proxy/command.rb +104 -89
  47. data/lib/net/ssh/proxy/errors.rb +12 -8
  48. data/lib/net/ssh/proxy/http.rb +93 -91
  49. data/lib/net/ssh/proxy/https.rb +42 -39
  50. data/lib/net/ssh/proxy/jump.rb +50 -47
  51. data/lib/net/ssh/proxy/socks4.rb +0 -2
  52. data/lib/net/ssh/proxy/socks5.rb +11 -12
  53. data/lib/net/ssh/service/forward.rb +370 -317
  54. data/lib/net/ssh/test.rb +83 -77
  55. data/lib/net/ssh/test/channel.rb +146 -142
  56. data/lib/net/ssh/test/extensions.rb +150 -146
  57. data/lib/net/ssh/test/kex.rb +35 -31
  58. data/lib/net/ssh/test/local_packet.rb +48 -44
  59. data/lib/net/ssh/test/packet.rb +87 -84
  60. data/lib/net/ssh/test/remote_packet.rb +35 -31
  61. data/lib/net/ssh/test/script.rb +173 -171
  62. data/lib/net/ssh/test/socket.rb +59 -55
  63. data/lib/net/ssh/transport/algorithms.rb +430 -364
  64. data/lib/net/ssh/transport/cipher_factory.rb +95 -91
  65. data/lib/net/ssh/transport/constants.rb +33 -25
  66. data/lib/net/ssh/transport/ctr.rb +33 -11
  67. data/lib/net/ssh/transport/hmac.rb +15 -13
  68. data/lib/net/ssh/transport/hmac/abstract.rb +82 -63
  69. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  70. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  71. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  72. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  73. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  74. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  75. data/lib/net/ssh/transport/identity_cipher.rb +55 -51
  76. data/lib/net/ssh/transport/kex.rb +14 -13
  77. data/lib/net/ssh/transport/kex/abstract.rb +123 -0
  78. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  79. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +38 -0
  80. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  81. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  82. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +112 -217
  83. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -62
  84. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  85. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  86. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  87. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  88. data/lib/net/ssh/transport/key_expander.rb +29 -25
  89. data/lib/net/ssh/transport/openssl.rb +116 -116
  90. data/lib/net/ssh/transport/packet_stream.rb +223 -190
  91. data/lib/net/ssh/transport/server_version.rb +64 -66
  92. data/lib/net/ssh/transport/session.rb +306 -257
  93. data/lib/net/ssh/transport/state.rb +198 -196
  94. data/lib/net/ssh/verifiers/accept_new.rb +35 -0
  95. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +34 -0
  96. data/lib/net/ssh/verifiers/always.rb +56 -0
  97. data/lib/net/ssh/verifiers/never.rb +21 -0
  98. data/lib/net/ssh/version.rb +55 -53
  99. data/net-ssh-public_cert.pem +18 -19
  100. data/net-ssh.gemspec +12 -11
  101. data/support/ssh_tunnel_bug.rb +2 -2
  102. metadata +86 -75
  103. metadata.gz.sig +0 -0
  104. data/Gemfile.norbnacl.lock +0 -41
  105. data/README.rdoc +0 -169
  106. data/lib/net/ssh/ruby_compat.rb +0 -24
  107. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  108. data/lib/net/ssh/verifiers/null.rb +0 -12
  109. data/lib/net/ssh/verifiers/secure.rb +0 -52
  110. data/lib/net/ssh/verifiers/strict.rb +0 -24
  111. data/support/arcfour_check.rb +0 -20
@@ -1,248 +1,281 @@
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'
8
7
 
8
+ module Net
9
+ module SSH
10
+ module Transport
9
11
 
10
- module Net; module SSH; module Transport
12
+ # A module that builds additional functionality onto the Net::SSH::BufferedIo
13
+ # module. It adds SSH encryption, compression, and packet validation, as
14
+ # per the SSH2 protocol. It also adds an abstraction for polling packets,
15
+ # to allow for both blocking and non-blocking reads.
16
+ module PacketStream
17
+ PROXY_COMMAND_HOST_IP = '<no hostip for proxy command>'.freeze
11
18
 
12
- # A module that builds additional functionality onto the Net::SSH::BufferedIo
13
- # module. It adds SSH encryption, compression, and packet validation, as
14
- # per the SSH2 protocol. It also adds an abstraction for polling packets,
15
- # to allow for both blocking and non-blocking reads.
16
- module PacketStream
17
- PROXY_COMMAND_HOST_IP = '<no hostip for proxy command>'.freeze
19
+ include BufferedIo
18
20
 
19
- include BufferedIo
20
-
21
- def self.extended(object)
22
- object.__send__(:initialize_ssh)
23
- end
21
+ def self.extended(object)
22
+ object.__send__(:initialize_ssh)
23
+ end
24
24
 
25
- # The map of "hints" that can be used to modify the behavior of the packet
26
- # stream. For instance, when authentication succeeds, an "authenticated"
27
- # hint is set, which is used to determine whether or not to compress the
28
- # data when using the "delayed" compression algorithm.
29
- attr_reader :hints
30
-
31
- # The server state object, which encapsulates the algorithms used to interpret
32
- # packets coming from the server.
33
- attr_reader :server
34
-
35
- # The client state object, which encapsulates the algorithms used to build
36
- # packets to send to the server.
37
- attr_reader :client
38
-
39
- # The name of the client (local) end of the socket, as reported by the
40
- # socket.
41
- def client_name
42
- @client_name ||= begin
43
- sockaddr = getsockname
44
- begin
45
- Socket.getnameinfo(sockaddr, Socket::NI_NAMEREQD).first
46
- rescue
47
- begin
48
- Socket.getnameinfo(sockaddr).first
49
- rescue
25
+ # The map of "hints" that can be used to modify the behavior of the packet
26
+ # stream. For instance, when authentication succeeds, an "authenticated"
27
+ # hint is set, which is used to determine whether or not to compress the
28
+ # data when using the "delayed" compression algorithm.
29
+ attr_reader :hints
30
+
31
+ # The server state object, which encapsulates the algorithms used to interpret
32
+ # packets coming from the server.
33
+ attr_reader :server
34
+
35
+ # The client state object, which encapsulates the algorithms used to build
36
+ # packets to send to the server.
37
+ attr_reader :client
38
+
39
+ # The name of the client (local) end of the socket, as reported by the
40
+ # socket.
41
+ def client_name
42
+ @client_name ||= begin
43
+ sockaddr = getsockname
50
44
  begin
51
- Socket.gethostbyname(Socket.gethostname).first
52
- rescue
53
- lwarn { "the client ipaddr/name could not be determined" }
54
- "unknown"
45
+ Socket.getnameinfo(sockaddr, Socket::NI_NAMEREQD).first
46
+ rescue StandardError
47
+ begin
48
+ Socket.getnameinfo(sockaddr).first
49
+ rescue StandardError
50
+ begin
51
+ Socket.gethostbyname(Socket.gethostname).first
52
+ rescue StandardError
53
+ lwarn { "the client ipaddr/name could not be determined" }
54
+ "unknown"
55
+ end
56
+ end
55
57
  end
56
58
  end
57
59
  end
58
- end
59
- end
60
60
 
61
- # The IP address of the peer (remote) end of the socket, as reported by
62
- # the socket.
63
- def peer_ip
64
- @peer_ip ||=
65
- if respond_to?(:getpeername)
66
- addr = getpeername
67
- Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
68
- else
69
- PROXY_COMMAND_HOST_IP
61
+ # The IP address of the peer (remote) end of the socket, as reported by
62
+ # the socket.
63
+ def peer_ip
64
+ @peer_ip ||=
65
+ if respond_to?(:getpeername)
66
+ addr = getpeername
67
+ Socket.getnameinfo(addr, Socket::NI_NUMERICHOST | Socket::NI_NUMERICSERV).first
68
+ else
69
+ PROXY_COMMAND_HOST_IP
70
+ end
70
71
  end
71
- end
72
72
 
73
- # Returns true if the IO is available for reading, and false otherwise.
74
- def available_for_read?
75
- result = Net::SSH::Compat.io_select([self], nil, nil, 0)
76
- result && result.first.any?
77
- end
73
+ # Returns true if the IO is available for reading, and false otherwise.
74
+ def available_for_read?
75
+ result = IO.select([self], nil, nil, 0)
76
+ result && result.first.any?
77
+ end
78
78
 
79
- # Returns the next full packet. If the mode parameter is :nonblock (the
80
- # default), then this will return immediately, whether a packet is
81
- # available or not, and will return nil if there is no packet ready to be
82
- # returned. If the mode parameter is :block, then this method will block
83
- # until a packet is available.
84
- def next_packet(mode=:nonblock)
85
- case mode
86
- when :nonblock then
87
- packet = poll_next_packet
88
- return packet if packet
89
-
90
- if available_for_read?
91
- if fill <= 0
92
- result = poll_next_packet
93
- if result.nil?
94
- raise Net::SSH::Disconnect, "connection closed by remote host"
95
- else
96
- return result
79
+ # Returns the next full packet. If the mode parameter is :nonblock (the
80
+ # default), then this will return immediately, whether a packet is
81
+ # available or not, and will return nil if there is no packet ready to be
82
+ # returned. If the mode parameter is :block, then this method will block
83
+ # until a packet is available or timeout seconds have passed.
84
+ def next_packet(mode=:nonblock, timeout=nil)
85
+ case mode
86
+ when :nonblock then
87
+ packet = poll_next_packet
88
+ return packet if packet
89
+
90
+ if available_for_read?
91
+ if fill <= 0
92
+ result = poll_next_packet
93
+ if result.nil?
94
+ raise Net::SSH::Disconnect, "connection closed by remote host"
95
+ else
96
+ return result
97
+ end
98
+ end
97
99
  end
98
- end
99
- end
100
- poll_next_packet
100
+ poll_next_packet
101
101
 
102
- when :block then
103
- loop do
104
- packet = poll_next_packet
105
- return packet if packet
102
+ when :block then
103
+ loop do
104
+ packet = poll_next_packet
105
+ return packet if packet
106
106
 
107
- loop do
108
- result = Net::SSH::Compat.io_select([self]) or next
109
- break if result.first.any?
110
- end
107
+ result = IO.select([self], nil, nil, timeout)
108
+ raise Net::SSH::ConnectionTimeout, "timeout waiting for next packet" unless result
109
+ raise Net::SSH::Disconnect, "connection closed by remote host" if fill <= 0
110
+ end
111
111
 
112
- if fill <= 0
113
- raise Net::SSH::Disconnect, "connection closed by remote host"
112
+ else
113
+ raise ArgumentError, "expected :block or :nonblock, got #{mode.inspect}"
114
114
  end
115
115
  end
116
116
 
117
- else
118
- raise ArgumentError, "expected :block or :nonblock, got #{mode.inspect}"
119
- end
120
- end
117
+ # Enqueues a packet to be sent, and blocks until the entire packet is
118
+ # sent.
119
+ def send_packet(payload)
120
+ enqueue_packet(payload)
121
+ wait_for_pending_sends
122
+ end
121
123
 
122
- # Enqueues a packet to be sent, and blocks until the entire packet is
123
- # sent.
124
- def send_packet(payload)
125
- enqueue_packet(payload)
126
- wait_for_pending_sends
127
- end
124
+ # Enqueues a packet to be sent, but does not immediately send the packet.
125
+ # The given payload is pre-processed according to the algorithms specified
126
+ # in the client state (compression, cipher, and hmac).
127
+ def enqueue_packet(payload)
128
+ # try to compress the packet
129
+ payload = client.compress(payload)
128
130
 
129
- # Enqueues a packet to be sent, but does not immediately send the packet.
130
- # The given payload is pre-processed according to the algorithms specified
131
- # in the client state (compression, cipher, and hmac).
132
- def enqueue_packet(payload)
133
- # try to compress the packet
134
- payload = client.compress(payload)
131
+ # the length of the packet, minus the padding
132
+ actual_length = (client.hmac.etm ? 0 : 4) + payload.bytesize + 1
135
133
 
136
- # the length of the packet, minus the padding
137
- actual_length = 4 + payload.bytesize + 1
134
+ # compute the padding length
135
+ padding_length = client.block_size - (actual_length % client.block_size)
136
+ padding_length += client.block_size if padding_length < 4
138
137
 
139
- # compute the padding length
140
- padding_length = client.block_size - (actual_length % client.block_size)
141
- padding_length += client.block_size if padding_length < 4
138
+ # compute the packet length (sans the length field itself)
139
+ packet_length = payload.bytesize + padding_length + 1
142
140
 
143
- # compute the packet length (sans the length field itself)
144
- packet_length = payload.bytesize + padding_length + 1
141
+ if packet_length < 16
142
+ padding_length += client.block_size
143
+ packet_length = payload.bytesize + padding_length + 1
144
+ end
145
145
 
146
- if packet_length < 16
147
- padding_length += client.block_size
148
- packet_length = payload.bytesize + padding_length + 1
149
- end
146
+ padding = Array.new(padding_length) { rand(256) }.pack("C*")
150
147
 
151
- padding = Array.new(padding_length) { rand(256) }.pack("C*")
148
+ if client.hmac.etm
149
+ debug { "using encrypt-then-mac" }
152
150
 
153
- unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
154
- mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))
151
+ # Encrypt padding_length, payload, and padding. Take MAC
152
+ # from the unencrypted packet_lenght and the encrypted
153
+ # data.
154
+ length_data = [packet_length].pack("N")
155
155
 
156
- encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
157
- message = encrypted_data + mac
156
+ unencrypted_data = [padding_length, payload, padding].pack("CA*A*")
158
157
 
159
- debug { "queueing packet nr #{client.sequence_number} type #{payload.getbyte(0)} len #{packet_length}" }
160
- enqueue(message)
158
+ encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
161
159
 
162
- client.increment(packet_length)
160
+ mac_data = length_data + encrypted_data
163
161
 
164
- self
165
- end
162
+ mac = client.hmac.digest([client.sequence_number, mac_data].pack("NA*"))
166
163
 
167
- # Performs any pending cleanup necessary on the IO and its associated
168
- # state objects. (See State#cleanup).
169
- def cleanup
170
- client.cleanup
171
- server.cleanup
172
- end
164
+ message = mac_data + mac
165
+ else
166
+ unencrypted_data = [packet_length, padding_length, payload, padding].pack("NCA*A*")
173
167
 
174
- # If the IO object requires a rekey operation (as indicated by either its
175
- # client or server state objects, see State#needs_rekey?), this will
176
- # yield. Otherwise, this does nothing.
177
- def if_needs_rekey?
178
- if client.needs_rekey? || server.needs_rekey?
179
- yield
180
- client.reset! if client.needs_rekey?
181
- server.reset! if server.needs_rekey?
182
- end
183
- end
168
+ mac = client.hmac.digest([client.sequence_number, unencrypted_data].pack("NA*"))
184
169
 
185
- protected
170
+ encrypted_data = client.update_cipher(unencrypted_data) << client.final_cipher
186
171
 
187
- # Called when this module is used to extend an object. It initializes
188
- # the states and generally prepares the object for use as a packet stream.
189
- def initialize_ssh
190
- @hints = {}
191
- @server = State.new(self, :server)
192
- @client = State.new(self, :client)
193
- @packet = nil
194
- initialize_buffered_io
195
- end
172
+ message = encrypted_data + mac
173
+ end
174
+
175
+ debug { "queueing packet nr #{client.sequence_number} type #{payload.getbyte(0)} len #{packet_length}" }
176
+ enqueue(message)
177
+
178
+ client.increment(packet_length)
196
179
 
197
- # Tries to read the next packet. If there is insufficient data to read
198
- # an entire packet, this returns immediately, otherwise the packet is
199
- # read, post-processed according to the cipher, hmac, and compression
200
- # algorithms specified in the server state object, and returned as a
201
- # new Packet object.
202
- def poll_next_packet
203
- if @packet.nil?
204
- minimum = server.block_size < 4 ? 4 : server.block_size
205
- return nil if available < minimum
206
- data = read_available(minimum)
207
-
208
- # decipher it
209
- @packet = Net::SSH::Buffer.new(server.update_cipher(data))
210
- @packet_length = @packet.read_long
180
+ self
211
181
  end
212
182
 
213
- need = @packet_length + 4 - server.block_size
214
- raise Net::SSH::Exception, "padding error, need #{need} block #{server.block_size}" if need % server.block_size != 0
183
+ # Performs any pending cleanup necessary on the IO and its associated
184
+ # state objects. (See State#cleanup).
185
+ def cleanup
186
+ client.cleanup
187
+ server.cleanup
188
+ end
215
189
 
216
- return nil if available < need + server.hmac.mac_length
190
+ # If the IO object requires a rekey operation (as indicated by either its
191
+ # client or server state objects, see State#needs_rekey?), this will
192
+ # yield. Otherwise, this does nothing.
193
+ def if_needs_rekey?
194
+ if client.needs_rekey? || server.needs_rekey?
195
+ yield
196
+ client.reset! if client.needs_rekey?
197
+ server.reset! if server.needs_rekey?
198
+ end
199
+ end
217
200
 
218
- if need > 0
219
- # read the remainder of the packet and decrypt it.
220
- data = read_available(need)
221
- @packet.append(server.update_cipher(data))
201
+ protected
202
+
203
+ # Called when this module is used to extend an object. It initializes
204
+ # the states and generally prepares the object for use as a packet stream.
205
+ def initialize_ssh
206
+ @hints = {}
207
+ @server = State.new(self, :server)
208
+ @client = State.new(self, :client)
209
+ @packet = nil
210
+ initialize_buffered_io
222
211
  end
223
212
 
224
- # get the hmac from the tail of the packet (if one exists), and
225
- # then validate it.
226
- real_hmac = read_available(server.hmac.mac_length) || ""
213
+ # Tries to read the next packet. If there is insufficient data to read
214
+ # an entire packet, this returns immediately, otherwise the packet is
215
+ # read, post-processed according to the cipher, hmac, and compression
216
+ # algorithms specified in the server state object, and returned as a
217
+ # new Packet object.
218
+ # rubocop:disable Metrics/AbcSize
219
+ def poll_next_packet
220
+ aad_length = server.hmac.etm ? 4 : 0
221
+
222
+ if @packet.nil?
223
+ minimum = server.block_size < 4 ? 4 : server.block_size
224
+ return nil if available < minimum + aad_length
225
+ data = read_available(minimum + aad_length)
226
+
227
+ # decipher it
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
236
+ end
237
+
238
+ need = @packet_length + 4 - aad_length - server.block_size
239
+ raise Net::SSH::Exception, "padding error, need #{need} block #{server.block_size}" if need % server.block_size != 0
240
+
241
+ return nil if available < need + server.hmac.mac_length
242
+
243
+ if need > 0
244
+ # read the remainder of the packet and decrypt it.
245
+ data = read_available(need)
246
+ @mac_data += data if server.hmac.etm
247
+ @packet.append(server.update_cipher(data))
248
+ end
227
249
 
228
- @packet.append(server.final_cipher)
229
- padding_length = @packet.read_byte
250
+ # get the hmac from the tail of the packet (if one exists), and
251
+ # then validate it.
252
+ real_hmac = read_available(server.hmac.mac_length) || ""
230
253
 
231
- payload = @packet.read(@packet_length - padding_length - 1)
254
+ @packet.append(server.final_cipher)
255
+ padding_length = @packet.read_byte
232
256
 
233
- my_computed_hmac = server.hmac.digest([server.sequence_number, @packet.content].pack("NA*"))
234
- raise Net::SSH::Exception, "corrupted mac detected" if real_hmac != my_computed_hmac
257
+ payload = @packet.read(@packet_length - padding_length - 1)
235
258
 
236
- # try to decompress the payload, in case compression is active
237
- payload = server.decompress(payload)
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
238
265
 
239
- debug { "received packet nr #{server.sequence_number} type #{payload.getbyte(0)} len #{@packet_length}" }
266
+ # try to decompress the payload, in case compression is active
267
+ payload = server.decompress(payload)
240
268
 
241
- server.increment(@packet_length)
242
- @packet = nil
269
+ debug { "received packet nr #{server.sequence_number} type #{payload.getbyte(0)} len #{@packet_length}" }
243
270
 
244
- return Packet.new(payload)
271
+ server.increment(@packet_length)
272
+ @packet = nil
273
+
274
+ return Packet.new(payload)
275
+ end
245
276
  end
246
- end
277
+ # rubocop:enable Metrics/AbcSize
247
278
 
248
- end; end; end
279
+ end
280
+ end
281
+ end