qsslsocket_openssl.cpp

来自「奇趣公司比较新的qt/emd版本」· C++ 代码 · 共 773 行 · 第 1/2 页

CPP
773
字号
    }    return true;}/*!    \internal    Declared static in QSslSocketPrivate, backend-dependent loading of    application-wide global ciphers.*/void QSslSocketPrivate::resetDefaultCiphers(){    SSL_CTX *myCtx = q_SSL_CTX_new(q_SSLv23_client_method());    SSL *mySsl = q_SSL_new(myCtx);    QList<QSslCipher> ciphers;    STACK_OF(SSL_CIPHER) *supportedCiphers = q_SSL_get_ciphers(mySsl);    for (int i = 0; i < q_sk_SSL_CIPHER_num(supportedCiphers); ++i) {        if (SSL_CIPHER *cipher = q_sk_SSL_CIPHER_value(supportedCiphers, i)) {            if (cipher->valid) {                QSslCipher ciph = QSslSocketBackendPrivate::QSslCipher_from_SSL_CIPHER(cipher);                if (!ciph.isNull()) {                    if (!ciph.name().toLower().startsWith(QLatin1String("adh")))                        ciphers << ciph;                }            }        }    }    q_SSL_CTX_free(myCtx);    q_SSL_free(mySsl);    setDefaultSupportedCiphers(ciphers);    setDefaultCiphers(ciphers);}QList<QSslCertificate> QSslSocketPrivate::systemCaCertificates(){#ifdef QQ_OS_UNIX    // Check known locations for the system's default bundle.  ### On Windows,    // we should use CAPI to find the bundle, and not rely on default unix    // locations.    const char *standardLocations[] = {"/etc/ssl/certs/",#if 0                                       // KDE uses KConfig for its SSL store,                                       // but it also stores the bundle at                                       // this location                                       "$HOME/.kde/share/apps/kssl/ca-bundle.crt",#endif                                       0};    const char **it = standardLocations;    QStringList nameFilter;    nameFilter << QLatin1String("*.pem") << QLatin1String("*.crt");    while (*it) {        if (QDirIterator(QLatin1String(*it), nameFilter).hasNext())            return certificatesFromPath(QLatin1String(*it));        ++it;    }#endif    // Qt provides a default bundle when we cannot detect the system's default    // bundle.    QFile caBundle(QLatin1String(":/trolltech/network/ssl/qt-ca-bundle.crt"));    if (caBundle.open(QIODevice::ReadOnly | QIODevice::Text))        return QSslCertificate::fromDevice(&caBundle);    // Unreachable; return no bundle.    return QList<QSslCertificate>();}void QSslSocketBackendPrivate::startClientEncryption(){    if (!initSslContext()) {        // ### report error: internal OpenSSL failure        return;    }    // Start connecting. This will place outgoing data in the BIO, so we    // follow up with calling transmit().    testConnection();    transmit();}void QSslSocketBackendPrivate::startServerEncryption(){    if (!initSslContext()) {        // ### report error: internal OpenSSL failure        return;    }    // Start connecting. This will place outgoing data in the BIO, so we    // follow up with calling transmit().    testConnection();    transmit();}/*!    \internal    Transmits encrypted data between the BIOs and the socket.*/void QSslSocketBackendPrivate::transmit(){    Q_Q(QSslSocket);    // If we don't have any SSL context, don't bother transmitting.    if (!ssl)        return;    bool transmitting;    do {        transmitting = false;                // If the connection is secure, we can transfer data from the write        // buffer (in plain text) to the write BIO through SSL_write.        if (connectionEncrypted && !writeBuffer.isEmpty()) {            int nextDataBlockSize;            while ((nextDataBlockSize = writeBuffer.nextDataBlockSize()) > 0) {                int writtenBytes = q_SSL_write(ssl, writeBuffer.readPointer(), nextDataBlockSize);                if (writtenBytes <= 0) {                    // ### Better error handling.                    q->setErrorString(QSslSocket::tr("Unable to write data: %1").arg(SSL_ERRORSTR()));                    q->setSocketError(QAbstractSocket::UnknownSocketError);                    emit q->error(QAbstractSocket::UnknownSocketError);                    return;                }                writeBuffer.free(writtenBytes);            }        }        // Check if we've got any data to be written to the socket.        QVarLengthArray<char, 4096> data;        int pendingBytes;        while (plainSocket->isValid() && (pendingBytes = q_BIO_pending(writeBio)) > 0) {            // Read encrypted data from the write BIO into a buffer.            data.resize(pendingBytes);            int encryptedBytesRead = q_BIO_read(writeBio, data.data(), pendingBytes);            // Write encrypted data from the buffer to the socket.            plainSocket->write(data.constData(), encryptedBytesRead);            transmitting = true;        }        // Check if we've got any data to be read from the socket.        while ((pendingBytes = plainSocket->bytesAvailable()) > 0) {            // Read encrypted data from the socket into a buffer.            data.resize(pendingBytes);            int decryptedBytesRead = plainSocket->read(data.data(), pendingBytes);            // Write encrypted data from the buffer into the read BIO.            q_BIO_write(readBio, data.constData(), decryptedBytesRead);            transmitting = true;        }        // If the connection isn't secured yet, this is the time to retry the        // connect / accept.        if (!connectionEncrypted) {            if (testConnection()) {                connectionEncrypted = true;                transmitting = true;            } else if (plainSocket->state() != QAbstractSocket::ConnectedState) {                break;            }        }        int readBytes = 0;        data.resize(4096);        ::memset(data.data(), 0, data.size());        do {            // Don't use SSL_pending(). It's very unreliable.            if ((readBytes = q_SSL_read(ssl, data.data(), data.size())) > 0) {                char *ptr = readBuffer.reserve(readBytes);                ::memcpy(ptr, data.data(), readBytes);                emit q->readyRead();                transmitting = true;                continue;            }            // Error.            switch (q_SSL_get_error(ssl, readBytes)) {            case SSL_ERROR_WANT_READ:            case SSL_ERROR_WANT_WRITE:                // Out of data.                break;            case SSL_ERROR_ZERO_RETURN:                // The remote host closed the connection.                plainSocket->disconnectFromHost();                break;            default:                // ### Handle errors better.                q->setErrorString(QSslSocket::tr("Error while reading: %1").arg(SSL_ERRORSTR()));                q->setSocketError(QAbstractSocket::UnknownSocketError);                emit q->error(QAbstractSocket::UnknownSocketError);                break;            }        } while (ssl && readBytes > 0);    } while (ssl && ctx && transmitting);}bool QSslSocketBackendPrivate::testConnection(){    Q_Q(QSslSocket);    // Check if the connection has been established. Get all errors from the    // verification stage.    _q_sslErrorList()->mutex.lock();    _q_sslErrorList()->errors.clear();    int result = (mode == QSslSocket::SslClientMode) ? q_SSL_connect(ssl) : q_SSL_accept(ssl);    errorList << _q_sslErrorList()->errors;    _q_sslErrorList()->mutex.unlock();    // Check if we're encrypted or not.    if (result <= 0) {        switch (q_SSL_get_error(ssl, result)) {        case SSL_ERROR_WANT_READ:        case SSL_ERROR_WANT_WRITE:            // The handshake is not yet complete.            break;        default:            // ### Handle errors better            q->setErrorString(QSslSocket::tr("Error during SSL handshake: %1").arg(SSL_ERRORSTR()));            q->setSocketError(QAbstractSocket::UnknownSocketError);            emit q->error(QAbstractSocket::UnknownSocketError);            q->abort();        }        return false;    }    // Store the peer certificate and chain. For clients, the peer certificate    // chain includes the peer certificate; for servers, it doesn't. Both the    // peer certificate and the chain may be empty if the peer didn't present    // any certificate.    peerCertificateChain = STACKOFX509_to_QSslCertificates(q_SSL_get_peer_cert_chain(ssl));    X509 *x509 = q_SSL_get_peer_certificate(ssl);    peerCertificate = QSslCertificatePrivate::QSslCertificate_from_X509(x509);    q_X509_free(x509);    // This is now.    QDateTime now = QDateTime::currentDateTime();    QList<QSslError> errors;    // Check all certificates in the certificate chain.    foreach (QSslCertificate cert, peerCertificateChain) {        // Check for certificate validity        if (cert.effectiveDate() >= now) {            errors << QSslError(QSslError::CertificateNotYetValid);        } else if (cert.expiryDate() <= now) {            errors << QSslError(QSslError::CertificateExpired);        }    }    // Check the peer certificate itself. First try the subject's common name    // (CN) as a wildcard, then try all alternate subject name DNS entries the    // same way.    if (!peerCertificate.isNull()) {        QString peerName = q->peerName();        QString commonName = peerCertificate.subjectInfo(QSslCertificate::CommonName);        QRegExp regexp(commonName, Qt::CaseInsensitive, QRegExp::Wildcard);        if (!regexp.exactMatch(peerName)) {            bool matched = false;            foreach (QString altName, peerCertificate.alternateSubjectNames().values(QSsl::DnsEntry)) {                regexp.setPattern(altName);                if (regexp.exactMatch(peerName)) {                    matched = true;                    break;                }            }            if (!matched) {                // No matches in common names or alternate names.                errors << QSslError(QSslError::HostNameMismatch);            }        }    } else {        errors << QSslError(QSslError::NoPeerCertificate);    }    // Verify the authenticity of the certificate. This code should really go    // into QSslCertificate.  ### Crude and inefficient.    // Check if the certificate is OK.    for (int i = 0; i < errorList.size(); ++i) {        int err = errorList.at(i);        switch (err) {        case X509_V_OK:            // X509_V_OK is also reported if the peer had no certificate.            break;        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:            errors << QSslError(QSslError::UnableToGetIssuerCertificate); break;        case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:            errors << QSslError(QSslError::UnableToDecryptCertificateSignature); break;        case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:            errors << QSslError(QSslError::UnableToDecodeIssuerPublicKey); break;        case X509_V_ERR_CERT_SIGNATURE_FAILURE:            errors << QSslError(QSslError::CertificateSignatureFailed); break;        case X509_V_ERR_CERT_NOT_YET_VALID:            errors << QSslError(QSslError::CertificateNotYetValid); break;        case X509_V_ERR_CERT_HAS_EXPIRED:            errors << QSslError(QSslError::CertificateExpired); break;        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:            errors << QSslError(QSslError::InvalidNotBeforeField); break;        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:            errors << QSslError(QSslError::InvalidNotAfterField); break;        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:            errors << QSslError(QSslError::SelfSignedCertificate); break;        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:            errors << QSslError(QSslError::SelfSignedCertificateInChain); break;        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:            errors << QSslError(QSslError::UnableToGetLocalIssuerCertificate); break;        case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:            errors << QSslError(QSslError::UnableToVerifyFirstCertificate); break;        case X509_V_ERR_CERT_REVOKED:            errors << QSslError(QSslError::CertificateRevoked); break;        case X509_V_ERR_INVALID_CA:            errors << QSslError(QSslError::InvalidCaCertificate); break;        case X509_V_ERR_PATH_LENGTH_EXCEEDED:            errors << QSslError(QSslError::PathLengthExceeded); break;        case X509_V_ERR_INVALID_PURPOSE:            errors << QSslError(QSslError::InvalidPurpose); break;        case X509_V_ERR_CERT_UNTRUSTED:            errors << QSslError(QSslError::CertificateUntrusted); break;        case X509_V_ERR_CERT_REJECTED:            errors << QSslError(QSslError::CertificateRejected); break;        default:            errors << QSslError(QSslError::UnspecifiedError); break;        }    }    if (!errors.isEmpty()) {        sslErrors = errors;        emit q->sslErrors(errors);        if (!ignoreSslErrors) {            q->setErrorString(sslErrors.first().errorString());            plainSocket->disconnectFromHost();            return false;        }    } else {        sslErrors.clear();    }        connectionEncrypted = true;    emit q->encrypted();    return true;}void QSslSocketBackendPrivate::disconnectFromHost(){    if (ssl) {        q_SSL_shutdown(ssl);        transmit();    }    plainSocket->disconnectFromHost();}void QSslSocketBackendPrivate::disconnected(){    if (ssl) {        q_SSL_free(ssl);        ssl = 0;    }    if (ctx) {        q_SSL_CTX_free(ctx);        ctx = 0;    }}QSslCipher QSslSocketBackendPrivate::sessionCipher() const{    if (!ssl || !ctx)        return QSslCipher();    SSL_CIPHER *sessionCipher = q_SSL_get_current_cipher(ssl);    return sessionCipher ? QSslCipher_from_SSL_CIPHER(sessionCipher) : QSslCipher();}QList<QSslCertificate> QSslSocketBackendPrivate::STACKOFX509_to_QSslCertificates(STACK_OF(X509) *x509){    ensureInitialized();    QList<QSslCertificate> certificates;    for (int i = 0; i < q_sk_X509_num(x509); ++i) {        if (X509 *entry = q_sk_X509_value(x509, i))            certificates << QSslCertificatePrivate::QSslCertificate_from_X509(entry);    }    return certificates;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?