sshincomingpacket.cpp 19.3 KB
Newer Older
hjk's avatar
hjk committed
1
/****************************************************************************
ck's avatar
ck committed
2
**
Eike Ziller's avatar
Eike Ziller committed
3 4
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing
ck's avatar
ck committed
5
**
hjk's avatar
hjk committed
6
** This file is part of Qt Creator.
ck's avatar
ck committed
7
**
hjk's avatar
hjk committed
8 9 10 11
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
Eike Ziller's avatar
Eike Ziller committed
12 13
** a written agreement between you and The Qt Company.  For licensing terms and
** conditions see http://www.qt.io/terms-conditions.  For further information
Eike Ziller's avatar
Eike Ziller committed
14
** use the contact form at http://www.qt.io/contact-us.
ck's avatar
ck committed
15 16
**
** GNU Lesser General Public License Usage
hjk's avatar
hjk committed
17
** Alternatively, this file may be used under the terms of the GNU Lesser
Eike Ziller's avatar
Eike Ziller committed
18 19 20 21 22 23
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file.  Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
ck's avatar
ck committed
24
**
Eike Ziller's avatar
Eike Ziller committed
25 26
** In addition, as a special exception, The Qt Company gives you certain additional
** rights.  These rights are described in The Qt Company LGPL Exception
con's avatar
con committed
27 28
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
hjk's avatar
hjk committed
29
****************************************************************************/
ck's avatar
ck committed
30 31 32

#include "sshincomingpacket_p.h"

33
#include "ssh_global.h"
34
#include "sshbotanconversions_p.h"
ck's avatar
ck committed
35 36
#include "sshcapabilities_p.h"

37
namespace QSsh {
ck's avatar
ck committed
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
namespace Internal {

const QByteArray SshIncomingPacket::ExitStatusType("exit-status");
const QByteArray SshIncomingPacket::ExitSignalType("exit-signal");

SshIncomingPacket::SshIncomingPacket() : m_serverSeqNr(0) { }

quint32 SshIncomingPacket::cipherBlockSize() const
{
    return qMax(m_decrypter.cipherBlockSize(), 8U);
}

quint32 SshIncomingPacket::macLength() const
{
    return m_decrypter.macLength();
}

void SshIncomingPacket::recreateKeys(const SshKeyExchange &keyExchange)
{
    m_decrypter.recreateKeys(keyExchange);
}

void SshIncomingPacket::reset()
{
    clear();
    m_serverSeqNr = 0;
    m_decrypter.clearKeys();
}

void SshIncomingPacket::consumeData(QByteArray &newData)
{
#ifdef CREATOR_SSH_DEBUG
    qDebug("%s: current data size = %d, new data size = %d",
        Q_FUNC_INFO, m_data.size(), newData.size());
#endif

    if (isComplete() || newData.isEmpty())
        return;

    /*
     * Until we have reached the minimum packet size, we cannot decrypt the
     * length field.
     */
    const quint32 minSize = minPacketSize();
    if (currentDataSize() < minSize) {
        const int bytesToTake
            = qMin<quint32>(minSize - currentDataSize(), newData.size());
        moveFirstBytes(m_data, newData, bytesToTake);
#ifdef CREATOR_SSH_DEBUG
        qDebug("Took %d bytes from new data", bytesToTake);
#endif
        if (currentDataSize() < minSize)
            return;
    }

93 94 95
    if (4 + length() + macLength() < currentDataSize())
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR, "Server sent invalid packet.");

ck's avatar
ck committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
    const int bytesToTake
        = qMin<quint32>(length() + 4 + macLength() - currentDataSize(),
              newData.size());
    moveFirstBytes(m_data, newData, bytesToTake);
#ifdef CREATOR_SSH_DEBUG
    qDebug("Took %d bytes from new data", bytesToTake);
#endif
    if (isComplete()) {
#ifdef CREATOR_SSH_DEBUG
        qDebug("Message complete. Overall size: %u, payload size: %u",
            m_data.size(), m_length - paddingLength() - 1);
#endif
        decrypt();
        ++m_serverSeqNr;
    }
}

void SshIncomingPacket::decrypt()
{
    Q_ASSERT(isComplete());
    const quint32 netDataLength = length() + 4;
    m_decrypter.decrypt(m_data, cipherBlockSize(),
        netDataLength - cipherBlockSize());
    const QByteArray &mac = m_data.mid(netDataLength, macLength());
    if (mac != generateMac(m_decrypter, m_serverSeqNr)) {
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_MAC_ERROR,
                           "Message authentication failed.");
    }
}

