// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include #include #include #include #include #include #include #include // Client and/or server presents a certificate signed by a system-trusted CA // but the other side presents a certificate signed by a different CA. constexpr bool TestServerPresentsIncorrectCa = false; constexpr bool TestClientPresentsIncorrectCa = true; // Decides whether or not to put the root CA into the global ssl configuration // or into the socket's specific ssl configuration. constexpr bool UseGlobalConfiguration = true; class ServerThread : public QThread { Q_OBJECT public: void run() override { QSslServer server; QSslConfiguration config = server.sslConfiguration(); if (!UseGlobalConfiguration) { QList certs = QSslCertificate::fromPath(QStringLiteral(":/rootCA.pem")); config.setCaCertificates(certs); } config.setLocalCertificate(QSslCertificate::fromPath(QStringLiteral(":/127.0.0.1.pem")) .first()); QFile keyFile(QStringLiteral(":/127.0.0.1-key.pem")); if (!keyFile.open(QIODevice::ReadOnly)) qFatal("Failed to open key file"); config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); config.setPeerVerifyMode(QSslSocket::VerifyPeer); server.setSslConfiguration(config); connect(&server, &QSslServer::pendingConnectionAvailable, [&server]() { QSslSocket *socket = static_cast(server.nextPendingConnection()); qDebug() << "[s] newConnection" << socket->peerAddress() << socket->peerPort(); socket->disconnectFromHost(); qApp->quit(); }); connect(&server, &QSslServer::startedEncryptionHandshake, [](QSslSocket *socket) { qDebug() << "[s] new handshake" << socket->peerAddress() << socket->peerPort(); }); connect(&server, &QSslServer::errorOccurred, [](QSslSocket *socket, QAbstractSocket::SocketError error) { qDebug() << "[s] errorOccurred" << socket->peerAddress() << socket->peerPort() << error << socket->errorString(); }); connect(&server, &QSslServer::peerVerifyError, [](QSslSocket *socket, const QSslError &error) { qDebug() << "[s] peerVerifyError" << socket->peerAddress() << socket->peerPort() << error; }); server.listen(QHostAddress::LocalHost, 24242); exec(); server.close(); } }; int main(int argc, char **argv) { QCoreApplication app(argc, argv); using namespace Qt::StringLiterals; if (!QFileInfo(u":/rootCA.pem"_s).exists()) qFatal("rootCA.pem not found. Did you run generate.sh in the certs directory?"); if (UseGlobalConfiguration) { QSslConfiguration config = QSslConfiguration::defaultConfiguration(); config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); QSslConfiguration::setDefaultConfiguration(config); } ServerThread serverThread; serverThread.start(); QSslSocket socket; QSslConfiguration config = socket.sslConfiguration(); QString certificatePath; QString keyFileName; if constexpr (TestClientPresentsIncorrectCa) { // true: Present cert signed with incorrect CA: should fail certificatePath = u":/127.0.0.1-client.pem"_s; keyFileName = u":/127.0.0.1-client-key.pem"_s; } else { // false: Use correct CA: should succeed certificatePath = u":/accepted-client.pem"_s; keyFileName = u":/accepted-client-key.pem"_s; } config.setLocalCertificate(QSslCertificate::fromPath(certificatePath).first()); if (!UseGlobalConfiguration && TestServerPresentsIncorrectCa) { // Verify server using incorrect CA: should fail config.setCaCertificates(QSslCertificate::fromPath(u":/rootCA.pem"_s)); } else if (UseGlobalConfiguration && !TestServerPresentsIncorrectCa) { // Verify server using correct CA, we need to explicitly set the // system CAs when the global config is overridden. config.setCaCertificates(QSslConfiguration::systemCaCertificates()); } QFile keyFile(keyFileName); if (!keyFile.open(QIODevice::ReadOnly)) qFatal("Failed to open key file"); config.setPrivateKey(QSslKey(&keyFile, QSsl::Rsa)); socket.setSslConfiguration(config); QObject::connect(&socket, &QSslSocket::encrypted, []() { qDebug() << "[c] encrypted"; }); QObject::connect(&socket, &QSslSocket::errorOccurred, [&socket](QAbstractSocket::SocketError error) { qDebug() << "[c] errorOccurred" << error << socket.errorString(); qApp->quit(); }); QObject::connect(&socket, &QSslSocket::sslErrors, [](const QList &errors) { qDebug() << "[c] sslErrors" << errors; }); QObject::connect(&socket, &QSslSocket::connected, []() { qDebug() << "[c] connected"; }); socket.connectToHostEncrypted(QStringLiteral("127.0.0.1"), 24242); const int res = app.exec(); serverThread.quit(); serverThread.wait(); return res; } #include "tst_manual_ssl_client_auth.moc"