net-ssh 4.1.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
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