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 46
46: def initialize( logger, algorithms, buffers )
47: @default_algorithms = algorithms
48: @buffers = buffers
49: @logger = logger
50: 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 109
109: def negotiate( session, options )
110: prepare_preferred_algorithms session, options
111:
112: # first, discover what the server can do
113: type, buffer = session.wait_for_message
114: raise Net::SSH::Exception, "expected KEXINIT" unless type == KEXINIT
115:
116: server_algorithm_packet = buffer.content
117:
118: cookie = buffer.read( 16 )
119: kex_algorithms = buffer.read_string
120: server_host_key_algorithms = buffer.read_string
121: encryption_algorithms_client_to_server = buffer.read_string
122: encryption_algorithms_server_to_client = buffer.read_string
123: mac_algorithms_client_to_server = buffer.read_string
124: mac_algorithms_server_to_client = buffer.read_string
125: compression_algorithms_client_to_server = buffer.read_string
126: compression_algorithms_server_to_client = buffer.read_string
127: languages_client_to_server = buffer.read_string
128: languages_server_to_client = buffer.read_string
129: first_kex_packet_follows = buffer.read_bool
130: zero = buffer.read_long
131:
132: # TODO: if first_kex_packet_follows, we need to try to skip the
133: # actual kexinit stuff and try to guess what the server is doing...
134: # need to read more about this scenario.
135:
136: # next, tell the server what we can do
137:
138: my_kex = @algorithms[ :kex ].join( "," )
139: my_server_host_key_algorithms = @algorithms[ :host_key ].join( "," )
140: my_encryption_algorithms = @algorithms[ :encryption ].join( "," )
141: my_mac_algorithms = @algorithms[ :hmac ].join( "," )
142: my_compression_algorithms = @algorithms[ :compression ].join( "," )
143: my_languages = @algorithms[ :languages ].join( "," )
144:
145: msg = @buffers.writer
146: msg.write_byte KEXINIT
147: msg.write_long rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF),
148: rand(0xFFFFFFFF)
149: msg.write_string my_kex, my_server_host_key_algorithms
150: msg.write_string my_encryption_algorithms, my_encryption_algorithms
151: msg.write_string my_mac_algorithms, my_mac_algorithms
152: msg.write_string my_compression_algorithms, my_compression_algorithms
153: msg.write_string my_languages, my_languages
154: msg.write_bool false
155: msg.write_long 0
156:
157: client_algorithm_packet = msg.to_s
158: session.send_message msg
159:
160: # negotiate algorithms
161:
162: kex_algorithm = first_matching_element( @algorithms[ :kex ],
163: kex_algorithms )
164: raise Net::SSH::Exception,
165: "could not settle on kex algorithm" unless kex_algorithm
166: @logger.debug "kex algorithm: #{kex_algorithm}" if @logger.debug?
167:
168: host_key_algorithm = first_matching_element(
169: @algorithms[ :host_key ], server_host_key_algorithms )
170: raise Net::SSH::Exception,
171: "could not settle on host key algorithm" unless host_key_algorithm
172: if @logger.debug?
173: @logger.debug "host key algorithm: #{host_key_algorithm}"
174: end
175:
176: encryption_algorithm_c2s = first_matching_element(
177: @algorithms[ :encryption ], encryption_algorithms_client_to_server )
178: unless encryption_algorithm_c2s
179: raise Net::SSH::Exception,
180: "could not settle on client-to-server encryption algorithm"
181: end
182: if @logger.debug?
183: @logger.debug "encryption algorithm (client-to-server): " +
184: encryption_algorithm_c2s
185: end
186:
187: encryption_algorithm_s2c = first_matching_element(
188: @algorithms[ :encryption ], encryption_algorithms_server_to_client )
189: unless encryption_algorithm_s2c
190: raise Net::SSH::Exception,
191: "could not settle on server-to-client encryption algorithm"
192: end
193: if @logger.debug?
194: @logger.debug "encryption algorithm (server-to-client): " +
195: encryption_algorithm_s2c
196: end
197:
198: mac_algorithm_c2s = first_matching_element(
199: @algorithms[ :hmac ], mac_algorithms_client_to_server )
200: unless mac_algorithm_c2s
201: raise Net::SSH::Exception,
202: "could not settle on client-to-server HMAC algorithm"
203: end
204: if @logger.debug?
205: @logger.debug "hmac algorithm (client-to-server): " +
206: mac_algorithm_c2s
207: end
208:
209: mac_algorithm_s2c = first_matching_element( @algorithms[ :hmac ],
210: mac_algorithms_server_to_client )
211: unless mac_algorithm_s2c
212: raise Net::SSH::Exception,
213: "could not settle on server-to-client HMAC algorithm"
214: end
215: if @logger.debug?
216: @logger.debug "hmac algorithm (server-to-client): " +
217: mac_algorithm_s2c
218: end
219:
220: compression_algorithm_c2s = first_matching_element(
221: @algorithms[ :compression ],
222: compression_algorithms_client_to_server )
223: unless compression_algorithm_c2s
224: raise Net::SSH::Exception,
225: "could not settle on client-to-server compression algorithm"
226: end
227: if @logger.debug?
228: @logger.debug "compression algorithm (client-to-server): " +
229: compression_algorithm_c2s
230: end
231:
232: compression_algorithm_s2c = first_matching_element(
233: @algorithms[ :compression ],
234: compression_algorithms_server_to_client )
235: unless compression_algorithm_s2c
236: raise Net::SSH::Exception,
237: "could not settle on server-to-client compression algorithm"
238: end
239: if @logger.debug?
240: @logger.debug "compression algorithm (server-to-client): " +
241: compression_algorithm_s2c
242: end
243:
244: language_c2s = first_matching_element( @algorithms[ :languages ],
245: languages_client_to_server ) || ""
246: if @logger.debug?
247: @logger.debug "language (client-to-server): #{language_c2s}"
248: end
249:
250: language_s2c = first_matching_element( @algorithms[ :languages ],
251: languages_server_to_client ) || ""
252: if @logger.debug?
253: @logger.debug "language (server-to-client): #{language_s2c}"
254: end
255:
256: return Algorithms.new( server_algorithm_packet,
257: client_algorithm_packet,
258: kex_algorithm,
259: host_key_algorithm,
260: encryption_algorithm_c2s,
261: encryption_algorithm_s2c,
262: mac_algorithm_c2s,
263: mac_algorithm_s2c,
264: compression_algorithm_c2s,
265: compression_algorithm_s2c,
266: language_c2s,
267: language_s2c,
268: @compression_level )
269: end