void WebsocketServer::initialisieren(const QString &name, const QString &ipAdresse, const int &anschluss, const QStringList &sslAlgorithmen, const QStringList &ssl_EK, const QString &ssl_DH, const QString &zertifikatSchluessel, const QString &zertifikat, const QString &zertifkatKette, const bool &ssl_aktiv) { QWebSocketServer::SslMode SSL_Modus; if (ssl_aktiv) { SSL_Modus=QWebSocketServer::SecureMode; K_IPAdresse=QHostAddress(ipAdresse); } else { SSL_Modus=QWebSocketServer::NonSecureMode; K_IPAdresse=QHostAddress(QHostAddress::LocalHost); } K_Server=new QWebSocketServer(name,SSL_Modus,this); connect(K_Server,&QWebSocketServer::sslErrors,this, &WebsocketServer::SSL_Fehler); connect(K_Server,&QWebSocketServer::serverError,this,&WebsocketServer::SSL_Serverfehler); connect(K_Server,&QWebSocketServer::newConnection,this,&WebsocketServer::NeuerKlient); connect(K_Server,&QWebSocketServer::acceptError,this,&WebsocketServer::Verbindungsfehler); K_Anschluss=anschluss; QSslConfiguration SSL; QList<QSslCipher> Algorithmen; QVector<QSslEllipticCurve> EK; SSL.setProtocol(QSsl::TlsV1_2OrLater); SSL.setPeerVerifyMode(QSslSocket::VerifyNone); QSslCipher Algorithmus; QSslEllipticCurve Kurve; if (ssl_aktiv) { //BUG Das mit der Reihenfolge geht nicht for (auto Eintrag : sslAlgorithmen) { Algorithmus=QSslCipher(Eintrag); if (Algorithmus.isNull()) qCWarning(qalarm_serverWebsocketServer)<< tr("Algorithmus %1 wird nicht unterstützt.").arg(Eintrag); else Algorithmen.append(Algorithmus); } SSL.setCiphers(Algorithmen); //BUG Es werden nie Kurven angeboten for (auto Eintrag : ssl_EK) { Kurve=QSslEllipticCurve::fromShortName(Eintrag); if (!Kurve.isValid()) qCWarning(qalarm_serverWebsocketServer)<< tr("Kurve %1 wird nicht unterstützt.").arg(Eintrag); else EK.append(Kurve); } SSL.setEllipticCurves(EK); if(!ssl_DH.isEmpty()) { #if (QT_VERSION >= QT_VERSION_CHECK(5,8,0)) SSL.setDiffieHellmanParameters(QSslDiffieHellmanParameters::fromEncoded(DateiLaden(ssl_DH,tr("Die DH Parameter %1 konnten nicht geladen werden.")))); #else qCWarning(qalarm_serverWebsocketServer)<<tr("Qt kann die DH Parameter erst ab Version 5.8.0 setzen"); #endif } QList<QSslCertificate> Zertifikate; Zertifikate=QSslCertificate::fromDevice(DateiLaden(zertifikat,tr("Zertifikat %1 konnte nicht geladen werden.").arg(zertifikat))); Zertifikate.append(QSslCertificate::fromDevice(DateiLaden(zertifkatKette,tr("Die Zertifikatskette %1 konnte nicht geladen werden.").arg(zertifkatKette)))); SSL.setLocalCertificateChain(Zertifikate); SSL.setPrivateKey(QSslKey(DateiLaden(zertifikatSchluessel,tr("Der Schlüssel %1 für das Zertifikat konnte nicht geladen werden.").arg(zertifikatSchluessel)),QSsl::Rsa)); if(SSL.privateKey().isNull() || SSL.localCertificate().isNull() || SSL.localCertificateChain().isEmpty()) return; qCDebug(qalarm_serverWebsocketServer)<<tr("Setze SSL Konfiguration"); qCDebug(qalarm_serverWebsocketServer)<<tr("Privater Schlüssel: ")<<SSL.privateKey(); qCDebug(qalarm_serverWebsocketServer)<<tr("Zertifikate: ")<<SSL.localCertificateChain(); #if (QT_VERSION >= QT_VERSION_CHECK(5,8,0)) qCDebug(qalarm_serverWebsocketServer)<<tr("DH Parameter: ")<<SSL.diffieHellmanParameters(); #endif qCDebug(qalarm_serverWebsocketServer)<<tr("Zerttest: ")<<SSL.peerVerifyMode(); qCDebug(qalarm_serverWebsocketServer)<<tr("Elliptische Kurven: ")<<SSL.ellipticCurves(); qCDebug(qalarm_serverWebsocketServer)<<tr("Algorithmen: ")<<SSL.ciphers(); K_Server->setSslConfiguration(SSL); } if(!K_Initfehler) Q_EMIT Initialisiert(); }
// static void QSslContext::initSslContext(QSslContext *sslContext, QSslSocket::SslMode mode, const QSslConfiguration &configuration, bool allowRootCertOnDemandLoading) { sslContext->sslConfiguration = configuration; sslContext->errorCode = QSslError::NoError; bool client = (mode == QSslSocket::SslClientMode); bool reinitialized = false; bool unsupportedProtocol = false; init_context: if (sslContext->sslConfiguration.protocol() == QSsl::SslV2) { // SSL 2 is no longer supported, but chosen deliberately -> error sslContext->ctx = nullptr; unsupportedProtocol = true; } else { // The ssl options will actually control the supported methods sslContext->ctx = q_SSL_CTX_new(client ? q_TLS_client_method() : q_TLS_server_method()); } if (!sslContext->ctx) { // After stopping Flash 10 the SSL library loses its ciphers. Try re-adding them // by re-initializing the library. if (!reinitialized) { reinitialized = true; if (q_OPENSSL_init_ssl(0, nullptr) == 1) goto init_context; } sslContext->errorStr = QSslSocket::tr("Error creating SSL context (%1)").arg( unsupportedProtocol ? QSslSocket::tr("unsupported protocol") : QSslSocketBackendPrivate::getErrorsFromOpenSsl() ); sslContext->errorCode = QSslError::UnspecifiedError; return; } // Enable bug workarounds. long options = QSslSocketBackendPrivate::setupOpenSslOptions(configuration.protocol(), configuration.d->sslOptions); q_SSL_CTX_set_options(sslContext->ctx, options); // Tell OpenSSL to release memory early // http://www.openssl.org/docs/ssl/SSL_CTX_set_mode.html q_SSL_CTX_set_mode(sslContext->ctx, SSL_MODE_RELEASE_BUFFERS); // Initialize ciphers QByteArray cipherString; bool first = true; QList<QSslCipher> ciphers = sslContext->sslConfiguration.ciphers(); if (ciphers.isEmpty()) ciphers = QSslSocketPrivate::defaultCiphers(); for (const QSslCipher &cipher : qAsConst(ciphers)) { if (first) first = false; else cipherString.append(':'); cipherString.append(cipher.name().toLatin1()); } if (!q_SSL_CTX_set_cipher_list(sslContext->ctx, cipherString.data())) { sslContext->errorStr = QSslSocket::tr("Invalid or empty cipher list (%1)").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; return; } const QDateTime now = QDateTime::currentDateTimeUtc(); // Add all our CAs to this store. const auto caCertificates = sslContext->sslConfiguration.caCertificates(); for (const QSslCertificate &caCertificate : caCertificates) { // From https://www.openssl.org/docs/ssl/SSL_CTX_load_verify_locations.html: // // If several CA certificates matching the name, key identifier, and // serial number condition are available, only the first one will be // examined. This may lead to unexpected results if the same CA // certificate is available with different expiration dates. If a // ``certificate expired'' verification error occurs, no other // certificate will be searched. Make sure to not have expired // certificates mixed with valid ones. // // See also: QSslSocketBackendPrivate::verify() if (caCertificate.expiryDate() >= now) { q_X509_STORE_add_cert(q_SSL_CTX_get_cert_store(sslContext->ctx), (X509 *)caCertificate.handle()); } } if (QSslSocketPrivate::s_loadRootCertsOnDemand && allowRootCertOnDemandLoading) { // tell OpenSSL the directories where to look up the root certs on demand const QList<QByteArray> unixDirs = QSslSocketPrivate::unixRootCertDirectories(); for (const QByteArray &unixDir : unixDirs) q_SSL_CTX_load_verify_locations(sslContext->ctx, nullptr, unixDir.constData()); } if (!sslContext->sslConfiguration.localCertificate().isNull()) { // Require a private key as well. if (sslContext->sslConfiguration.privateKey().isNull()) { sslContext->errorStr = QSslSocket::tr("Cannot provide a certificate with no key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; return; } // Load certificate if (!q_SSL_CTX_use_certificate(sslContext->ctx, (X509 *)sslContext->sslConfiguration.localCertificate().handle())) { sslContext->errorStr = QSslSocket::tr("Error loading local certificate, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; return; } if (configuration.d->privateKey.algorithm() == QSsl::Opaque) { sslContext->pkey = reinterpret_cast<EVP_PKEY *>(configuration.d->privateKey.handle()); } else { // Load private key sslContext->pkey = q_EVP_PKEY_new(); // before we were using EVP_PKEY_assign_R* functions and did not use EVP_PKEY_free. // this lead to a memory leak. Now we use the *_set1_* functions which do not // take ownership of the RSA/DSA key instance because the QSslKey already has ownership. if (configuration.d->privateKey.algorithm() == QSsl::Rsa) q_EVP_PKEY_set1_RSA(sslContext->pkey, reinterpret_cast<RSA *>(configuration.d->privateKey.handle())); else if (configuration.d->privateKey.algorithm() == QSsl::Dsa) q_EVP_PKEY_set1_DSA(sslContext->pkey, reinterpret_cast<DSA *>(configuration.d->privateKey.handle())); #ifndef OPENSSL_NO_EC else if (configuration.d->privateKey.algorithm() == QSsl::Ec) q_EVP_PKEY_set1_EC_KEY(sslContext->pkey, reinterpret_cast<EC_KEY *>(configuration.d->privateKey.handle())); #endif } if (!q_SSL_CTX_use_PrivateKey(sslContext->ctx, sslContext->pkey)) { sslContext->errorStr = QSslSocket::tr("Error loading private key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; return; } if (configuration.d->privateKey.algorithm() == QSsl::Opaque) sslContext->pkey = nullptr; // Don't free the private key, it belongs to QSslKey // Check if the certificate matches the private key. if (!q_SSL_CTX_check_private_key(sslContext->ctx)) { sslContext->errorStr = QSslSocket::tr("Private key does not certify public key, %1").arg(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; return; } // If we have any intermediate certificates then we need to add them to our chain bool first = true; for (const QSslCertificate &cert : qAsConst(configuration.d->localCertificateChain)) { if (first) { first = false; continue; } q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_EXTRA_CHAIN_CERT, 0, q_X509_dup(reinterpret_cast<X509 *>(cert.handle()))); } } // Initialize peer verification. if (sslContext->sslConfiguration.peerVerifyMode() == QSslSocket::VerifyNone) { q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_NONE, nullptr); } else { q_SSL_CTX_set_verify(sslContext->ctx, SSL_VERIFY_PEER, q_X509Callback); } // Set verification depth. if (sslContext->sslConfiguration.peerVerifyDepth() != 0) q_SSL_CTX_set_verify_depth(sslContext->ctx, sslContext->sslConfiguration.peerVerifyDepth()); // set persisted session if the user set it if (!configuration.sessionTicket().isEmpty()) sslContext->setSessionASN1(configuration.sessionTicket()); // Set temp DH params QSslDiffieHellmanParameters dhparams = configuration.diffieHellmanParameters(); if (!dhparams.isValid()) { sslContext->errorStr = QSslSocket::tr("Diffie-Hellman parameters are not valid"); sslContext->errorCode = QSslError::UnspecifiedError; return; } if (!dhparams.isEmpty()) { const QByteArray ¶ms = dhparams.d->derData; const char *ptr = params.constData(); DH *dh = q_d2i_DHparams(NULL, reinterpret_cast<const unsigned char **>(&ptr), params.length()); if (dh == NULL) qFatal("q_d2i_DHparams failed to convert QSslDiffieHellmanParameters to DER form"); q_SSL_CTX_set_tmp_dh(sslContext->ctx, dh); q_DH_free(dh); } #ifndef OPENSSL_NO_PSK if (!client) q_SSL_CTX_use_psk_identity_hint(sslContext->ctx, sslContext->sslConfiguration.preSharedKeyIdentityHint().constData()); #endif // !OPENSSL_NO_PSK const QVector<QSslEllipticCurve> qcurves = sslContext->sslConfiguration.ellipticCurves(); if (!qcurves.isEmpty()) { #ifdef OPENSSL_NO_EC sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocket::tr("OpenSSL version with disabled elliptic curves")); sslContext->errorCode = QSslError::UnspecifiedError; #else // Set the curves to be used. std::vector<int> curves; curves.reserve(qcurves.size()); for (const auto &sslCurve : qcurves) curves.push_back(sslCurve.id); if (!q_SSL_CTX_ctrl(sslContext->ctx, SSL_CTRL_SET_CURVES, long(curves.size()), &curves[0])) { sslContext->errorStr = msgErrorSettingEllipticCurves(QSslSocketBackendPrivate::getErrorsFromOpenSsl()); sslContext->errorCode = QSslError::UnspecifiedError; } #endif } }