net-ssh 3.2.0 → 7.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data/.dockerignore +6 -0
  4. data/.github/FUNDING.yml +1 -0
  5. data/.github/config/rubocop_linter_action.yml +4 -0
  6. data/.github/workflows/ci-with-docker.yml +44 -0
  7. data/.github/workflows/ci.yml +93 -0
  8. data/.github/workflows/rubocop.yml +16 -0
  9. data/.gitignore +13 -0
  10. data/.rubocop.yml +22 -0
  11. data/.rubocop_todo.yml +1081 -0
  12. data/CHANGES.txt +237 -7
  13. data/DEVELOPMENT.md +23 -0
  14. data/Dockerfile +27 -0
  15. data/Dockerfile.openssl3 +17 -0
  16. data/Gemfile +13 -0
  17. data/Gemfile.noed25519 +12 -0
  18. data/Gemfile.norbnacl +12 -0
  19. data/ISSUE_TEMPLATE.md +30 -0
  20. data/Manifest +4 -5
  21. data/README.md +298 -0
  22. data/Rakefile +125 -74
  23. data/SECURITY.md +4 -0
  24. data/appveyor.yml +58 -0
  25. data/docker-compose.yml +23 -0
  26. data/lib/net/ssh/authentication/agent.rb +279 -18
  27. data/lib/net/ssh/authentication/certificate.rb +183 -0
  28. data/lib/net/ssh/authentication/constants.rb +17 -15
  29. data/lib/net/ssh/authentication/ed25519.rb +186 -0
  30. data/lib/net/ssh/authentication/ed25519_loader.rb +31 -0
  31. data/lib/net/ssh/authentication/key_manager.rb +86 -39
  32. data/lib/net/ssh/authentication/methods/abstract.rb +67 -48
  33. data/lib/net/ssh/authentication/methods/hostbased.rb +34 -37
  34. data/lib/net/ssh/authentication/methods/keyboard_interactive.rb +13 -13
  35. data/lib/net/ssh/authentication/methods/none.rb +16 -19
  36. data/lib/net/ssh/authentication/methods/password.rb +27 -17
  37. data/lib/net/ssh/authentication/methods/publickey.rb +96 -55
  38. data/lib/net/ssh/authentication/pageant.rb +471 -367
  39. data/lib/net/ssh/authentication/pub_key_fingerprint.rb +43 -0
  40. data/lib/net/ssh/authentication/session.rb +131 -121
  41. data/lib/net/ssh/buffer.rb +399 -300
  42. data/lib/net/ssh/buffered_io.rb +154 -150
  43. data/lib/net/ssh/config.rb +308 -185
  44. data/lib/net/ssh/connection/channel.rb +635 -613
  45. data/lib/net/ssh/connection/constants.rb +29 -29
  46. data/lib/net/ssh/connection/event_loop.rb +123 -0
  47. data/lib/net/ssh/connection/keepalive.rb +55 -51
  48. data/lib/net/ssh/connection/session.rb +620 -551
  49. data/lib/net/ssh/connection/term.rb +125 -123
  50. data/lib/net/ssh/errors.rb +101 -99
  51. data/lib/net/ssh/key_factory.rb +197 -105
  52. data/lib/net/ssh/known_hosts.rb +214 -127
  53. data/lib/net/ssh/loggable.rb +50 -49
  54. data/lib/net/ssh/packet.rb +83 -79
  55. data/lib/net/ssh/prompt.rb +50 -81
  56. data/lib/net/ssh/proxy/command.rb +105 -90
  57. data/lib/net/ssh/proxy/errors.rb +12 -10
  58. data/lib/net/ssh/proxy/http.rb +82 -79
  59. data/lib/net/ssh/proxy/https.rb +50 -0
  60. data/lib/net/ssh/proxy/jump.rb +54 -0
  61. data/lib/net/ssh/proxy/socks4.rb +2 -6
  62. data/lib/net/ssh/proxy/socks5.rb +14 -17
  63. data/lib/net/ssh/service/forward.rb +370 -317
  64. data/lib/net/ssh/test/channel.rb +145 -136
  65. data/lib/net/ssh/test/extensions.rb +131 -110
  66. data/lib/net/ssh/test/kex.rb +34 -32
  67. data/lib/net/ssh/test/local_packet.rb +46 -44
  68. data/lib/net/ssh/test/packet.rb +89 -70
  69. data/lib/net/ssh/test/remote_packet.rb +32 -30
  70. data/lib/net/ssh/test/script.rb +156 -142
  71. data/lib/net/ssh/test/socket.rb +49 -48
  72. data/lib/net/ssh/test.rb +82 -77
  73. data/lib/net/ssh/transport/algorithms.rb +462 -359
  74. data/lib/net/ssh/transport/chacha20_poly1305_cipher.rb +117 -0
  75. data/lib/net/ssh/transport/chacha20_poly1305_cipher_loader.rb +17 -0
  76. data/lib/net/ssh/transport/cipher_factory.rb +122 -99
  77. data/lib/net/ssh/transport/constants.rb +32 -24
  78. data/lib/net/ssh/transport/ctr.rb +42 -22
  79. data/lib/net/ssh/transport/hmac/abstract.rb +81 -63
  80. data/lib/net/ssh/transport/hmac/md5.rb +0 -2
  81. data/lib/net/ssh/transport/hmac/md5_96.rb +0 -2
  82. data/lib/net/ssh/transport/hmac/none.rb +0 -2
  83. data/lib/net/ssh/transport/hmac/ripemd160.rb +0 -2
  84. data/lib/net/ssh/transport/hmac/sha1.rb +0 -2
  85. data/lib/net/ssh/transport/hmac/sha1_96.rb +0 -2
  86. data/lib/net/ssh/transport/hmac/sha2_256.rb +7 -11
  87. data/lib/net/ssh/transport/hmac/sha2_256_96.rb +4 -8
  88. data/lib/net/ssh/transport/hmac/sha2_256_etm.rb +12 -0
  89. data/lib/net/ssh/transport/hmac/sha2_512.rb +6 -9
  90. data/lib/net/ssh/transport/hmac/sha2_512_96.rb +4 -8
  91. data/lib/net/ssh/transport/hmac/sha2_512_etm.rb +12 -0
  92. data/lib/net/ssh/transport/hmac.rb +14 -12
  93. data/lib/net/ssh/transport/identity_cipher.rb +54 -44
  94. data/lib/net/ssh/transport/kex/abstract.rb +130 -0
  95. data/lib/net/ssh/transport/kex/abstract5656.rb +72 -0
  96. data/lib/net/ssh/transport/kex/curve25519_sha256.rb +39 -0
  97. data/lib/net/ssh/transport/kex/curve25519_sha256_loader.rb +30 -0
  98. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha1.rb +33 -40
  99. data/lib/net/ssh/transport/kex/diffie_hellman_group14_sha256.rb +11 -0
  100. data/lib/net/ssh/transport/kex/diffie_hellman_group1_sha1.rb +119 -213
  101. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha1.rb +53 -61
  102. data/lib/net/ssh/transport/kex/diffie_hellman_group_exchange_sha256.rb +5 -9
  103. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp256.rb +36 -90
  104. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp384.rb +18 -10
  105. data/lib/net/ssh/transport/kex/ecdh_sha2_nistp521.rb +18 -10
  106. data/lib/net/ssh/transport/kex.rb +15 -12
  107. data/lib/net/ssh/transport/key_expander.rb +24 -20
  108. data/lib/net/ssh/transport/openssl.rb +161 -124
  109. data/lib/net/ssh/transport/openssl_cipher_extensions.rb +8 -0
  110. data/lib/net/ssh/transport/packet_stream.rb +246 -185
  111. data/lib/net/ssh/transport/server_version.rb +55 -56
  112. data/lib/net/ssh/transport/session.rb +306 -255
  113. data/lib/net/ssh/transport/state.rb +178 -176
  114. data/lib/net/ssh/verifiers/accept_new.rb +33 -0
  115. data/lib/net/ssh/verifiers/accept_new_or_local_tunnel.rb +33 -0
  116. data/lib/net/ssh/verifiers/always.rb +58 -0
  117. data/lib/net/ssh/verifiers/never.rb +19 -0
  118. data/lib/net/ssh/version.rb +55 -53
  119. data/lib/net/ssh.rb +111 -47
  120. data/net-ssh-public_cert.pem +18 -18
  121. data/net-ssh.gemspec +38 -205
  122. data/support/ssh_tunnel_bug.rb +5 -5
  123. data.tar.gz.sig +0 -0
  124. metadata +173 -118
  125. metadata.gz.sig +0 -0
  126. data/.travis.yml +0 -18
  127. data/README.rdoc +0 -182
  128. data/lib/net/ssh/authentication/agent/java_pageant.rb +0 -85
  129. data/lib/net/ssh/authentication/agent/socket.rb +0 -178
  130. data/lib/net/ssh/ruby_compat.rb +0 -46
  131. data/lib/net/ssh/verifiers/lenient.rb +0 -30
  132. data/lib/net/ssh/verifiers/null.rb +0 -12
  133. data/lib/net/ssh/verifiers/secure.rb +0 -52
  134. data/lib/net/ssh/verifiers/strict.rb +0 -24
  135. data/setup.rb +0 -1585
  136. data/support/arcfour_check.rb +0 -20
  137. data/test/README.txt +0 -18
  138. data/test/authentication/methods/common.rb +0 -28
  139. data/test/authentication/methods/test_abstract.rb +0 -51
  140. data/test/authentication/methods/test_hostbased.rb +0 -114
  141. data/test/authentication/methods/test_keyboard_interactive.rb +0 -121
  142. data/test/authentication/methods/test_none.rb +0 -41
  143. data/test/authentication/methods/test_password.rb +0 -95
  144. data/test/authentication/methods/test_publickey.rb +0 -148
  145. data/test/authentication/test_agent.rb +0 -232
  146. data/test/authentication/test_key_manager.rb +0 -240
  147. data/test/authentication/test_session.rb +0 -107
  148. data/test/common.rb +0 -125
  149. data/test/configs/auth_off +0 -5
  150. data/test/configs/auth_on +0 -4
  151. data/test/configs/empty +0 -0
  152. data/test/configs/eqsign +0 -3
  153. data/test/configs/exact_match +0 -8
  154. data/test/configs/host_plus +0 -10
  155. data/test/configs/multihost +0 -4
  156. data/test/configs/negative_match +0 -6
  157. data/test/configs/nohost +0 -19
  158. data/test/configs/numeric_host +0 -4
  159. data/test/configs/proxy_remote_user +0 -2
  160. data/test/configs/send_env +0 -2
  161. data/test/configs/substitutes +0 -8
  162. data/test/configs/wild_cards +0 -14
  163. data/test/connection/test_channel.rb +0 -487
  164. data/test/connection/test_session.rb +0 -564
  165. data/test/integration/README.txt +0 -17
  166. data/test/integration/Vagrantfile +0 -12
  167. data/test/integration/common.rb +0 -63
  168. data/test/integration/playbook.yml +0 -56
  169. data/test/integration/test_forward.rb +0 -637
  170. data/test/integration/test_id_rsa_keys.rb +0 -96
  171. data/test/integration/test_proxy.rb +0 -93
  172. data/test/known_hosts/github +0 -1
  173. data/test/known_hosts/github_hash +0 -1
  174. data/test/manual/test_pageant.rb +0 -37
  175. data/test/start/test_connection.rb +0 -53
  176. data/test/start/test_options.rb +0 -57
  177. data/test/start/test_transport.rb +0 -28
  178. data/test/start/test_user_nil.rb +0 -27
  179. data/test/test_all.rb +0 -12
  180. data/test/test_buffer.rb +0 -433
  181. data/test/test_buffered_io.rb +0 -63
  182. data/test/test_config.rb +0 -268
  183. data/test/test_key_factory.rb +0 -191
  184. data/test/test_known_hosts.rb +0 -66
  185. data/test/transport/hmac/test_md5.rb +0 -41
  186. data/test/transport/hmac/test_md5_96.rb +0 -27
  187. data/test/transport/hmac/test_none.rb +0 -34
  188. data/test/transport/hmac/test_ripemd160.rb +0 -36
  189. data/test/transport/hmac/test_sha1.rb +0 -36
  190. data/test/transport/hmac/test_sha1_96.rb +0 -27
  191. data/test/transport/hmac/test_sha2_256.rb +0 -37
  192. data/test/transport/hmac/test_sha2_256_96.rb +0 -27
  193. data/test/transport/hmac/test_sha2_512.rb +0 -37
  194. data/test/transport/hmac/test_sha2_512_96.rb +0 -27
  195. data/test/transport/kex/test_diffie_hellman_group14_sha1.rb +0 -13
  196. data/test/transport/kex/test_diffie_hellman_group1_sha1.rb +0 -150
  197. data/test/transport/kex/test_diffie_hellman_group_exchange_sha1.rb +0 -96
  198. data/test/transport/kex/test_diffie_hellman_group_exchange_sha256.rb +0 -19
  199. data/test/transport/kex/test_ecdh_sha2_nistp256.rb +0 -161
  200. data/test/transport/kex/test_ecdh_sha2_nistp384.rb +0 -38
  201. data/test/transport/kex/test_ecdh_sha2_nistp521.rb +0 -38
  202. data/test/transport/test_algorithms.rb +0 -328
  203. data/test/transport/test_cipher_factory.rb +0 -443
  204. data/test/transport/test_hmac.rb +0 -34
  205. data/test/transport/test_identity_cipher.rb +0 -40
  206. data/test/transport/test_packet_stream.rb +0 -1762
  207. data/test/transport/test_server_version.rb +0 -74
  208. data/test/transport/test_session.rb +0 -331
  209. data/test/transport/test_state.rb +0 -181
  210. data/test/verifiers/test_secure.rb +0 -40