void SshIncomingPacket::moveFirstBytes(QByteArray &target, QByteArray &source,
    int n)
{
    target.append(source.left(n));
    source.remove(0, n);
}

SshKeyExchangeInit SshIncomingPacket::extractKeyExchangeInitData() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_KEXINIT);

    SshKeyExchangeInit exchangeData;
    try {
        quint32 offset = TypeOffset + 1;
        std::memcpy(exchangeData.cookie, &m_data.constData()[offset],
                    sizeof exchangeData.cookie);
        offset += sizeof exchangeData.cookie;
        exchangeData.keyAlgorithms
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.serverHostKeyAlgorithms
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.encryptionAlgorithmsClientToServer
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.encryptionAlgorithmsServerToClient
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.macAlgorithmsClientToServer
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.macAlgorithmsServerToClient
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.compressionAlgorithmsClientToServer
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.compressionAlgorithmsServerToClient
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.languagesClientToServer
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.languagesServerToClient
            = SshPacketParser::asNameList(m_data, &offset);
        exchangeData.firstKexPacketFollows
            = SshPacketParser::asBool(m_data, &offset);
166
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
167 168 169 170 171 172
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
            "Key exchange failed: Server sent invalid SSH_MSG_KEXINIT packet.");
    }
    return exchangeData;
}

173 174 175 176 177 178
static void getHostKeySpecificReplyData(SshKeyExchangeReply &replyData,
                                        const QByteArray &hostKeyAlgo, const QByteArray &input)
{
    quint32 offset = 0;
    if (hostKeyAlgo == SshCapabilities::PubKeyDss || hostKeyAlgo == SshCapabilities::PubKeyRsa) {
        // DSS: p and q, RSA: e and n
179 180
        replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
        replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
181 182 183

        // g and y
        if (hostKeyAlgo == SshCapabilities::PubKeyDss) {
184 185
            replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
            replyData.hostKeyParameters << SshPacketParser::asBigInt(input, &offset);
186 187
        }
    } else {
188
        QSSH_ASSERT_AND_RETURN(hostKeyAlgo == SshCapabilities::PubKeyEcdsa256);
189 190 191 192 193 194 195 196 197 198
        if (SshPacketParser::asString(input, &offset)
                != hostKeyAlgo.mid(11)) { // Without "ecdsa-sha2-" prefix.
            throw SshPacketParseException();
        }
        replyData.q = SshPacketParser::asString(input, &offset);
    }
}

SshKeyExchangeReply SshIncomingPacket::extractKeyExchangeReply(const QByteArray &kexAlgo,
                                                               const QByteArray &hostKeyAlgo) const
ck's avatar
ck committed
199 200 201 202 203 204
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_KEXDH_REPLY);

    try {
        SshKeyExchangeReply replyData;
205 206 207
        quint32 topLevelOffset = TypeOffset + 1;
        replyData.k_s = SshPacketParser::asString(m_data, &topLevelOffset);
        quint32 k_sOffset = 0;
208
        if (SshPacketParser::asString(replyData.k_s, &k_sOffset) != hostKeyAlgo)
ck's avatar
ck committed
209
            throw SshPacketParseException();
210
        getHostKeySpecificReplyData(replyData, hostKeyAlgo, replyData.k_s.mid(k_sOffset));
ck's avatar
ck committed
211

212
        if (kexAlgo == SshCapabilities::DiffieHellmanGroup1Sha1) {
213 214
            replyData.f = SshPacketParser::asBigInt(m_data, &topLevelOffset);
        } else {
215 216
            QSSH_ASSERT_AND_RETURN_VALUE(kexAlgo.startsWith(SshCapabilities::EcdhKexNamePrefix),
                                         SshKeyExchangeReply());
217
            replyData.q_s = SshPacketParser::asString(m_data, &topLevelOffset);
ck's avatar
ck committed
218
        }
219 220
        const QByteArray fullSignature = SshPacketParser::asString(m_data, &topLevelOffset);
        quint32 sigOffset = 0;
221
        if (SshPacketParser::asString(fullSignature, &sigOffset) != hostKeyAlgo)
ck's avatar
ck committed
222
            throw SshPacketParseException();
223
        replyData.signatureBlob = SshPacketParser::asString(fullSignature, &sigOffset);
224
        if (hostKeyAlgo == SshCapabilities::PubKeyEcdsa256) {
225 226 227 228 229 230 231 232
            // Botan's PK_Verifier wants the signature in this format.
            quint32 blobOffset = 0;
            const Botan::BigInt r = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
            const Botan::BigInt s = SshPacketParser::asBigInt(replyData.signatureBlob, &blobOffset);
            replyData.signatureBlob = convertByteArray(Botan::BigInt::encode(r));
            replyData.signatureBlob += convertByteArray(Botan::BigInt::encode(s));
        }
        replyData.k_s.prepend(m_data.mid(TypeOffset + 1, 4));
ck's avatar
ck committed
233
        return replyData;
234
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
235 236
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
            "Key exchange failed: "
237
            "Server sent invalid key exchange reply packet.");
