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