@@ -5,417 +5,520 @@ require 'net/ssh/transport/cipher_factory'
5
5
  require 'net/ssh/transport/constants'
6
6
  require 'net/ssh/transport/hmac'
7
7
  require 'net/ssh/transport/kex'
8
+ require 'net/ssh/transport/kex/curve25519_sha256_loader'
8
9
  require 'net/ssh/transport/server_version'
10
+ require 'net/ssh/authentication/ed25519_loader'
11
+
12
+ module Net
13
+ module SSH
14
+ module Transport
15
+ # Implements the higher-level logic behind an SSH key-exchange. It handles
16
+ # both the initial exchange, as well as subsequent re-exchanges (as needed).
17
+ # It also encapsulates the negotiation of the algorithms, and provides a
18
+ # single point of access to the negotiated algorithms.
19
+ #
20
+ # You will never instantiate or reference this directly. It is used
21
+ # internally by the transport layer.
22
+ class Algorithms
23
+ include Loggable
24
+ include Constants
25
+
26
+ # Define the default algorithms, in order of preference, supported by Net::SSH.
27
+ DEFAULT_ALGORITHMS = {
28
+ host_key: %w[ecdsa-sha2-nistp521-cert-v01@openssh.com
29
+ ecdsa-sha2-nistp384-cert-v01@openssh.com
30
+ ecdsa-sha2-nistp256-cert-v01@openssh.com
31
+ ecdsa-sha2-nistp521
32
+ ecdsa-sha2-nistp384
33
+ ecdsa-sha2-nistp256
34
+ ssh-rsa-cert-v01@openssh.com
35
+ ssh-rsa-cert-v00@openssh.com
36
+ ssh-rsa
37
+ rsa-sha2-256
38
+ rsa-sha2-512],
39
+
40
+ kex: %w[ecdh-sha2-nistp521
41
+ ecdh-sha2-nistp384
42
+ ecdh-sha2-nistp256
43
+ diffie-hellman-group-exchange-sha256
44
+ diffie-hellman-group14-sha256
45
+ diffie-hellman-group14-sha1],
46
+
47
+ encryption: %w[aes256-ctr aes192-ctr aes128-ctr],
48
+
49
+ hmac: %w[hmac-sha2-512-etm@openssh.com hmac-sha2-256-etm@openssh.com
50
+ hmac-sha2-512 hmac-sha2-256
51
+ hmac-sha1]
52
+ }.freeze
53
+
54
+ if Net::SSH::Transport::ChaCha20Poly1305CipherLoader::LOADED
55
+ DEFAULT_ALGORITHMS[:encryption].unshift(
56
+ 'chacha20-poly1305@openssh.com'
57
+ )
58
+ end
59
+ if Net::SSH::Authentication::ED25519Loader::LOADED
60
+ DEFAULT_ALGORITHMS[:host_key].unshift(
61
+ 'ssh-ed25519-cert-v01@openssh.com',
62
+ 'ssh-ed25519'
63
+ )
64
+ end
9
65
 
10
- module Net; module SSH; module Transport
11
-
12
- # Implements the higher-level logic behind an SSH key-exchange. It handles
13
- # both the initial exchange, as well as subsequent re-exchanges (as needed).
14
- # It also encapsulates the negotiation of the algorithms, and provides a
15
- # single point of access to the negotiated algorithms.
16
- #
17
- # You will never instantiate or reference this directly. It is used
18
- # internally by the transport layer.
19
- class Algorithms
20
- include Constants, Loggable
21
-
22
- # Define the default algorithms, in order of preference, supported by
23
- # Net::SSH.
24
- ALGORITHMS = {
25
- :host_key => %w(ssh-rsa ssh-dss
26
- ssh-rsa-cert-v01@openssh.com
27
- ssh-rsa-cert-v00@openssh.com),
28
- :kex => %w(diffie-hellman-group-exchange-sha1
29
- diffie-hellman-group1-sha1
30
- diffie-hellman-group14-sha1
31
- diffie-hellman-group-exchange-sha256),
32
- :encryption => %w(aes128-cbc 3des-cbc blowfish-cbc cast128-cbc
33
- aes192-cbc aes256-cbc rijndael-cbc@lysator.liu.se
34
- idea-cbc none arcfour128 arcfour256 arcfour
35
- aes128-ctr aes192-ctr aes256-ctr
36
- camellia128-cbc camellia192-cbc camellia256-cbc
37
- camellia128-cbc@openssh.org
38
- camellia192-cbc@openssh.org
39
- camellia256-cbc@openssh.org
40
- camellia128-ctr camellia192-ctr camellia256-ctr
41
- camellia128-ctr@openssh.org
42
- camellia192-ctr@openssh.org
43
- camellia256-ctr@openssh.org
44
- cast128-ctr blowfish-ctr 3des-ctr
45
- ),
46
-
47
- :hmac => %w(hmac-sha1 hmac-md5 hmac-sha1-96 hmac-md5-96
48
- hmac-ripemd160 hmac-ripemd160@openssh.com
49
- hmac-sha2-256 hmac-sha2-512 hmac-sha2-256-96
50
- hmac-sha2-512-96 none),
51
-
52
- :compression => %w(none zlib@openssh.com zlib),
53
- :language => %w()
54
- }
55
- if defined?(OpenSSL::PKey::EC)
56
- ALGORITHMS[:host_key] += %w(ecdsa-sha2-nistp256
57
- ecdsa-sha2-nistp384
58
- ecdsa-sha2-nistp521)
59
- ALGORITHMS[:kex] += %w(ecdh-sha2-nistp256
60
- ecdh-sha2-nistp384
61
- ecdh-sha2-nistp521)
62
- end
66
+ if Net::SSH::Transport::Kex::Curve25519Sha256Loader::LOADED
67
+ DEFAULT_ALGORITHMS[:kex].unshift(
68
+ 'curve25519-sha256',
69
+ 'curve25519-sha256@libssh.org'
70
+ )
71
+ end
63
72
 
