in Sources/NIOSSH/Key Exchange/SSHKeyExchangeStateMachine.swift [120:179]
mutating func handle(keyExchange message: SSHMessage.KeyExchangeMessage) throws -> SSHMultiMessage? {
switch self.state {
case .keyExchangeSent(message: let ourMessage):
switch self.role {
case .client:
self.addKeyExchangeInitMessagesToExchangeBytes(clientsMessage: ourMessage, serversMessage: message)
// verify algorithms
let negotiated = try self.negotiatedAlgorithms(message)
let exchanger = try self.exchangerForAlgorithm(negotiated.negotiatedKeyExchangeAlgorithm)
// Ok, we need to send the key exchange message.
let message = SSHMessage.keyExchangeInit(exchanger.initiateKeyExchangeClientSide(allocator: self.allocator))
self.state = .awaitingKeyExchangeInit(exchange: exchanger, negotiated: negotiated)
return SSHMultiMessage(message)
case .server:
// Write their message in first, then ours.
self.addKeyExchangeInitMessagesToExchangeBytes(clientsMessage: message, serversMessage: ourMessage)
let negotiated = try self.negotiatedAlgorithms(message)
let exchanger = try self.exchangerForAlgorithm(negotiated.negotiatedKeyExchangeAlgorithm)
// Ok, we're waiting for them to go. They might be sending a wrong guess, which we want to ignore.
if self.expectingIncorrectGuess(message) {
self.state = .awaitingKeyExchangeInitInvalidGuess(exchange: exchanger, negotiated: negotiated)
} else {
self.state = .awaitingKeyExchangeInit(exchange: exchanger, negotiated: negotiated)
}
return nil
}
case .idle:
// We received a key exchange message while idle. We will need to send our own key exchange message back,
// and also follow immediately up with our own key exchange init message.
let ourMessage = self.createKeyExchangeMessage()
switch self.role {
case .client:
self.addKeyExchangeInitMessagesToExchangeBytes(clientsMessage: ourMessage, serversMessage: message)
case .server:
self.addKeyExchangeInitMessagesToExchangeBytes(clientsMessage: message, serversMessage: ourMessage)
}
let negotiated = try self.negotiatedAlgorithms(message)
let exchanger = try self.exchangerForAlgorithm(negotiated.negotiatedKeyExchangeAlgorithm)
let result: SSHMultiMessage
switch self.role {
case .client:
result = SSHMultiMessage(.keyExchange(ourMessage), SSHMessage.keyExchangeInit(exchanger.initiateKeyExchangeClientSide(allocator: self.allocator)))
case .server:
result = SSHMultiMessage(.keyExchange(ourMessage))
}
self.state = .keyExchangeReceived(exchange: exchanger, negotiated: negotiated, expectingGuess: self.expectingIncorrectGuess(message))
return result
case .keyExchangeReceived, .awaitingKeyExchangeInit, .awaitingKeyExchangeInitInvalidGuess, .keyExchangeInitReceived, .keyExchangeInitSent, .keysExchanged, .newKeysSent, .newKeysReceived, .complete:
throw SSHKeyExchangeError.unexpectedMessage
}
}