ck's avatar
ck committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251
    }
}

SshDisconnect SshIncomingPacket::extractDisconnect() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_DISCONNECT);

    SshDisconnect msg;
    try {
        quint32 offset = TypeOffset + 1;
        msg.reasonCode = SshPacketParser::asUint32(m_data, &offset);
        msg.description = SshPacketParser::asUserString(m_data, &offset);
        msg.language = SshPacketParser::asString(m_data, &offset);
252
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_DISCONNECT.");
    }

    return msg;
}

SshUserAuthBanner SshIncomingPacket::extractUserAuthBanner() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_USERAUTH_BANNER);

    try {
        SshUserAuthBanner msg;
        quint32 offset = TypeOffset + 1;
        msg.message = SshPacketParser::asUserString(m_data, &offset);
        msg.language = SshPacketParser::asString(m_data, &offset);
        return msg;
271
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
272 273 274 275 276
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_USERAUTH_BANNER.");
    }
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
SshUserAuthInfoRequestPacket SshIncomingPacket::extractUserAuthInfoRequest() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_USERAUTH_INFO_REQUEST);

    try {
        SshUserAuthInfoRequestPacket msg;
        quint32 offset = TypeOffset + 1;
        msg.name = SshPacketParser::asUserString(m_data, &offset);
        msg.instruction = SshPacketParser::asUserString(m_data, &offset);
        msg.languageTag = SshPacketParser::asString(m_data, &offset);
        const quint32 promptCount = SshPacketParser::asUint32(m_data, &offset);
        msg.prompts.reserve(promptCount);
        msg.echos.reserve(promptCount);
        for (quint32 i = 0; i < promptCount; ++i) {
            msg.prompts << SshPacketParser::asUserString(m_data, &offset);
            msg.echos << SshPacketParser::asBool(m_data, &offset);
        }
        return msg;
296
    } catch (const SshPacketParseException &) {
297 298 299 300 301
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_USERAUTH_INFO_REQUEST.");
    }
}

ck's avatar
ck committed
302 303 304 305 306 307 308 309 310 311 312 313
SshDebug SshIncomingPacket::extractDebug() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_DEBUG);

    try {
        SshDebug msg;
        quint32 offset = TypeOffset + 1;
        msg.display = SshPacketParser::asBool(m_data, &offset);
        msg.message = SshPacketParser::asUserString(m_data, &offset);
        msg.language = SshPacketParser::asString(m_data, &offset);
        return msg;
314
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
315
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
316 317 318 319 320 321 322 323 324 325 326 327 328 329
            "Invalid SSH_MSG_DEBUG.");
    }
}

SshUnimplemented SshIncomingPacket::extractUnimplemented() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_UNIMPLEMENTED);

    try {
        SshUnimplemented msg;
        quint32 offset = TypeOffset + 1;
        msg.invalidMsgSeqNr = SshPacketParser::asUint32(m_data, &offset);
        return msg;
330
    } catch (const SshPacketParseException &) {
331 332
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_UNIMPLEMENTED.");
ck's avatar
ck committed
333 334 335 336 337 338 339 340 341 342 343 344 345
    }
}

SshChannelOpenFailure SshIncomingPacket::extractChannelOpenFailure() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_FAILURE);

    SshChannelOpenFailure openFailure;
    try {
        quint32 offset = TypeOffset + 1;
        openFailure.localChannel = SshPacketParser::asUint32(m_data, &offset);
        openFailure.reasonCode = SshPacketParser::asUint32(m_data, &offset);
346
        openFailure.reasonString = QString::fromLocal8Bit(SshPacketParser::asString(m_data, &offset));
ck's avatar
ck committed
347
        openFailure.language = SshPacketParser::asString(m_data, &offset);
348
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Server sent invalid SSH_MSG_CHANNEL_OPEN_FAILURE packet.");
    }
    return openFailure;
}