64
- # The underlying transport layer session that supports this object
65
- attr_reader :session
73
+ # Define all algorithms, with the deprecated, supported by Net::SSH.
74
+ ALGORITHMS = {
75
+ host_key: DEFAULT_ALGORITHMS[:host_key] + %w[ssh-dss],
66
76
 
67
- # The hash of options used to initialize this object
68
- attr_reader :options
77
+ kex: DEFAULT_ALGORITHMS[:kex] +
78
+ %w[diffie-hellman-group-exchange-sha1
79
+ diffie-hellman-group1-sha1],
69
80
 
70
- # The kex algorithm to use settled on between the client and server.
71
- attr_reader :kex
81
+ encryption: DEFAULT_ALGORITHMS[:encryption] +
82
+ %w[aes256-cbc aes192-cbc aes128-cbc
83
+ rijndael-cbc@lysator.liu.se
84
+ blowfish-ctr blowfish-cbc
85
+ cast128-ctr cast128-cbc
86
+ 3des-ctr 3des-cbc
87
+ idea-cbc
88
+ none],
72
89
 
73
- # The type of host key that will be used for this session.
74
- attr_reader :host_key
90
+ hmac: DEFAULT_ALGORITHMS[:hmac] +
91
+ %w[hmac-sha2-512-96 hmac-sha2-256-96
92
+ hmac-sha1-96
93
+ hmac-ripemd160 hmac-ripemd160@openssh.com
94
+ hmac-md5 hmac-md5-96
95
+ none],
75
96
 
76
- # The type of the cipher to use to encrypt packets sent from the client to
77
- # the server.
78
- attr_reader :encryption_client
97
+ compression: %w[none zlib@openssh.com zlib],
98
+ language: %w[]
99
+ }.freeze
79
100
 
80
- # The type of the cipher to use to decrypt packets arriving from the server.
81
- attr_reader :encryption_server
101
+ # The underlying transport layer session that supports this object
102
+ attr_reader :session
82
103
 
83
- # The type of HMAC to use to sign packets sent by the client.
84
- attr_reader :hmac_client
104
+ # The hash of options used to initialize this object
105
+ attr_reader :options
85
106
 
86
- # The type of HMAC to use to validate packets arriving from the server.
87
- attr_reader :hmac_server
107
+ # The kex algorithm to use settled on between the client and server.
108
+ attr_reader :kex
88
109
 
89
- # The type of compression to use to compress packets being sent by the client.
90
- attr_reader :compression_client
110
+ # The type of host key that will be used for this session.
111
+ attr_reader :host_key
91
112
 
92
- # The type of compression to use to decompress packets arriving from the server.
93
- attr_reader :compression_server
113
+ # The type of the cipher to use to encrypt packets sent from the client to
114
+ # the server.
115
+ attr_reader :encryption_client
94
116
 
95
- # The language that will be used in messages sent by the client.
96
- attr_reader :language_client
117
+ # The type of the cipher to use to decrypt packets arriving from the server.
118
+ attr_reader :encryption_server
97
119
 
98
- # The language that will be used in messages sent from the server.
99
- attr_reader :language_server
120
+ # The type of HMAC to use to sign packets sent by the client.
121
+ attr_reader :hmac_client
100
122
 
101
- # The hash of algorithms preferred by the client, which will be told to
102
- # the server during algorithm negotiation.
103
- attr_reader :algorithms
123
+ # The type of HMAC to use to validate packets arriving from the server.
124
+ attr_reader :hmac_server
104
125
 
105
- # The session-id for this session, as decided during the initial key exchange.
106
- attr_reader :session_id
126
+ # The type of compression to use to compress packets being sent by the client.
127
+ attr_reader :compression_client
107
128
 
108
- # Returns true if the given packet can be processed during a key-exchange.
109
- def self.allowed_packet?(packet)
110
- ( 1.. 4).include?(packet.type) ||
111
- ( 6..19).include?(packet.type) ||
112
- (21..49).include?(packet.type)
113
- end
129
+ # The type of compression to use to decompress packets arriving from the server.
130
+ attr_reader :compression_server
114
131
 
115
- # Instantiates a new Algorithms object, and prepares the hash of preferred
116
- # algorithms based on the options parameter and the ALGORITHMS constant.
117
- def initialize(session, options={})
118
- @session = session
119
- @logger = session.logger
120
- @options = options
121
- @algorithms = {}
122
- @pending = @initialized = false
123
- @client_packet = @server_packet = nil
124
- prepare_preferred_algorithms!
125
- end
132
+ # The language that will be used in messages sent by the client.
133
+ attr_reader :language_client
126
134
 
127
- # Start the algorithm negotation
128
- def start
129
- raise ArgumentError, "Cannot call start if it's negoitation started or done" if @pending || @initialized
130
- send_kexinit
131
- end
135
+ # The language that will be used in messages sent from the server.
136
+ attr_reader :language_server
132
137
 
133
- # Request a rekey operation. This will return immediately, and does not
134
- # actually perform the rekey operation. It does cause the session to change
135
- # state, however--until the key exchange finishes, no new packets will be
136
- # processed.
137
- def rekey!
138
- @client_packet = @server_packet = nil
139
- @initialized = false
140
- send_kexinit
141
- end
138
+ # The hash of algorithms preferred by the client, which will be told to
139
+ # the server during algorithm negotiation.
140
+ attr_reader :algorithms
142
141
 
143
- # Called by the transport layer when a KEXINIT packet is recieved, indicating
144
- # that the server wants to exchange keys. This can be spontaneous, or it
145
- # can be in response to a client-initiated rekey request (see #rekey!). Either
146
- # way, this will block until the key exchange completes.
147
- def accept_kexinit(packet)
148
- info { "got KEXINIT from server" }
149
- @server_data = parse_server_algorithm_packet(packet)
150
- @server_packet = @server_data[:raw]
151
- if !pending?
152
- send_kexinit
153
- else
154
- proceed!
155
- end
156
- end
142
+ # The session-id for this session, as decided during the initial key exchange.
143
+ attr_reader :session_id
157
144
 
