Class Net::SSH::Transport::AlgorithmNegotiator
In: lib/net/ssh/transport/algorithm-negotiator.rb
Parent: Object

The AlgorithmNegotiator is used for negotiating the algorithms to be employed for a specific SSH session.

Methods

negotiate   new  

Included Modules

Constants

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.

[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.

[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

[Validate]