QByteArray SshPacketParser::asString(const QByteArray &data, quint32 *offset) { const quint32 length = asUint32(data, offset); if (size(data) < *offset + length) throw SshPacketParseException(); const QByteArray &string = data.mid(*offset, length); *offset += length; return string; }
quint32 SshPacketParser::asUint32(const QByteArray &data, quint32 offset) { if (size(data) < offset + 4) throw SshPacketParseException(); const quint32 value = ((data.at(offset) & 0xff) << 24) + ((data.at(offset + 1) & 0xff) << 16) + ((data.at(offset + 2) & 0xff) << 8) + (data.at(offset + 3) & 0xff); return value; }
SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &pubKeyAlgo) const { Q_ASSERT(isComplete()); Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY); try { SshKeyExchangeReply replyData; quint32 offset = TypeOffset + 1; const quint32 k_sLength = SshPacketParser::asUint32(m_data, &offset); if (offset + k_sLength > currentDataSize()) throw SshPacketParseException(); replyData.k_s = m_data.mid(offset - 4, k_sLength + 4); if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) throw SshPacketParseException(); // DSS: p and q, RSA: e and n replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); // g and y if (pubKeyAlgo == SshCapabilities::PubKeyDss) { replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); replyData.parameters << SshPacketParser::asBigInt(m_data, &offset); } replyData.f = SshPacketParser::asBigInt(m_data, &offset); offset += 4; if (SshPacketParser::asString(m_data, &offset) != pubKeyAlgo) throw SshPacketParseException(); replyData.signatureBlob = SshPacketParser::asString(m_data, &offset); return replyData; } catch (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED, "Key exchange failed: " "Server sent invalid SSH_MSG_KEXDH_REPLY packet."); } }
quint64 SshPacketParser::asUint64(const QByteArray &data, quint32 offset) { if (size(data) < offset + 8) throw SshPacketParseException(); const quint64 value = (static_cast<quint64>(data.at(offset) & 0xff) << 56) + (static_cast<quint64>(data.at(offset + 1) & 0xff) << 48) + (static_cast<quint64>(data.at(offset + 2) & 0xff) << 40) + (static_cast<quint64>(data.at(offset + 3) & 0xff) << 32) + ((data.at(offset + 4) & 0xff) << 24) + ((data.at(offset + 5) & 0xff) << 16) + ((data.at(offset + 6) & 0xff) << 8) + (data.at(offset + 7) & 0xff); return value; }
SshNameList SshPacketParser::asNameList(const QByteArray &data, quint32 *offset) { const quint32 length = asUint32(data, offset); const int listEndPos = *offset + length; if (data.size() < listEndPos) throw SshPacketParseException(); SshNameList names(length + 4); int nextNameOffset = *offset; int nextCommaOffset = data.indexOf(',', nextNameOffset); while (nextNameOffset > 0 && nextNameOffset < listEndPos) { const int stringEndPos = nextCommaOffset == -1 || nextCommaOffset > listEndPos ? listEndPos : nextCommaOffset; names.names << QByteArray(data.constData() + nextNameOffset, stringEndPos - nextNameOffset); nextNameOffset = nextCommaOffset + 1; nextCommaOffset = data.indexOf(',', nextNameOffset); } *offset += length; return names; }
SshChannelExitStatus SshIncomingPacket::extractChannelExitStatus() const { Q_ASSERT(isComplete()); Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST); SshChannelExitStatus exitStatus; try { quint32 offset = TypeOffset + 1; exitStatus.localChannel = SshPacketParser::asUint32(m_data, &offset); const QByteArray &type = SshPacketParser::asString(m_data, &offset); Q_ASSERT(type == ExitStatusType); Q_UNUSED(type); if (SshPacketParser::asBool(m_data, &offset)) throw SshPacketParseException(); exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset); } catch (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid exit-status packet."); } return exitStatus; }
SshChannelExitSignal SshIncomingPacket::extractChannelExitSignal() const { Q_ASSERT(isComplete()); Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST); SshChannelExitSignal exitSignal; try { quint32 offset = TypeOffset + 1; exitSignal.localChannel = SshPacketParser::asUint32(m_data, &offset); const QByteArray &type = SshPacketParser::asString(m_data, &offset); Q_ASSERT(type == ExitSignalType); Q_UNUSED(type); if (SshPacketParser::asBool(m_data, &offset)) throw SshPacketParseException(); exitSignal.signal = SshPacketParser::asString(m_data, &offset); exitSignal.coreDumped = SshPacketParser::asBool(m_data, &offset); exitSignal.error = SshPacketParser::asUserString(m_data, &offset); exitSignal.language = SshPacketParser::asString(m_data, &offset); } catch (SshPacketParseException &) { throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Invalid exit-signal packet."); } return exitSignal; }
bool SshPacketParser::asBool(const QByteArray &data, quint32 offset) { if (size(data) <= offset) throw SshPacketParseException(); return data.at(offset); }