158
- # A convenience method for accessing the list of preferred types for a
159
- # specific algorithm (see #algorithms).
160
- def [](key)
161
- algorithms[key]
162
- end
145
+ # Returns true if the given packet can be processed during a key-exchange.
146
+ def self.allowed_packet?(packet)
147
+ (1..4).include?(packet.type) ||
148
+ (6..19).include?(packet.type) ||
149
+ (21..49).include?(packet.type)
150
+ end
163
151
 
164
- # Returns +true+ if a key-exchange is pending. This will be true from the
165
- # moment either the client or server requests the key exchange, until the
166
- # exchange completes. While an exchange is pending, only a limited number
167
- # of packets are allowed, so event processing essentially stops during this
168
- # period.
169
- def pending?
170
- @pending
171
- end
152
+ # Instantiates a new Algorithms object, and prepares the hash of preferred
153
+ # algorithms based on the options parameter and the ALGORITHMS constant.
154
+ def initialize(session, options = {})
155
+ @session = session
156
+ @logger = session.logger
157
+ @options = options
158
+ @algorithms = {}
159
+ @pending = @initialized = false
160
+ @client_packet = @server_packet = nil
161
+ prepare_preferred_algorithms!
162
+ end
172
163
 
173
- # Returns true if no exchange is pending, and otherwise returns true or
174
- # false depending on whether the given packet is of a type that is allowed
175
- # during a key exchange.
176
- def allow?(packet)
177
- !pending? || Algorithms.allowed_packet?(packet)
178
- end
164
+ # Start the algorithm negotation
165
+ def start
166
+ raise ArgumentError, "Cannot call start if it's negotiation started or done" if @pending || @initialized
179
167
 
180
- # Returns true if the algorithms have been negotiated at all.
181
- def initialized?
182
- @initialized
183
- end
168
+ send_kexinit
169
+ end
184
170
 
185
- private
186
-
187
- # Sends a KEXINIT packet to the server. If a server KEXINIT has already
188
- # been received, this will then invoke #proceed! to proceed with the key
189
- # exchange, otherwise it returns immediately (but sets the object to the
190
- # pending state).
191
- def send_kexinit
192
- info { "sending KEXINIT" }
193
- @pending = true
194
- packet = build_client_algorithm_packet
195
- @client_packet = packet.to_s
196
- session.send_message(packet)
197
- proceed! if @server_packet
198
- end
171
+ # Request a rekey operation. This will return immediately, and does not
172
+ # actually perform the rekey operation. It does cause the session to change
173
+ # state, however--until the key exchange finishes, no new packets will be
174
+ # processed.
175
+ def rekey!
176
+ @client_packet = @server_packet = nil
177
+ @initialized = false
178
+ send_kexinit
179
+ end
199
180
 
200
- # After both client and server have sent their KEXINIT packets, this
201
- # will do the algorithm negotiation and key exchange. Once both finish,
202
- # the object leaves the pending state and the method returns.
203
- def proceed!
204
- info { "negotiating algorithms" }
205
- negotiate_algorithms
206
- exchange_keys
207
- @pending = false
208
- end
181
+ # Called by the transport layer when a KEXINIT packet is received, indicating
182
+ # that the server wants to exchange keys. This can be spontaneous, or it
183
+ # can be in response to a client-initiated rekey request (see #rekey!). Either
184
+ # way, this will block until the key exchange completes.
185
+ def accept_kexinit(packet)
186
+ info { "got KEXINIT from server" }
187
+ @server_data = parse_server_algorithm_packet(packet)
188
+ @server_packet = @server_data[:raw]
189
+ if !pending?
190
+ send_kexinit
191
+ else
192
+ proceed!
193
+ end
194
+ end
209
195
 
210
- # Prepares the list of preferred algorithms, based on the options hash
211
- # that was given when the object was constructed, and the ALGORITHMS
212
- # constant. Also, when determining the host_key type to use, the known
213
- # hosts files are examined to see if the host has ever sent a host_key
214
- # before, and if so, that key type is used as the preferred type for
215
- # communicating with this server.
216
- def prepare_preferred_algorithms!
217
- options[:compression] = %w(zlib@openssh.com zlib) if options[:compression] == true
218
-
219
- ALGORITHMS.each do |algorithm, list|
220
- algorithms[algorithm] = list.dup
221
-
222
- # apply the preferred algorithm order, if any
223
- if options[algorithm]
224
- algorithms[algorithm] = Array(options[algorithm]).compact.uniq
225
- unsupported = []
226
- algorithms[algorithm].select! do |name|
227
- supported = ALGORITHMS[algorithm].include?(name)
228
- unsupported << name unless supported
229
- supported
230
- end
231
- lwarn { "unsupported #{algorithm} algorithm: `#{unsupported}'" } unless unsupported.empty?
196
+ # A convenience method for accessing the list of preferred types for a
197
+ # specific algorithm (see #algorithms).
198
+ def [](key)
199
+ algorithms[key]
200
+ end
201
+
202
+ # Returns +true+ if a key-exchange is pending. This will be true from the
203
+ # moment either the client or server requests the key exchange, until the
204
+ # exchange completes. While an exchange is pending, only a limited number
205
+ # of packets are allowed, so event processing essentially stops during this
206
+ # period.
207
+ def pending?
208
+ @pending
209
+ end
210
+
211
+ # Returns true if no exchange is pending, and otherwise returns true or
212
+ # false depending on whether the given packet is of a type that is allowed
213
+ # during a key exchange.
214
+ def allow?(packet)
215
+ !pending? || Algorithms.allowed_packet?(packet)
216
+ end
217
+
218
+ # Returns true if the algorithms have been negotiated at all.
219
+ def initialized?
220
+ @initialized
221
+ end
222
+
223
+ def host_key_format
224
+ case host_key
225
+ when /^([a-z0-9-]+)-cert-v\d{2}@openssh.com$/
226
+ Regexp.last_match[1]
227
+ else
228
+ host_key
229
+ end
230
+ end
231
+
232
+ private
233
+
234
+ # Sends a KEXINIT packet to the server. If a server KEXINIT has already
235
+ # been received, this will then invoke #proceed! to proceed with the key
236
+ # exchange, otherwise it returns immediately (but sets the object to the
237
+ # pending state).
238
+ def send_kexinit
239
+ info { "sending KEXINIT" }
240
+ @pending = true
241
+ packet = build_client_algorithm_packet
242
+ @client_packet = packet.to_s
243
+ session.send_message(packet)
244
+ proceed! if @server_packet
245
+ end
246
+
247
+ # After both client and server have sent their KEXINIT packets, this
248
+ # will do the algorithm negotiation and key exchange. Once both finish,
249
+ # the object leaves the pending state and the method returns.
250
+ def proceed!
251
+ info { "negotiating algorithms" }
252
+ negotiate_algorithms
253
+ exchange_keys
254
+ @pending = false
255
+ end
256
+
257
+ # Prepares the list of preferred algorithms, based on the options hash
258
+ # that was given when the object was constructed, and the ALGORITHMS
259
+ # constant. Also, when determining the host_key type to use, the known
260
+ # hosts files are examined to see if the host has ever sent a host_key
261
+ # before, and if so, that key type is used as the preferred type for
262
+ # communicating with this server.
263
+ def prepare_preferred_algorithms!
264
+ options[:compression] = %w[zlib@openssh.com zlib] if options[:compression] == true
265
+
266
+ ALGORITHMS.each do |algorithm, supported|
267
+ algorithms[algorithm] = compose_algorithm_list(
268
+ supported, options[algorithm] || DEFAULT_ALGORITHMS[algorithm],
269
+ options[:append_all_supported_algorithms]
270
+ )
271
+ end
272
+
273
+ # for convention, make sure our list has the same keys as the server
274
+ # list
275
+
276
+ algorithms[:encryption_client ] = algorithms[:encryption_server ] = algorithms[:encryption]
277
+ algorithms[:hmac_client ] = algorithms[:hmac_server ] = algorithms[:hmac]
278
+ algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
279
+ algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
232
280
 