SshChannelOpenConfirmation SshIncomingPacket::extractChannelOpenConfirmation() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_OPEN_CONFIRMATION);

    SshChannelOpenConfirmation confirmation;
    try {
        quint32 offset = TypeOffset + 1;
        confirmation.localChannel = SshPacketParser::asUint32(m_data, &offset);
        confirmation.remoteChannel = SshPacketParser::asUint32(m_data, &offset);
        confirmation.remoteWindowSize = SshPacketParser::asUint32(m_data, &offset);
        confirmation.remoteMaxPacketSize = SshPacketParser::asUint32(m_data, &offset);
367
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Server sent invalid SSH_MSG_CHANNEL_OPEN_CONFIRMATION packet.");
    }
    return confirmation;
}

SshChannelWindowAdjust SshIncomingPacket::extractWindowAdjust() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_WINDOW_ADJUST);

    SshChannelWindowAdjust adjust;
    try {
        quint32 offset = TypeOffset + 1;
        adjust.localChannel = SshPacketParser::asUint32(m_data, &offset);
        adjust.bytesToAdd = SshPacketParser::asUint32(m_data, &offset);
384
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_CHANNEL_WINDOW_ADJUST packet.");
    }
    return adjust;
}

SshChannelData SshIncomingPacket::extractChannelData() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_DATA);

    SshChannelData data;
    try {
        quint32 offset = TypeOffset + 1;
        data.localChannel = SshPacketParser::asUint32(m_data, &offset);
        data.data = SshPacketParser::asString(m_data, &offset);
401
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_CHANNEL_DATA packet.");
    }
    return data;
}

SshChannelExtendedData SshIncomingPacket::extractChannelExtendedData() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_EXTENDED_DATA);

    SshChannelExtendedData data;
    try {
        quint32 offset = TypeOffset + 1;
        data.localChannel = SshPacketParser::asUint32(m_data, &offset);
        data.type = SshPacketParser::asUint32(m_data, &offset);
        data.data = SshPacketParser::asString(m_data, &offset);
419
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_CHANNEL_EXTENDED_DATA packet.");
    }
    return data;
}

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);
437
        Q_UNUSED(type);
ck's avatar
ck committed
438 439 440
        if (SshPacketParser::asBool(m_data, &offset))
            throw SshPacketParseException();
        exitStatus.exitStatus = SshPacketParser::asUint32(m_data, &offset);
441
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
        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);
459
        Q_UNUSED(type);
ck's avatar
ck committed
460 461 462 463 464 465
        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);
466
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
467 468 469 470 471 472 473 474 475 476 477 478 479
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid exit-signal packet.");
    }
    return exitSignal;
}

quint32 SshIncomingPacket::extractRecipientChannel() const
{
    Q_ASSERT(isComplete());

    try {
        quint32 offset = TypeOffset + 1;
        return SshPacketParser::asUint32(m_data, &offset);
480
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Server sent invalid packet.");
    }
}

QByteArray SshIncomingPacket::extractChannelRequestType() const
{
    Q_ASSERT(isComplete());
    Q_ASSERT(type() == SSH_MSG_CHANNEL_REQUEST);

    try {
        quint32 offset = TypeOffset + 1;
        SshPacketParser::asUint32(m_data, &offset);
        return SshPacketParser::asString(m_data, &offset);
495
    } catch (const SshPacketParseException &) {
ck's avatar
ck committed
496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
        throw SSH_SERVER_EXCEPTION(SSH_DISCONNECT_PROTOCOL_ERROR,
            "Invalid SSH_MSG_CHANNEL_REQUEST packet.");
    }
}

void SshIncomingPacket::calculateLength() const
{
    Q_ASSERT(currentDataSize() >= minPacketSize());
#ifdef CREATOR_SSH_DEBUG
    qDebug("Length field before decryption: %d-%d-%d-%d", m_data.at(0) & 0xff,
        m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
#endif
    m_decrypter.decrypt(m_data, 0, cipherBlockSize());
#ifdef CREATOR_SSH_DEBUG
    qDebug("Length field after decryption: %d-%d-%d-%d", m_data.at(0) & 0xff, m_data.at(1) & 0xff, m_data.at(2) & 0xff, m_data.at(3) & 0xff);
    qDebug("message type = %d", m_data.at(TypeOffset));
#endif
    m_length = SshPacketParser::asUint32(m_data, static_cast<quint32>(0));
#ifdef CREATOR_SSH_DEBUG
    qDebug("decrypted length is %u", m_length);
#endif
}

} // namespace Internal
520
} // namespace QSsh