Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/network/kernel/qauthenticator.cpp

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 201 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation ([email protected])
     
    5151#include <qendian.h>
    5252#include <qstring.h>
     53
     54
     55
    5356
    5457QT_BEGIN_NAMESPACE
    5558
     59
    5660#include "../../3rdparty/des/des.cpp"
     61
    5762
    5863static QByteArray qNtlmPhase1();
     
    8489  Note that, in particular, NTLM version 2 is not supported.
    8590
     91
     92
     93
     94
     95
     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
    86129  \sa QSslSocket
    87130*/
     
    122165    if (d == other.d)
    123166        return *this;
    124     detach();
    125     d->user = other.d->user;
    126     d->password = other.d->password;
     167
     168    if (d && !d->ref.deref())
     169        delete d;
     170
     171    d = other.d;
     172    if (d)
     173        d->ref.ref();
    127174    return *this;
    128175}
     
    139186        && d->password == other.d->password
    140187        && d->realm == other.d->realm
    141         && d->method == other.d->method;
     188        && d->method == other.d->method
     189        && d->options == other.d->options;
    142190}
    143191
     
    163211{
    164212    detach();
    165     d->user = user;
     213    int separatorPosn = 0;
     214
     215    switch(d->method) {
     216    case QAuthenticatorPrivate::Ntlm:
     217        if((separatorPosn = user.indexOf(QLatin1String("\\"))) != -1) {
     218            //domain name is present
     219            d->realm.clear();
     220            d->userDomain = user.left(separatorPosn);
     221            d->extractedUser = user.mid(separatorPosn + 1);
     222            d->user = user;
     223        } else if((separatorPosn = user.indexOf(QLatin1String("@"))) != -1) {
     224            //domain name is present
     225            d->realm.clear();
     226            d->userDomain = user.left(separatorPosn);
     227            d->extractedUser = user.left(separatorPosn);
     228            d->user = user;
     229        } else {
     230            d->extractedUser = user;
     231            d->user = user;
     232            d->realm.clear();
     233            d->userDomain.clear();
     234        }
     235        break;
     236    default:
     237        d->user = user;
     238        d->userDomain.clear();
     239        break;
     240    }
    166241}
    167242
     
    206281}
    207282
    208 
    209 /*!
    210   returns true if the authenticator is null.
     283/*!
     284    \since 4.7
     285    Returns the value related to option \a opt if it was set by the server.
     286    See \l{QAuthenticator#Options} for more information on incoming options.
     287    If option \a opt isn't found, an invalid QVariant will be returned.
     288
     289    \sa options(), QAuthenticator#Options
     290*/
     291QVariant QAuthenticator::option(const QString &opt) const
     292{
     293    return d ? d->options.value(opt) : QVariant();
     294}
     295
     296/*!
     297    \since 4.7
     298    Returns all incoming options set in this QAuthenticator object by parsing
     299    the server reply. See \l{QAuthenticator#Options} for more information
     300    on incoming options.
     301
     302    \sa option(), QAuthenticator#Options
     303*/
     304QVariantHash QAuthenticator::options() const
     305{
     306    return d ? d->options : QVariantHash();
     307}
     308
     309/*!
     310    \since 4.7
     311
     312    Sets the outgoing option \a opt to value \a value.
     313    See \l{QAuthenticator#Options} for more information on outgoing options.
     314
     315    \sa options(), option(), QAuthenticator#Options
     316*/
     317void QAuthenticator::setOption(const QString &opt, const QVariant &value)
     318{
     319    detach();
     320    d->options.insert(opt, value);
     321}
     322
     323
     324/*!
     325    Returns true if the authenticator is null.
    211326*/
    212327bool QAuthenticator::isNull() const
     
    229344void QAuthenticatorPrivate::parseHttpResponse(const QHttpResponseHeader &header, bool isProxy)
    230345{
    231     QList<QPair<QString, QString> > values = header.values();
     346    const QList<QPair<QString, QString> > values = header.values();
     347    QList<QPair<QByteArray, QByteArray> > rawValues;
     348
     349    QList<QPair<QString, QString> >::const_iterator it, end;
     350    for (it = values.constBegin(), end = values.constEnd(); it != end; ++it)
     351        rawValues.append(qMakePair(it->first.toLatin1(), it->second.toUtf8()));
     352
     353    // continue in byte array form
     354    parseHttpResponse(rawValues, isProxy);
     355}
     356#endif
     357
     358void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy)
     359{
    232360    const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
    233361
     
    243371    */
    244372
    245     QString headerVal;
     373    Q headerVal;
    246374    for (int i = 0; i < values.size(); ++i) {
    247         const QPair<QString, QString> &current = values.at(i);
    248         if (current.first.toLower() != QLatin1String(search))
     375        const QPair<Q> &current = values.at(i);
     376        if (current.first.toLower() != )
    249377            continue;
    250         QString str = current.second;
    251         if (method < Basic && str.startsWith(QLatin1String("Basic"), Qt::CaseInsensitive)) {
    252             method = Basic; headerVal = str.mid(6);
    253         } else if (method < Ntlm && str.startsWith(QLatin1String("NTLM"), Qt::CaseInsensitive)) {
     378        QByteArray str = current.second.toLower();
     379        if (method < Basic && str.startsWith("basic")) {
     380            method = Basic;
     381            headerVal = current.second.mid(6);
     382        } else if (method < Ntlm && str.startsWith("ntlm")) {
    254383            method = Ntlm;
    255             headerVal = str.mid(5);
    256         } else if (method < DigestMd5 && str.startsWith(QLatin1String("Digest"), Qt::CaseInsensitive)) {
     384            headerVal = .mid(5);
     385        } else if (method < DigestMd5 && str.startsWith()) {
    257386            method = DigestMd5;
    258             headerVal = str.mid(7);
     387            headerVal = .mid(7);
    259388        }
    260389    }
    261390
    262     challenge = headerVal.trimmed().toLatin1();
     391    challenge = headerVal.trimmed();
    263392    QHash<QByteArray, QByteArray> options = parseDigestAuthenticationChallenge(challenge);
    264393
    265394    switch(method) {
    266395    case Basic:
    267         realm = QString::fromLatin1(options.value("realm"));
     396        if(realm.isEmpty())
     397            this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
    268398        if (user.isEmpty())
    269399            phase = Done;
     
    271401    case Ntlm:
    272402        // #### extract from header
    273         realm.clear();
    274403        break;
    275404    case DigestMd5: {
    276         realm = QString::fromLatin1(options.value("realm"));
     405        if(realm.isEmpty())
     406            this->options[QLatin1String("realm")] = realm = QString::fromLatin1(options.value("realm"));
    277407        if (options.value("stale").toLower() == "true")
    278408            phase = Start;
     
    287417    }
    288418}
    289 #endif
    290419
    291420QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path)
     
    662791#define NTLMSSP_NEGOTIATE_56 0x80000000
    663792
     793
     794
     795
     796
     797
     798
     799
     800
     801
     802
     803
     804
     805
     806
    664807
    665808/* usage:
     
    804947    // extracted
    805948    QString targetNameStr, targetInfoStr;
     949
    806950};
    807951
     
    819963    QByteArray lmResponseBuf, ntlmResponseBuf;
    820964    QString domainStr, userStr, workstationStr, sessionKeyStr;
     965
    821966};
    822967
     
    9001045}
    9011046
    902 
     1047#ifdef NTLMV1_CLIENT
    9031048static QByteArray qEncodeNtlmResponse(const QAuthenticatorPrivate *ctx, const QNtlmPhase2Block& ch)
    9041049{
     
    9421087    return rc;
    9431088}
    944 
     1089#endif
     1090
     1091/*********************************************************************
     1092* Function Name: qEncodeHmacMd5
     1093* Params:
     1094*    key:   Type - QByteArray
     1095*         - It is the Authentication key
     1096*    message:   Type - QByteArray
     1097*         - This is the actual message which will be encoded
     1098*           using HMacMd5 hash algorithm
     1099*
     1100* Return Value:
     1101*    hmacDigest:   Type - QByteArray
     1102*
     1103* Description:
     1104*    This function will be used to encode the input message using
     1105*    HMacMd5 hash algorithm.
     1106*
     1107*    As per the RFC2104 the HMacMd5 algorithm can be specified
     1108*        ---------------------------------------
     1109*         MD5(K XOR opad, MD5(K XOR ipad, text))
     1110*        ---------------------------------------
     1111*
     1112*********************************************************************/
     1113QByteArray qEncodeHmacMd5(QByteArray &key, const QByteArray &message)
     1114{
     1115    Q_ASSERT_X(!(message.isEmpty()),"qEncodeHmacMd5", "Empty message check");
     1116    Q_ASSERT_X(!(key.isEmpty()),"qEncodeHmacMd5", "Empty key check");
     1117
     1118    QCryptographicHash hash(QCryptographicHash::Md5);
     1119    QByteArray hMsg;
     1120
     1121    QByteArray iKeyPad(blockSize, 0x36);
     1122    QByteArray oKeyPad(blockSize, 0x5c);
     1123
     1124    hash.reset();
     1125    // Adjust the key length to blockSize
     1126
     1127    if(blockSize < key.length()) {
     1128        hash.addData(key);
     1129        key = hash.result(); //MD5 will always return 16 bytes length output
     1130    }
     1131
     1132    //Key will be <= 16 or 20 bytes as hash function (MD5 or SHA hash algorithms)
     1133    //key size can be max of Block size only
     1134    key = key.leftJustified(blockSize,0,true);
     1135
     1136    //iKeyPad, oKeyPad and key are all of same size "blockSize"
     1137
     1138    //xor of iKeyPad with Key and store the result into iKeyPad
     1139    for(int i = 0; i<key.size();i++) {
     1140        iKeyPad[i] = key[i]^iKeyPad[i];
     1141    }
     1142
     1143    //xor of oKeyPad with Key and store the result into oKeyPad
     1144    for(int i = 0; i<key.size();i++) {
     1145        oKeyPad[i] = key[i]^oKeyPad[i];
     1146    }
     1147
     1148    iKeyPad.append(message); // (K0 xor ipad) || text
     1149
     1150    hash.reset();
     1151    hash.addData(iKeyPad);
     1152    hMsg = hash.result();
     1153                    //Digest gen after pass-1: H((K0 xor ipad)||text)
     1154
     1155    QByteArray hmacDigest;
     1156    oKeyPad.append(hMsg);
     1157    hash.reset();
     1158    hash.addData(oKeyPad);
     1159    hmacDigest = hash.result();
     1160                    // H((K0 xor opad )|| H((K0 xor ipad) || text))
     1161
     1162    /*hmacDigest should not be less than half the length of the HMAC output
     1163      (to match the birthday attack bound) and not less than 80 bits
     1164      (a suitable lower bound on the number of bits that need to be
     1165      predicted by an attacker).
     1166      Refer RFC 2104 for more details on truncation part */
     1167
     1168    /*MD5 hash always returns 16 byte digest only and HMAC-MD5 spec
     1169      (RFC 2104) also says digest length should be 16 bytes*/
     1170    return hmacDigest;
     1171}
     1172
     1173static QByteArray qCreatev2Hash(const QAuthenticatorPrivate *ctx,
     1174                                QNtlmPhase3Block *phase3)
     1175{
     1176    Q_ASSERT(phase3 != 0);
     1177    // since v2 Hash is need for both NTLMv2 and LMv2 it is calculated
     1178    // only once and stored and reused
     1179    if(phase3->v2Hash.size() == 0) {
     1180        QCryptographicHash md4(QCryptographicHash::Md4);
     1181        QByteArray passUnicode = qStringAsUcs2Le(ctx->password);
     1182        md4.addData(passUnicode.data(), passUnicode.size());
     1183
     1184        QByteArray hashKey = md4.result();
     1185        Q_ASSERT(hashKey.size() == 16);
     1186        // Assuming the user and domain is always unicode in challenge
     1187        QByteArray message =
     1188                qStringAsUcs2Le(ctx->extractedUser.toUpper()) +
     1189                qStringAsUcs2Le(phase3->domainStr);
     1190
     1191        phase3->v2Hash = qEncodeHmacMd5(hashKey, message);
     1192    }
     1193    return phase3->v2Hash;
     1194}
     1195
     1196static QByteArray clientChallenge(const QAuthenticatorPrivate *ctx)
     1197{
     1198    Q_ASSERT(ctx->cnonce.size() >= 8);
     1199    QByteArray clientCh = ctx->cnonce.right(8);
     1200    return clientCh;
     1201}
     1202
     1203// caller has to ensure a valid targetInfoBuff
     1204static QByteArray qExtractServerTime(const QByteArray& targetInfoBuff)
     1205{
     1206    QByteArray timeArray;
     1207    QDataStream ds(targetInfoBuff);
     1208    ds.setByteOrder(QDataStream::LittleEndian);
     1209
     1210    quint16 avId;
     1211    quint16 avLen;
     1212
     1213    ds >> avId;
     1214    ds >> avLen;
     1215    while(avId != 0) {
     1216        if(avId == AVTIMESTAMP) {
     1217            timeArray.resize(avLen);
     1218            //avLen size of QByteArray is allocated
     1219            ds.readRawData(timeArray.data(), avLen);
     1220            break;
     1221        }
     1222        ds.skipRawData(avLen);
     1223        ds >> avId;
     1224        ds >> avLen;
     1225    }
     1226    return timeArray;
     1227}
     1228
     1229static QByteArray qEncodeNtlmv2Response(const QAuthenticatorPrivate *ctx,
     1230                                        const QNtlmPhase2Block& ch,
     1231                                        QNtlmPhase3Block *phase3)
     1232{
     1233    Q_ASSERT(phase3 != 0);
     1234    // return value stored in phase3
     1235    qCreatev2Hash(ctx, phase3);
     1236
     1237    QByteArray temp;
     1238    QDataStream ds(&temp, QIODevice::WriteOnly);
     1239    ds.setByteOrder(QDataStream::LittleEndian);
     1240
     1241    ds << respversion;
     1242    ds << hirespversion;
     1243
     1244    //Reserved
     1245    QByteArray reserved1(6, 0);
     1246    ds.writeRawData(reserved1.constData(), reserved1.size());
     1247
     1248    quint64 time = 0;
     1249    QByteArray timeArray;
     1250
     1251    if(ch.targetInfo.len)
     1252    {
     1253        timeArray = qExtractServerTime(ch.targetInfoBuff);
     1254    }
     1255
     1256    //if server sends time, use it instead of current time
     1257    if(timeArray.size()) {
     1258        ds.writeRawData(timeArray.constData(), timeArray.size());
     1259    } else {
     1260        QDateTime currentTime(QDate::currentDate(),
     1261                              QTime::currentTime(), Qt::UTC);
     1262
     1263        // number of seconds between 1601 and epoc(1970)
     1264        // 369 years, 89 leap years
     1265        // ((369 * 365) + 89) * 24 * 3600 = 11644473600
     1266
     1267        time = Q_UINT64_C(currentTime.toTime_t() + 11644473600);
     1268
     1269        // represented as 100 nano seconds
     1270        time = Q_UINT64_C(time * 10000000);
     1271        ds << time;
     1272    }
     1273
     1274    //8 byte client challenge
     1275    QByteArray clientCh = clientChallenge(ctx);
     1276    ds.writeRawData(clientCh.constData(), clientCh.size());
     1277
     1278    //Reserved
     1279    QByteArray reserved2(4, 0);
     1280    ds.writeRawData(reserved2.constData(), reserved2.size());
     1281
     1282    if (ch.targetInfo.len > 0) {
     1283        ds.writeRawData(ch.targetInfoBuff.constData(),
     1284                        ch.targetInfoBuff.size());
     1285    }
     1286
     1287    //Reserved
     1288    QByteArray reserved3(4, 0);
     1289    ds.writeRawData(reserved3.constData(), reserved3.size());
     1290
     1291    QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
     1292    message.append(temp);
     1293
     1294    QByteArray ntChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
     1295    ntChallengeResp.append(temp);
     1296
     1297    return ntChallengeResp;
     1298}
     1299
     1300static QByteArray qEncodeLmv2Response(const QAuthenticatorPrivate *ctx,
     1301                                      const QNtlmPhase2Block& ch,
     1302                                      QNtlmPhase3Block *phase3)
     1303{
     1304    Q_ASSERT(phase3 != 0);
     1305    // return value stored in phase3
     1306    qCreatev2Hash(ctx, phase3);
     1307
     1308    QByteArray message((const char*)ch.challenge, sizeof(ch.challenge));
     1309    QByteArray clientCh = clientChallenge(ctx);
     1310
     1311    message.append(clientCh);
     1312
     1313    QByteArray lmChallengeResp = qEncodeHmacMd5(phase3->v2Hash, message);
     1314    lmChallengeResp.append(clientCh);
     1315
     1316    return lmChallengeResp;
     1317}
    9451318
    9461319static bool qNtlmDecodePhase2(const QByteArray& data, QNtlmPhase2Block& ch)
     
    9771350
    9781351    if (ch.targetInfo.len > 0) {
    979         // UNUSED right now
     1352        if (ch.targetInfo.len + ch.targetInfo.offset > (unsigned)data.size())
     1353            return false;
     1354
     1355        ch.targetInfoBuff = data.mid(ch.targetInfo.offset, ch.targetInfo.len);
    9801356    }
    9811357
     
    9961372
    9971373    bool unicode = ch.flags & NTLMSSP_NEGOTIATE_UNICODE;
    998 
    999     ctx->realm = ch.targetNameStr;
    10001374
    10011375    pb.flags = NTLMSSP_NEGOTIATE_NTLM;
     
    10091383    Q_ASSERT(QNtlmPhase3BlockBase::Size == sizeof(QNtlmPhase3BlockBase));
    10101384   
    1011     offset = qEncodeNtlmString(pb.domain, offset, ctx->realm, unicode);
    1012     pb.domainStr = ctx->realm;
    1013     offset = qEncodeNtlmString(pb.user, offset, ctx->user, unicode);
    1014     pb.userStr = ctx->user;
     1385    if(ctx->userDomain.isEmpty()) {
     1386        offset = qEncodeNtlmString(pb.domain, offset, ch.targetNameStr, unicode);
     1387        pb.domainStr = ch.targetNameStr;
     1388    } else {
     1389        offset = qEncodeNtlmString(pb.domain, offset, ctx->userDomain, unicode);
     1390        pb.domainStr = ctx->userDomain;
     1391    }
     1392
     1393    offset = qEncodeNtlmString(pb.user, offset, ctx->extractedUser, unicode);
     1394    pb.userStr = ctx->extractedUser;
    10151395
    10161396    offset = qEncodeNtlmString(pb.workstation, offset, ctx->workstation, unicode);
     
    10181398
    10191399    // Get LM response
     1400
    10201401    pb.lmResponseBuf = qEncodeLmResponse(ctx, ch);
     1402
     1403
     1404
     1405
     1406
     1407
     1408
    10211409    offset = qEncodeNtlmBuffer(pb.lmResponse, offset, pb.lmResponseBuf);
    10221410
    10231411    // Get NTLM response
     1412
    10241413    pb.ntlmResponseBuf = qEncodeNtlmResponse(ctx, ch);
     1414
     1415
     1416
    10251417    offset = qEncodeNtlmBuffer(pb.ntlmResponse, offset, pb.ntlmResponseBuf);
    10261418
Note: See TracChangeset for help on using the changeset viewer.