233
- if options[:append_all_supported_algorithms]
234
- list.each { |name| algorithms[algorithm] << name unless algorithms[algorithm].include?(name) }
281
+ if !options.key?(:host_key)
282
+ # make sure the host keys are specified in preference order, where any
283
+ # existing known key for the host has preference.
284
+
285
+ existing_keys = session.host_keys
286
+ host_keys = existing_keys.flat_map { |key| key.respond_to?(:ssh_types) ? key.ssh_types : [key.ssh_type] }.uniq
287
+ algorithms[:host_key].each do |name|
288
+ host_keys << name unless host_keys.include?(name)
235
289
  end
290
+ algorithms[:host_key] = host_keys
236
291
  end
237
292
  end
238
293
 
239
- # for convention, make sure our list has the same keys as the server
240
- # list
294
+ # Composes the list of algorithms by taking supported algorithms and matching with supplied options.
295
+ def compose_algorithm_list(supported, option, append_all_supported_algorithms = false)
296
+ return supported.dup unless option
297
+
298
+ list = []
299
+ option = Array(option).compact.uniq
300
+
301
+ if option.first && option.first.start_with?('+', '-')
302
+ list = supported.dup
303
+
304
+ appends = option.select { |opt| opt.start_with?('+') }.map { |opt| opt[1..-1] }
305
+ deletions = option.select { |opt| opt.start_with?('-') }.map { |opt| opt[1..-1] }
241
306
 
242
- algorithms[:encryption_client ] = algorithms[:encryption_server ] = algorithms[:encryption]
243
- algorithms[:hmac_client ] = algorithms[:hmac_server ] = algorithms[:hmac]
244
- algorithms[:compression_client] = algorithms[:compression_server] = algorithms[:compression]
245
- algorithms[:language_client ] = algorithms[:language_server ] = algorithms[:language]
307
+ list.concat(appends)
246
308
 
247
- if !options.key?(:host_key)
248
- # make sure the host keys are specified in preference order, where any
249
- # existing known key for the host has preference.
309
+ deletions.each do |opt|
310
+ if opt.include?('*')
311
+ opt_escaped = Regexp.escape(opt)
312
+ algo_re = /\A#{opt_escaped.gsub('\*', '[A-Za-z\d\-@\.]*')}\z/
313
+ list.delete_if { |existing_opt| algo_re.match(existing_opt) }
314
+ else
315
+ list.delete(opt)
316
+ end
317
+ end
318
+
319
+ list.uniq!
320
+ else
321
+ list = option
322
+
323
+ if append_all_supported_algorithms
324
+ supported.each { |name| list << name unless list.include?(name) }
325
+ end
326
+ end
250
327
 
251
- existing_keys = session.host_keys
252
- host_keys = existing_keys.map { |key| key.ssh_type }.uniq
253
- algorithms[:host_key].each do |name|
254
- host_keys << name unless host_keys.include?(name)
328
+ unsupported = []
329
+ list.select! do |name|
330
+ is_supported = supported.include?(name)
331
+ unsupported << name unless is_supported
332
+ is_supported
255
333
  end
