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.
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 ) |
Create a new AlgorithmNegotiator instance, using the given logger, set of default algorithms, and buffer factory.
# 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
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.
# 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