The AlgorithmNegotiator is used for negotiating the algorithms to be employed for a specific SSH session.
Methods
Included Modules
Constants
| Algorithms | = | Struct.new( :server_packet, :client_packet, :kex, :host_key, :encryption_c2s, :encryption_s2c, :mac_c2s, :mac_s2c, :compression_c2s, :compression_s2c, :language_c2s, :language_s2c, :compression_level ) |
Public Class methods
Create a new AlgorithmNegotiator instance, using the given logger, set of default algorithms, and buffer factory.
[ show source ]
# File lib/net/ssh/transport/algorithm-negotiator.rb, line 45
45: def initialize( logger, algorithms, buffers )
46: @default_algorithms = algorithms
47: @buffers = buffers
48: @logger = logger
49: end
Public Instance methods
Negotiate the supported algorithms with the server. If a compromise cannot be reached between what the client wants and what the server can provide, this will fail.
[ show source ]
# File lib/net/ssh/transport/algorithm-negotiator.rb, line 101
101: def negotiate( session, options )
102: prepare_preferred_algorithms options
103:
104: # first, discover what the server can do
105: type, buffer = session.wait_for_message
106: raise Net::SSH::Exception, "expected KEXINIT" unless type == KEXINIT
107:
108: server_algorithm_packet = buffer.content
109:
110: cookie = buffer.read( 16 )
111: kex_algorithms = buffer.read_string
112: server_host_key_algorithms = buffer.read_string
113: encryption_algorithms_client_to_server = buffer.read_string
114: encryption_algorithms_server_to_client = buffer.read_string
115: mac_algorithms_client_to_server = buffer.read_string
116: mac_algorithms_server_to_client = buffer.read_string
117: compression_algorithms_client_to_server = buffer.read_string
118: compression_algorithms_server_to_client = buffer.read_string
119: languages_client_to_server = buffer.read_string
120: languages_server_to_client = buffer.read_string
121: first_kex_packet_follows = buffer.read_bool
122: zero = buffer.read_long
123:
124: # TODO: if first_kex_packet_follows, we need to try to skip the
125: # actual kexinit stuff and try to guess what the server is doing...
126: # need to read more about this scenario.
127:
128: # next, tell the server what we can do
129:
130: my_kex = @algorithms[ :kex ].join( "," )
131: my_server_host_key_algorithms = @algorithms[ :host_key ].join( "," )
132: my_encryption_algorithms = @algorithms[ :encryption ].join( "," )
133: my_mac_algorithms = @algorithms[ :hmac ].join( "," )
134: my_compression_algorithms = @algorithms[ :compression ].join( "," )
135: my_languages = @algorithms[ :languages ].join( "," )
136:
137: msg = @buffers.writer
138: msg.write_byte KEXINIT
139: msg.write_long rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF),
140: rand(0xFFFFFFFF)
141: msg.write_string my_kex, my_server_host_key_algorithms
142: msg.write_string my_encryption_algorithms, my_encryption_algorithms
143: msg.write_string my_mac_algorithms, my_mac_algorithms
144: msg.write_string my_compression_algorithms, my_compression_algorithms
145: msg.write_string my_languages, my_languages
146: msg.write_bool false
147: msg.write_long 0
148:
149: client_algorithm_packet = msg.to_s
150: session.send_message msg
151:
152: # negotiate algorithms
153:
154: kex_algorithm = first_matching_element( @algorithms[ :kex ],
155: kex_algorithms )
156: raise Net::SSH::Exception,
157: "could not settle on kex algorithm" unless kex_algorithm
158: @logger.debug "kex algorithm: #{kex_algorithm}" if @logger.debug?
159:
160: host_key_algorithm = first_matching_element(
161: @algorithms[ :host_key ], server_host_key_algorithms )
162: raise Net::SSH::Exception,
163: "could not settle on host key algorithm" unless host_key_algorithm
164: if @logger.debug?
165: @logger.debug "host key algorithm: #{host_key_algorithm}"
166: end
167:
168: encryption_algorithm_c2s = first_matching_element(
169: @algorithms[ :encryption ], encryption_algorithms_client_to_server )
170: unless encryption_algorithm_c2s
171: raise Net::SSH::Exception,
172: "could not settle on client-to-server encryption algorithm"
173: end
174: if @logger.debug?
175: @logger.debug "encryption algorithm (client-to-server): " +
176: encryption_algorithm_c2s
177: end
178:
179: encryption_algorithm_s2c = first_matching_element(
180: @algorithms[ :encryption ], encryption_algorithms_server_to_client )
181: unless encryption_algorithm_s2c
182: raise Net::SSH::Exception,
183: "could not settle on server-to-client encryption algorithm"
184: end
185: if @logger.debug?
186: @logger.debug "encryption algorithm (server-to-client): " +
187: encryption_algorithm_s2c
188: end
189:
190: mac_algorithm_c2s = first_matching_element(
191: @algorithms[ :hmac ], mac_algorithms_client_to_server )
192: unless mac_algorithm_c2s
193: raise Net::SSH::Exception,
194: "could not settle on client-to-server HMAC algorithm"
195: end
196: if @logger.debug?
197: @logger.debug "hmac algorithm (client-to-server): " +
198: mac_algorithm_c2s
199: end
200:
201: mac_algorithm_s2c = first_matching_element( @algorithms[ :hmac ],
202: mac_algorithms_server_to_client )
203: unless mac_algorithm_s2c
204: raise Net::SSH::Exception,
205: "could not settle on server-to-client HMAC algorithm"
206: end
207: if @logger.debug?
208: @logger.debug "hmac algorithm (server-to-client): " +
209: mac_algorithm_s2c
210: end
211:
212: compression_algorithm_c2s = first_matching_element(
213: @algorithms[ :compression ],
214: compression_algorithms_client_to_server )
215: unless compression_algorithm_c2s
216: raise Net::SSH::Exception,
217: "could not settle on client-to-server compression algorithm"
218: end
219: if @logger.debug?
220: @logger.debug "compression algorithm (client-to-server): " +
221: compression_algorithm_c2s
222: end
223:
224: compression_algorithm_s2c = first_matching_element(
225: @algorithms[ :compression ],
226: compression_algorithms_server_to_client )
227: unless compression_algorithm_s2c
228: raise Net::SSH::Exception,
229: "could not settle on server-to-client compression algorithm"
230: end
231: if @logger.debug?
232: @logger.debug "compression algorithm (server-to-client): " +
233: compression_algorithm_s2c
234: end
235:
236: language_c2s = first_matching_element( @algorithms[ :languages ],
237: languages_client_to_server ) || ""
238: if @logger.debug?
239: @logger.debug "language (client-to-server): #{language_c2s}"
240: end
241:
242: language_s2c = first_matching_element( @algorithms[ :languages ],
243: languages_server_to_client ) || ""
244: if @logger.debug?
245: @logger.debug "language (server-to-client): #{language_s2c}"
246: end
247:
248: return Algorithms.new( server_algorithm_packet,
249: client_algorithm_packet,
250: kex_algorithm,
251: host_key_algorithm,
252: encryption_algorithm_c2s,
253: encryption_algorithm_s2c,
254: mac_algorithm_c2s,
255: mac_algorithm_s2c,
256: compression_algorithm_c2s,
257: compression_algorithm_s2c,
258: language_c2s,
259: language_s2c,
260: @compression_level )
261: end