256
- algorithms[:host_key] = host_keys
334
+
335
+ lwarn { %(unsupported algorithm: `#{unsupported}') } unless unsupported.empty?
336
+
337
+ list
257
338
  end
258
- end
259
339
 
260
- # Parses a KEXINIT packet from the server.
261
- def parse_server_algorithm_packet(packet)
262
- data = { :raw => packet.content }
263
-
264
- packet.read(16) # skip the cookie value
265
-
266
- data[:kex] = packet.read_string.split(/,/)
267
- data[:host_key] = packet.read_string.split(/,/)
268
- data[:encryption_client] = packet.read_string.split(/,/)
269
- data[:encryption_server] = packet.read_string.split(/,/)
270
- data[:hmac_client] = packet.read_string.split(/,/)
271
- data[:hmac_server] = packet.read_string.split(/,/)
272
- data[:compression_client] = packet.read_string.split(/,/)
273
- data[:compression_server] = packet.read_string.split(/,/)
274
- data[:language_client] = packet.read_string.split(/,/)
275
- data[:language_server] = packet.read_string.split(/,/)
276
-
277
- # TODO: if first_kex_packet_follows, we need to try to skip the
278
- # actual kexinit stuff and try to guess what the server is doing...
279
- # need to read more about this scenario.
280
- # first_kex_packet_follows = packet.read_bool
281
-
282
- return data
283
- end
340
+ # Parses a KEXINIT packet from the server.
341
+ def parse_server_algorithm_packet(packet)
342
+ data = { raw: packet.content }
343
+
344
+ packet.read(16) # skip the cookie value
345
+
346
+ data[:kex] = packet.read_string.split(/,/)
347
+ data[:host_key] = packet.read_string.split(/,/)
348
+ data[:encryption_client] = packet.read_string.split(/,/)
349
+ data[:encryption_server] = packet.read_string.split(/,/)
350
+ data[:hmac_client] = packet.read_string.split(/,/)
351
+ data[:hmac_server] = packet.read_string.split(/,/)
352
+ data[:compression_client] = packet.read_string.split(/,/)
353
+ data[:compression_server] = packet.read_string.split(/,/)
354
+ data[:language_client] = packet.read_string.split(/,/)
355
+ data[:language_server] = packet.read_string.split(/,/)
356
+
357
+ # TODO: if first_kex_packet_follows, we need to try to skip the
358
+ # actual kexinit stuff and try to guess what the server is doing...
359
+ # need to read more about this scenario.
360
+ # first_kex_packet_follows = packet.read_bool
361
+
362
+ return data
363
+ end
284
364
 
285
- # Given the #algorithms map of preferred algorithm types, this constructs
286
- # a KEXINIT packet to send to the server. It does not actually send it,
287
- # it simply builds the packet and returns it.
288
- def build_client_algorithm_packet
289
- kex = algorithms[:kex ].join(",")
290
- host_key = algorithms[:host_key ].join(",")
291
- encryption = algorithms[:encryption ].join(",")
292
- hmac = algorithms[:hmac ].join(",")
293
- compression = algorithms[:compression].join(",")
294
- language = algorithms[:language ].join(",")
295
-
296
- Net::SSH::Buffer.from(:byte, KEXINIT,
297
- :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
298
- :string, [kex, host_key, encryption, encryption, hmac, hmac],
299
- :string, [compression, compression, language, language],
300
- :bool, false, :long, 0)
301
- end
365
+ # Given the #algorithms map of preferred algorithm types, this constructs
366
+ # a KEXINIT packet to send to the server. It does not actually send it,
367
+ # it simply builds the packet and returns it.
368
+ def build_client_algorithm_packet
369
+ kex = algorithms[:kex].join(",")
370
+ host_key = algorithms[:host_key].join(",")
371
+ encryption = algorithms[:encryption].join(",")
372
+ hmac = algorithms[:hmac].join(",")
373
+ compression = algorithms[:compression].join(",")
374
+ language = algorithms[:language].join(",")
375
+
376
+ Net::SSH::Buffer.from(:byte, KEXINIT,
377
+ :long, [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)],
378
+ :mstring, [kex, host_key, encryption, encryption, hmac, hmac],
379
+ :mstring, [compression, compression, language, language],
380
+ :bool, false, :long, 0)
381
+ end
302
382
 
303
- # Given the parsed server KEX packet, and the client's preferred algorithm
304
- # lists in #algorithms, determine which preferred algorithms each has
305
- # in common and set those as the selected algorithms. If, for any algorithm,
306
- # no type can be settled on, an exception is raised.
307
- def negotiate_algorithms
308
- @kex = negotiate(:kex)
309
- @host_key = negotiate(:host_key)
310
- @encryption_client = negotiate(:encryption_client)
311
- @encryption_server = negotiate(:encryption_server)
312
- @hmac_client = negotiate(:hmac_client)
313
- @hmac_server = negotiate(:hmac_server)
314
- @compression_client = negotiate(:compression_client)
315
- @compression_server = negotiate(:compression_server)
316
- @language_client = negotiate(:language_client) rescue ""
317
- @language_server = negotiate(:language_server) rescue ""
318
-
319
- debug do
320
- "negotiated:\n" +
321
- [:kex, :host_key, :encryption_server, :encryption_client, :hmac_client, :hmac_server, :compression_client, :compression_server, :language_client, :language_server].map do |key|
322
- "* #{key}: #{instance_variable_get("@#{key}")}"
323
- end.join("\n")
383
+ # Given the parsed server KEX packet, and the client's preferred algorithm
384
+ # lists in #algorithms, determine which preferred algorithms each has
385
+ # in common and set those as the selected algorithms. If, for any algorithm,
386
+ # no type can be settled on, an exception is raised.
387
+ def negotiate_algorithms
388
+ @kex = negotiate(:kex)
389
+ @host_key = negotiate(:host_key)
390
+ @encryption_client = negotiate(:encryption_client)
391
+ @encryption_server = negotiate(:encryption_server)
392
+ @hmac_client = negotiate(:hmac_client)
393
+ @hmac_server = negotiate(:hmac_server)
394
+ @compression_client = negotiate(:compression_client)
395
+ @compression_server = negotiate(:compression_server)
396
+ @language_client = negotiate(:language_client) rescue ""
397
+ @language_server = negotiate(:language_server) rescue ""
398
+
399
+ debug do
400
+ "negotiated:\n" +
401
+ %i[kex host_key encryption_server encryption_client hmac_client hmac_server
402
+ compression_client compression_server language_client language_server].map do |key|
403
+ "* #{key}: #{instance_variable_get("@#{key}")}"
404
+ end.join("\n")
405
+ end
324
406
  end
325
- end
326
407
 
327
- # Negotiates a single algorithm based on the preferences reported by the
328
- # server and those set by the client. This is called by
329
- # #negotiate_algorithms.
330
- def negotiate(algorithm)
331
- match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
408
+ # Negotiates a single algorithm based on the preferences reported by the
409
+ # server and those set by the client. This is called by
410
+ # #negotiate_algorithms.
411
+ def negotiate(algorithm)
412
+ match = self[algorithm].find { |item| @server_data[algorithm].include?(item) }
332
413
 
333
- if match.nil?
334
- raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm"
414
+ if match.nil?
415
+ raise Net::SSH::Exception, "could not settle on #{algorithm} algorithm\n"\
416
+ "Server #{algorithm} preferences: #{@server_data[algorithm].join(',')}\n"\
417
+ "Client #{algorithm} preferences: #{self[algorithm].join(',')}"
418
+ end
419
+
420
+ return match
335
421
  end
336
422
 
337
- return match
338
- end
423
+ # Considers the sizes of the keys and block-sizes for the selected ciphers,
424
+ # and the lengths of the hmacs, and returns the largest as the byte requirement
425
+ # for the key-exchange algorithm.
426
+ def kex_byte_requirement
427
+ sizes = [8] # require at least 8 bytes
428
+
429
+ sizes.concat(CipherFactory.get_lengths(encryption_client))
430
+ sizes.concat(CipherFactory.get_lengths(encryption_server))
339
431
 
340
- # Considers the sizes of the keys and block-sizes for the selected ciphers,
341
- # and the lengths of the hmacs, and returns the largest as the byte requirement
342
- # for the key-exchange algorithm.
343
- def kex_byte_requirement
344
- sizes = [8] # require at least 8 bytes
432
+ sizes << HMAC.key_length(hmac_client)
433
+ sizes << HMAC.key_length(hmac_server)
345
434
 
346
- sizes.concat(CipherFactory.get_lengths(encryption_client))
347
- sizes.concat(CipherFactory.get_lengths(encryption_server))
435
+ sizes.max
436
+ end
348
437
 
349
- sizes << HMAC.key_length(hmac_client)
350
- sizes << HMAC.key_length(hmac_server)
438
+ # Instantiates one of the Transport::Kex classes (based on the negotiated
439
+ # kex algorithm), and uses it to exchange keys. Then, the ciphers and
440
+ # HMACs are initialized and fed to the transport layer, to be used in
441
+ # further communication with the server.
442
+ def exchange_keys
443
+ debug { "exchanging keys" }
444
+
445
+ need_bytes = kex_byte_requirement
446
+ algorithm = Kex::MAP[kex].new(self, session,
447
+ client_version_string: Net::SSH::Transport::ServerVersion::PROTO_VERSION,
448
+ server_version_string: session.server_version.version,
449
+ server_algorithm_packet: @server_packet,
450
+ client_algorithm_packet: @client_packet,
451
+ need_bytes: need_bytes,
452
+ minimum_dh_bits: options[:minimum_dh_bits],
453
+ logger: logger)
454
+ result = algorithm.exchange_keys
455
+
456
+ secret = result[:shared_secret].to_ssh
457
+ hash = result[:session_id]
458
+ digester = result[:hashing_algorithm]
459
+
460
+ @session_id ||= hash
461
+
462
+ key = Proc.new { |salt| digester.digest(secret + hash + salt + @session_id) }
463
+
464
+ iv_client = key["A"]
465
+ iv_server = key["B"]
466
+ key_client = key["C"]
467
+ key_server = key["D"]
468
+ mac_key_client = key["E"]
469
+ mac_key_server = key["F"]
470
+
471
+ parameters = { shared: secret, hash: hash, digester: digester }
472
+
473
+ cipher_client = CipherFactory.get(
474
+ encryption_client,
475
+ parameters.merge(iv: iv_client, key: key_client, encrypt: true)
476
+ )
477
+ cipher_server = CipherFactory.get(
478
+ encryption_server,
479
+ parameters.merge(iv: iv_server, key: key_server, decrypt: true)
480
+ )
481
+
482
+ mac_client =
483
+ if cipher_client.implicit_mac?
484
+ cipher_client.implicit_mac
485
+ else
486
+ HMAC.get(hmac_client, mac_key_client, parameters)
487
+ end
488
+ mac_server =
489
+ if cipher_server.implicit_mac?
490
+ cipher_server.implicit_mac
491
+ else
492
+ HMAC.get(hmac_server, mac_key_server, parameters)
493
+ end
351
494
 
352
- sizes.max
353
- end
495
+ session.configure_client cipher: cipher_client, hmac: mac_client,
496
+ compression: normalize_compression_name(compression_client),
497
+ compression_level: options[:compression_level],
498
+ rekey_limit: options[:rekey_limit],
499
+ max_packets: options[:rekey_packet_limit],
500
+ max_blocks: options[:rekey_blocks_limit]
354
501
 
355
- # Instantiates one of the Transport::Kex classes (based on the negotiated
356
- # kex algorithm), and uses it to exchange keys. Then, the ciphers and
357
- # HMACs are initialized and fed to the transport layer, to be used in
358
- # further communication with the server.
359
- def exchange_keys
360
- debug { "exchanging keys" }
361
-
362
- algorithm = Kex::MAP[kex].new(self, session,
363
- :client_version_string => Net::SSH::Transport::ServerVersion::PROTO_VERSION,
364
- :server_version_string => session.server_version.version,
365
- :server_algorithm_packet => @server_packet,
366
- :client_algorithm_packet => @client_packet,
367
- :need_bytes => kex_byte_requirement,
368
- :logger => logger)
369
- result = algorithm.exchange_keys
370
-
371
- secret = result[:shared_secret].to_ssh
372
- hash = result[:session_id]
373
- digester = result[:hashing_algorithm]
374
-
375
- @session_id ||= hash
376
-
377
- key = Proc.new { |salt| digester.digest(secret + hash + salt + @session_id) }
378
-
379
- iv_client = key["A"]
380
- iv_server = key["B"]
381
- key_client = key["C"]
382
- key_server = key["D"]
383
- mac_key_client = key["E"]
384
- mac_key_server = key["F"]
385
-
386
- parameters = { :shared => secret, :hash => hash, :digester => digester }
387
-
388
- cipher_client = CipherFactory.get(encryption_client, parameters.merge(:iv => iv_client, :key => key_client, :encrypt => true))
389
- cipher_server = CipherFactory.get(encryption_server, parameters.merge(:iv => iv_server, :key => key_server, :decrypt => true))
390
-
391
- mac_client = HMAC.get(hmac_client, mac_key_client, parameters)
392
- mac_server = HMAC.get(hmac_server, mac_key_server, parameters)
393
-
394
- session.configure_client :cipher => cipher_client, :hmac => mac_client,
395
- :compression => normalize_compression_name(compression_client),
396
- :compression_level => options[:compression_level],
397
- :rekey_limit => options[:rekey_limit],
398
- :max_packets => options[:rekey_packet_limit],
399
- :max_blocks => options[:rekey_blocks_limit]
400
-
401
- session.configure_server :cipher => cipher_server, :hmac => mac_server,
402
- :compression => normalize_compression_name(compression_server),
403
- :rekey_limit => options[:rekey_limit],
404
- :max_packets => options[:rekey_packet_limit],
405
- :max_blocks => options[:rekey_blocks_limit]
406
-
407
- @initialized = true
408
- end
502
+ session.configure_server cipher: cipher_server, hmac: mac_server,
503
+ compression: normalize_compression_name(compression_server),
504
+ rekey_limit: options[:rekey_limit],
505
+ max_packets: options[:rekey_packet_limit],
506
+ max_blocks: options[:rekey_blocks_limit]
409
507
 
410
- # Given the SSH name for some compression algorithm, return a normalized
411
- # name as a symbol.
412
- def normalize_compression_name(name)
413
- case name
414
- when "none" then false
415
- when "zlib" then :standard
416
- when "zlib@openssh.com" then :delayed
417
- else raise ArgumentError, "unknown compression type `#{name}'"
508
+ @initialized = true
509
+ end
510
+
511
+ # Given the SSH name for some compression algorithm, return a normalized
512
+ # name as a symbol.
513
+ def normalize_compression_name(name)
514
+ case name
515
+ when "none" then false
516
+ when "zlib" then :standard
517
+ when "zlib@openssh.com" then :delayed
518
+ else raise ArgumentError, "unknown compression type `#{name}'"
519
+ end
418
520
  end
419
521
  end
522
+ end
420
523
  end
421
- end; end; end
524
+ end