📄 qtsslsocket.cpp
字号:
if (!lib->SSL_CTX_use_certificate_file(d->ctx, QFile::encodeName(d->cert).constData(), SSL_FILETYPE_PEM)) { setErrorString(tr("Error loading certificate, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } // Load private key if (!lib->SSL_CTX_use_PrivateKey_file(d->ctx, QFile::encodeName(d->key).constData(), SSL_FILETYPE_PEM)) { setErrorString(tr("Error loading private key, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } // Check if the certificate matches the private key. if (!lib->SSL_CTX_check_private_key(d->ctx)) { setErrorString(tr("Private key do not certificate public key, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } } if (!d->cafile.isEmpty() || !d->cadir.isEmpty()) { // Load trusted certificate authority (CA) certificates. if (!lib->SSL_CTX_load_verify_locations(d->ctx, d->cafile.isEmpty() ? 0 : QFile::encodeName(d->cafile).constData(), d->cadir.isEmpty() ? 0 : QFile::encodeName(d->cadir).constData())) { setErrorString(tr("Failed to load the list of trusted CAs").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } // Prior to 0.9.6, OpenSSL was unable to determine whether or // not a certificate came from a CA or not. We need to set the // verify depth to 1 in those cases, so that only root level // CAs are accepted for signing certificates.#if OPENSSL_VERSION_NUMBER < 0x00906000L lib->SSL_CTX_set_verify_depth(d->ctx, 1);#endif } // Create and initialize SSL session if (!(d->ssl = lib->SSL_new(d->ctx))) { setErrorString(tr("Error creating SSL session, %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } lib->SSL_clear(d->ssl); // Have the SSL library read from a memory location. We will store // encrypted data in the write buffer, and read decrypted data // from the read buffer. d->rbio = lib->BIO_new(lib->BIO_s_mem()); d->wbio = lib->BIO_new(lib->BIO_s_mem()); if (!d->rbio || !d->wbio) { setErrorString(tr("Error creating SSL session")); emit error(UnknownSocketError); return false; } lib->SSL_set_bio(d->ssl, d->rbio, d->wbio); if (d->mode == Server) lib->SSL_set_accept_state(d->ssl); else lib->SSL_set_connect_state(d->ssl);#if QT_VERSION >= 0x040100 setPeerAddress(d->socket->peerAddress()); setPeerPort(d->socket->peerPort()); setPeerName(d->socket->peerName()); setLocalAddress(d->socket->localAddress()); setLocalPort(d->socket->localPort());#endif // It is required that there is no data in the any output buffer // when the SSL library takes over communication. Subclasses with // buffers should reimplement flush. d->socket->flush(); d->initialized = true; return true;}/*! \internal*/void QtSslSocket::handleSocketError(SocketError socketError){ setErrorString(d->socket->errorString()); emit error(socketError);}/*! \internal*/void QtSslSocket::readFromSocket(){ QByteArray block = d->socket->readAll(); if (lib->BIO_write(d->rbio, block.data(), block.size()) != block.size()) { setErrorString(tr("Failed to write protocol data to BIO")); emit error(UnknownSocketError); return; } if (!d->connectionSecured) { if (d->mode == Client && sslConnect()) { emit connected(); } else if (d->mode == Server && sslAccept()) { emit connected(); } writeToSocket(); } // The connected() and accepted() signals can be connected to // slots that close the socket. We don't want to read more data // from the SSL buffers if the socket is closing. if (d->socket->state() == ClosingState || d->socket->state() == UnconnectedState) {#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::readFromSocket(), socket is closing";#endif return; } int ret = 0; do { char buffer[SslReadBlockSize]; ret = lib->SSL_read(d->ssl, buffer, sizeof(buffer)); if (ret <= 0) { if (ret < 0 && lib->SSL_get_error(d->ssl, ret) == SSL_ERROR_WANT_READ) { // If a renegotiation is taking place, we will not be able to // read data. Rather we must submit whatever is in our // outbound queue (placed by SSL_read) to complete the // handshake. Note that this condition is also met when // SSL_read is called and there is no pending data. writeToSocket(); } else if (ret == 0) { // The read operation was not successful, probably because no // data was available or the remote host closed the // connection. if (lib->SSL_get_error(d->ssl, 0) == SSL_ERROR_ZERO_RETURN) {#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::readFromSocket(), failed to read";#endif d->socket->disconnectFromHost(); } else { setErrorString(tr("Failed to read from SSL, %1") .arg(SSL_ERRORSTR())); emit error(UnknownSocketError); } } else { setErrorString(tr("Failed to read from SSL, %1") .arg(SSL_ERRORSTR())); emit error(UnknownSocketError); } break; }#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::readFromSocket(), read" << ret << "bytes";#endif char *ptr = d->readBuffer.reserve(ret); memcpy(ptr, buffer, ret); emit readyRead(); d->readyReadEmitted = true; } while (ret > 0);}/*! \internal*/void QtSslSocket::writeToSocket(){ d->calledWriteToSocket = false; if (d->connectionSecured) { while (!d->writeBuffer.isEmpty()) { int ret = lib->SSL_write(d->ssl, d->writeBuffer.readPointer(), d->writeBuffer.nextDataBlockSize()); if (ret <= 0) { setErrorString(tr("SSL error: %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return; } d->writeBuffer.free(ret); } } int pending = (int)lib->BIO_ctrl(d->wbio,BIO_CTRL_PENDING,0,NULL); if (pending > 0) { QByteArray buffer; buffer.resize(pending); // With BIO_s_mem(), BIO_read can not fail. lib->BIO_read(d->wbio, buffer.data(), buffer.size()); d->socket->write(buffer);#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::writeToSocket(), wrote" << buffer.size() << "bytes";#endif }}/*! \internal*/void QtSslSocket::socketBytesWritten(qint64 bytes){ emit bytesWritten(bytes);}/*! \internal*/QString QtSslSocket::verifyErrorString(int err){ // Comments from man verify(1) switch (err) { case X509_V_OK: // the operation was successful. return tr("An unknown error occurred"); case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: // the passed certificate is self signed and the same // certificate cannot be found in the list of trusted // certificates. return tr("Self signed certificate"); case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: // the certificate chain could be built up using the // untrusted certificates but the root could not be found // locally. return tr("Self signed certificate in certificate chain"); case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: // the certificate signature could not be decrypted. This // means that the actual signature value could not be // determined rather than it not matching the expected // value, this is only meaningful for RSA keys. return tr("Unable to decrypt certificate's signature"); case X509_V_ERR_CERT_SIGNATURE_FAILURE: // the signature of the certificate is invalid. return tr("Certificate signature failure"); case X509_V_ERR_CERT_NOT_YET_VALID: // the certificate is not yet valid: the notBefore date is // after the current time. return tr("The certificate is not yet valid"); case X509_V_ERR_CERT_HAS_EXPIRED: // the certificate has expired: that is the notAfter date // is before the current time. return tr("The certificate has expired"); case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: // the certificate notBefore field contains an invalid // time. return tr("Format error in certificate's notBefore field"); case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: // the certificate notAfter field contains an invalid // time. return tr("Format error in certificate's notAfter field"); case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: // the issuer certificate of a locally looked up // certificate could not be found. This normally means // the list of trusted certificates is not complete. return tr("Unable to get local issuer certificate"); case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: // no signatures could be verified because the chain // contains only one certificate and it is not self // signed. return tr("Unable to verify the first certificate"); case X509_V_ERR_INVALID_CA: // a CA certificate is invalid. Either it is not a CA or // its extensions are not consistent with the supplied // purpose return tr("Invalid CA certificate"); case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: // the issuer certificate could not be found: this occurs // if the issuer certificate of an untrusted certificate // cannot be found. return tr("Unable to get issuer certificate"); case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: // the public key in the certificate SubjectPublicKeyInfo // could not be read. return tr("Unable to decode issuer public key"); case X509_V_ERR_PATH_LENGTH_EXCEEDED: // the basicConstraints pathlength parameter has been // exceeded. return tr("Path length constraint exceeded"); case X509_V_ERR_INVALID_PURPOSE: // the supplied certificate cannot be used for the // specified purpose. return tr("Unsupported certificate purpose"); case X509_V_ERR_CERT_UNTRUSTED: // the root CA is not marked as trusted for the specified // purpose. return tr("Certificate not trusted"); case X509_V_ERR_CERT_REJECTED: // the root CA is marked to reject the specified purpose. return tr("Certificate rejected"); case X509_V_ERR_SUBJECT_ISSUER_MISMATCH: // the current candidate issuer certificate was rejected // because its subject name did not match the issuer name // of the current certificate. return tr("Subject issuer mismatch"); case X509_V_ERR_AKID_SKID_MISMATCH: // the current candidate issuer certificate was rejected // because its subject key identifier was present and did // not match the authority key identifier current // certificate. return tr("Authority and subject key identifier mismatch"); case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH: // the current candidate issuer certificate was rejected // because its issuer name and serial number was present // and did not match the authority key identifier of the // current certificate. return tr("Authority and issuer serial number mismatch"); case X509_V_ERR_KEYUSAGE_NO_CERTSIGN: // the current candidate issuer certificate was rejected // because its keyUsage extension does not permit // certificate signing. return tr("Key usage does not include certificate signing"); case X509_V_ERR_OUT_OF_MEM: // an error occurred trying to allocate memory. This // should never happen. return tr("Out of memory"); default: return tr("Unknown error"); }}/*! \internal If \a accept is true, this function will attempt to negotiate a server side handshake with the remote client, otherwise it will negotiate a client side handshake with the remote server.*/bool QtSslSocket::sslAcceptOrConnect(bool accept){ if (!d->initialized && !initSsl()) return false; // SSL connect (handshake). Note that during the handshake, the // verify callback is called and it might emit warnings. int result = accept ? lib->SSL_accept(d->ssl) : lib->SSL_connect(d->ssl); if (result <= 0) { if (result < 0) { int err = lib->SSL_get_error(d->ssl, result); if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) { // The handshake is not yet complete. writeToSocket(); return false; } } setErrorString(tr("SSL error: %1").arg(SSL_ERRORSTR())); emit error(UnknownSocketError); return false; } // Parse certificate QStringList items = peerCertificate().split('/'); QString certHost; QDateTime notValidBefore; QDateTime notValidAfter; for (int i = 0; i < (int) items.count(); ++i) { QString s = items.at(i); if (s.startsWith("CN=")) certHost = s.mid(3); else if (s.startsWith("notValidBefore=")) notValidBefore = QDateTime::fromString(s.mid(15), Qt::ISODate); else if (s.startsWith("notValidAfter=")) notValidAfter = QDateTime::fromString(s.mid(14), Qt::ISODate); } // Check if the certificate was verified. Note that err is // X509_V_OK also if the peer had no certificate. int err = lib->SSL_get_verify_result(d->ssl); if (err != X509_V_OK) { VerifyResult res = VerifyOk; switch (err) { case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: res = SelfSigned; break; default: res = UnableToVerify; } emit connectionVerificationDone(res, certHost.toLower() != d->socket->peerName().toLower(), verifyErrorString(err)); } else { QString errorString = tr("The SSL certificate has been verified"); VerifyResult result = VerifyOk; if (notValidBefore > QDateTime::currentDateTime()) { result = NotYetValid; errorString = tr("The SSL certificate is not valid until %1").arg(notValidBefore.toString()); } else if (notValidAfter < QDateTime::currentDateTime()) { result = Expired; errorString = tr("The SSL certificate expired on %1").arg(notValidAfter.toString()); } if (certHost.toLower() != d->socket->peerName().toLower()) { errorString += tr(", %1 ").arg(result == VerifyOk ? "but" : "and"); errorString += tr("the host name \"%0\" doesn't match the host name in the certificate \"%1\"") .arg(d->socket->peerName()).arg(certHost); } emit connectionVerificationDone(result,certHost.toLower() != d->socket->peerName().toLower(), errorString); } if (d->socket->state() != ConnectedState) {#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::sslAcceptOrConnect(), socket not connected";#endif return false; }#ifdef QTSSLSOCKET_DEBUG qDebug() << "QtSslSocket::sslAcceptOrConnect(), connected!" << d->socket->bytesAvailable() << d->socket->bytesToWrite() << d->writeBuffer.size() << d->readBuffer.size();#endif setSocketState(ConnectedState); emit stateChanged(ConnectedState); d->connectionSecured = true; readFromSocket(); return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -