net-ssh 3.2.0 → 7.2.0.rc1

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 (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