SSH: Tighter state checking during key exchange.

This will also make it easier for us to initiate a re-exchange
if we ever want to implement that.
This commit is contained in:
Christian Kandeler
2011-04-19 14:39:32 +02:00
parent 8e5797bbd4
commit cca52b6d30
2 changed files with 13 additions and 9 deletions

View File

@@ -342,6 +342,7 @@ void SshConnectionPrivate::handleServerId()
m_keyExchange.reset(new SshKeyExchange(m_sendFacility)); m_keyExchange.reset(new SshKeyExchange(m_sendFacility));
m_serverId = m_incomingData.left(endOffset); m_serverId = m_incomingData.left(endOffset);
m_keyExchange->sendKexInitPacket(m_serverId); m_keyExchange->sendKexInitPacket(m_serverId);
m_keyExchangeState = KexInitSent;
m_incomingData.remove(0, endOffset + 2); m_incomingData.remove(0, endOffset + 2);
} }
@@ -358,7 +359,7 @@ void SshConnectionPrivate::handlePackets()
void SshConnectionPrivate::handleCurrentPacket() void SshConnectionPrivate::handleCurrentPacket()
{ {
Q_ASSERT(m_incomingPacket.isComplete()); Q_ASSERT(m_incomingPacket.isComplete());
Q_ASSERT(m_keyExchangeState == KeyExchangeStarted || !m_ignoreNextPacket); Q_ASSERT(m_keyExchangeState == DhInitSent || !m_ignoreNextPacket);
if (m_ignoreNextPacket) { if (m_ignoreNextPacket) {
m_ignoreNextPacket = false; m_ignoreNextPacket = false;
@@ -381,14 +382,15 @@ void SshConnectionPrivate::handleCurrentPacket()
void SshConnectionPrivate::handleKeyExchangeInitPacket() void SshConnectionPrivate::handleKeyExchangeInitPacket()
{ {
if (m_keyExchangeState != NoKeyExchange) { if (m_keyExchangeState != NoKeyExchange
&& m_keyExchangeState != KexInitSent) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected packet.", tr("Unexpected packet of type %1.") "Unexpected packet.", tr("Unexpected packet of type %1.")
.arg(m_incomingPacket.type())); .arg(m_incomingPacket.type()));
} }
// Server-initiated re-exchange. // Server-initiated re-exchange.
if (m_state == ConnectionEstablished) { if (m_keyExchangeState == NoKeyExchange) {
m_keyExchange.reset(new SshKeyExchange(m_sendFacility)); m_keyExchange.reset(new SshKeyExchange(m_sendFacility));
m_keyExchange->sendKexInitPacket(m_serverId); m_keyExchange->sendKexInitPacket(m_serverId);
} }
@@ -400,12 +402,12 @@ void SshConnectionPrivate::handleKeyExchangeInitPacket()
m_ignoreNextPacket = true; m_ignoreNextPacket = true;
} }
m_keyExchangeState = KeyExchangeStarted; m_keyExchangeState = DhInitSent;
} }
void SshConnectionPrivate::handleKeyExchangeReplyPacket() void SshConnectionPrivate::handleKeyExchangeReplyPacket()
{ {
if (m_keyExchangeState != KeyExchangeStarted) { if (m_keyExchangeState != DhInitSent) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected packet.", tr("Unexpected packet of type %1.") "Unexpected packet.", tr("Unexpected packet of type %1.")
.arg(m_incomingPacket.type())); .arg(m_incomingPacket.type()));
@@ -414,12 +416,12 @@ void SshConnectionPrivate::handleKeyExchangeReplyPacket()
m_keyExchange->sendNewKeysPacket(m_incomingPacket, m_keyExchange->sendNewKeysPacket(m_incomingPacket,
ClientId.left(ClientId.size() - 2)); ClientId.left(ClientId.size() - 2));
m_sendFacility.recreateKeys(*m_keyExchange); m_sendFacility.recreateKeys(*m_keyExchange);
m_keyExchangeState = KeyExchangeSuccess; m_keyExchangeState = NewKeysSent;
} }
void SshConnectionPrivate::handleNewKeysPacket() void SshConnectionPrivate::handleNewKeysPacket()
{ {
if (m_keyExchangeState != KeyExchangeSuccess) { if (m_keyExchangeState != NewKeysSent) {
throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR, throw SshServerException(SSH_DISCONNECT_PROTOCOL_ERROR,
"Unexpected packet.", tr("Unexpected packet of type %1.") "Unexpected packet.", tr("Unexpected packet of type %1.")
.arg(m_incomingPacket.type())); .arg(m_incomingPacket.type()));

View File

@@ -71,8 +71,10 @@ enum SshStateInternal {
enum SshKeyExchangeState { enum SshKeyExchangeState {
NoKeyExchange, NoKeyExchange,
KeyExchangeStarted, // After server's KEXINIT message KexInitSent,
KeyExchangeSuccess // After server's DH_REPLY message DhInitSent,
NewKeysSent,
KeyExchangeSuccess // After server's DH_REPLY message
}; };
class SshConnectionPrivate : public QObject class SshConnectionPrivate : public QObject