#include #include #include #include #include // This is the public certificate chain of qt.io as of 2020-11-18: static const char* qtIoCertChain = R"(-----BEGIN CERTIFICATE----- MIIEjjCCBDOgAwIBAgIQCQsKtxCf9ik3vIVQ+PMa5TAKBggqhkjOPQQDAjBKMQsw CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjAwODE2MDAwMDAwWhcNMjEwODE2 MTIwMDAwWjBhMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNh biBGcmFuY2lzY28xGTAXBgNVBAoTEENsb3VkZmxhcmUsIEluYy4xEjAQBgNVBAMT CXd3dy5xdC5pbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABP/r0xH22wdU8fLk RsXhxRj5fmUNUo7rxnUl3lyqYYp53cLvn3agQifXkegpE8Xv4pGmuyWZj85FtoeZ UZh8iyCjggLiMIIC3jAfBgNVHSMEGDAWgBSlzjfq67B1DpRniLRF+tkkEIeWHzAd BgNVHQ4EFgQU7qPYGi9VtC4/6MS+54LNEAXApBgwFAYDVR0RBA0wC4IJd3d3LnF0 LmlvMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwewYDVR0fBHQwcjA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Ns b3VkZmxhcmVJbmNFQ0NDQS0zLmNybDA3oDWgM4YxaHR0cDovL2NybDQuZGlnaWNl cnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNybDBMBgNVHSAERTBDMDcGCWCG SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v Q1BTMAgGBmeBDAECAjB2BggrBgEFBQcBAQRqMGgwJAYIKwYBBQUHMAGGGGh0dHA6 Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBABggrBgEFBQcwAoY0aHR0cDovL2NhY2VydHMu ZGlnaWNlcnQuY29tL0Nsb3VkZmxhcmVJbmNFQ0NDQS0zLmNydDAMBgNVHRMBAf8E AjAAMIIBBAYKKwYBBAHWeQIEAgSB9QSB8gDwAHYA9lyUL9F3MCIUVBgIMJRWjuNN Exkzv98MLyALzE7xZOMAAAFz90PlSQAABAMARzBFAiAhrrtxdmuxpCy8HAJJ5Qkg WNvlo8nZqfe6pqGUcz0dmwIhAOMqDtd5ZhcfRk96GAJxPm8bH4hDnmqDP/zJG2Mq nFpMAHYAXNxDkv7mq0VEsV6a1FbmEDf71fpH3KFzlLJe5vbHDsoAAAFz90PlewAA BAMARzBFAiB/EkdY10LDdaRcf6eSc/QxucxU+2PI+3pWjh/21A8ZUAIhAK2Qz9Kw onlRNyHpV3E6qyVydkXihj3c3q5UclpURYcmMAoGCCqGSM49BAMCA0kAMEYCIQDz K/lzLb2Rbeg1HErRLLm2HkJUmfOGU2+tbROSTGK8ugIhAKA+MKqaZ8VjPxQ+Ho4v fuwccvZfkU/fg8tAHTOzX23v -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDzTCCArWgAwIBAgIQCjeHZF5ftIwiTv0b7RQMPDANBgkqhkiG9w0BAQsFADBa MQswCQYDVQQGEwJJRTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJl clRydXN0MSIwIAYDVQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTIw MDEyNzEyNDgwOFoXDTI0MTIzMTIzNTk1OVowSjELMAkGA1UEBhMCVVMxGTAXBgNV BAoTEENsb3VkZmxhcmUsIEluYy4xIDAeBgNVBAMTF0Nsb3VkZmxhcmUgSW5jIEVD QyBDQS0zMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEua1NZpkUC0bsH4HRKlAe nQMVLzQSfS2WuIg4m4Vfj7+7Te9hRsTJc9QkT+DuHM5ss1FxL2ruTAUJd9NyYqSb 16OCAWgwggFkMB0GA1UdDgQWBBSlzjfq67B1DpRniLRF+tkkEIeWHzAfBgNVHSME GDAWgBTlnVkwgkdYzKz6CFQ2hns6tQRN8DAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0l BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8CAQAwNAYI KwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j b20wOgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL09t bmlyb290MjAyNS5jcmwwbQYDVR0gBGYwZDA3BglghkgBhv1sAQEwKjAoBggrBgEF BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzALBglghkgBhv1sAQIw CAYGZ4EMAQIBMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQELBQADggEB AAUkHd0bsCrrmNaF4zlNXmtXnYJX/OvoMaJXkGUFvhZEOFp3ArnPEELG4ZKk40Un +ABHLGioVplTVI+tnkDB0A+21w0LOEhsUCxJkAZbZB2LzEgwLt4I4ptJIsCSDBFe lpKU1fwg3FZs5ZKTv3ocwDfjhUkV+ivhdDkYD7fa86JXWGBPzI6UAPxGezQxPk1H goE6y/SJXQ7vTQ1unBuCJN0yJV0ReFEQPaA1IwQvZW+cwdFD19Ae8zFnWSfda9J1 CZMRJCQUzym+5iPDuI9yP+kHyCREU3qzuWFloUwOxkgAyXVjBYdwRVKD05WdRerw 6DEdfgkfCv4+3ao8XnTSrLE= -----END CERTIFICATE-----)"; // This is a purposely random self signed certificate (which of course can't be used to certify the qt.io certificate). // It is created using the command "openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650": static const char* qtSelfSignedRoot = R"(-----BEGIN CERTIFICATE----- MIIFpTCCA42gAwIBAgIJAMJqcJ20MhuHMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNV BAYTAkRLMQswCQYDVQQIDAJESzETMBEGA1UEBwwKQ29wZW5oYWdlbjEZMBcGA1UE CgwQQ2VydGlmaWNhdGUgVGVzdDEdMBsGA1UEAwwUY2VydGlmaWNhdGUtdGVzdC5j b20wHhcNMjAxMTE4MTc0MTI1WhcNMzAxMTE2MTc0MTI1WjBpMQswCQYDVQQGEwJE SzELMAkGA1UECAwCREsxEzARBgNVBAcMCkNvcGVuaGFnZW4xGTAXBgNVBAoMEENl cnRpZmljYXRlIFRlc3QxHTAbBgNVBAMMFGNlcnRpZmljYXRlLXRlc3QuY29tMIIC IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAy94AOweO1udrRlSyhDQIDxID VxvJ1fkUWXRsZY5wFXb7ChR0ytOUlFfcHGW2ZkISoFNARIql4Gg4JBgbR3V0E6Zw NfJYqrK/7p5EbaQTaD0Y6TojBvtfbTndRLwOdu/st4tbTMefAvbnTZD2Uz+2swrG N7iFU0+q8eacr5Xc/2igpNcC+ChgN48fRGCAUTR8dT8V3hU6m6X2dqN5j4lLznKP NQzPIlciVuWb/PcEnr9QUQcd32qLG+tMH6lygs9A0RvlDYsOsffhSdK8WEfItciy qH9zESWRaz7FxORvMks7i2kqn6gnvXEapaeFo17D2lVhpf3rGFJ5GplsPJADcIKX bTVrDkEG9HvAMPgPUwBMFloJ/UZQLqf8AD1SZ0OhyacuBnk7F/PBxQbXhOGhF196 zwC0PZsYEKnFXbBAUhMfBc3DrvfsuDQxpqZHDvhcj0Kdb5Uem4J9oJEjUSKLLBWn /x2Kpyo3lSFG6ITuTH/hYjSNY3wAU0xJexyYr02FCzrNe0hdfI1l0J0SozjQCV61 Cy8SRmqAMSRmCHNsI5cjsjAI8TnE7ceNAesPxr3Ewne2mZCalmFLvFYwojkPH9XH fyZlSakHJXqsPSXv5LtYeqiAoXwrKWlbtjjartHfzN6SdQKSYUdSRYspQGBDV9Jt 5s1onyEA4ZVXb/bmOY0CAwEAAaNQME4wHQYDVR0OBBYEFMRNFuc1cMvJVJo1DFxU iE69H/eEMB8GA1UdIwQYMBaAFMRNFuc1cMvJVJo1DFxUiE69H/eEMAwGA1UdEwQF MAMBAf8wDQYJKoZIhvcNAQEFBQADggIBAH6t55VosJTZlPWl0PUgqoH72w90sPCx O4ycWY6G+1AhgMoUEooxzQUIQF8Pr1bxYackZDFhD+aSNurCaYlya2nImFSPVewY y6QPWGFMi7mUvOtg0nlsCBmrvdbRcnKx0WzC+CXcqJyC2cFa6WsJV2qyHLV0Sm5W IeW5ps0BBHiFhA7uLNLLSQE1RuwhIZv8R9r9SWx8JXmWhi5u4CHVY31pc8Xv9+TZ 3wgufHiVwptCbaBF28YHneO9HH1NSdT9LbY4ZRKIHpiwUGTBGwKieKzmJTmpKikl lx9edyoK16SoZk2Up2WU/FQN9x0/ZHOP0tt4PDL7VwlQSZ+hnjTfHpjF3Gx+Xmn5 UwLj9MHEutzeQjRGLFDgeckUetH/AdQ67/uqI/mvqhuV1PfEgllooCmAlQ0JSnz7 PCYI90bZpS4n4KyH4ThAN/HfhiqubSO2RqJizDp2Jy7T9U01El9mvj4wsdYeiUNU yf/eicYbd+g+lNa+l0DNXI36p3uDLYAgGPejQCD0zyQjud5z+YHsv7vB6lWuLg2Y 2opb4j3k0zzgp8RN3sp5Fv1OgwQd3Mm68D8+c0RP4JBe/z4OUWLWGCPTV/aL8+T/ c6kOQOkfF05r9de+7w3Yb/WC7cjOi4UslWYAxeLtwHeB6aN+qi3DHS2NTVWhGSbS a0PCws5udT72 -----END CERTIFICATE-----)"; // List errors method: static void listSslErrors(const QList &errors) { bool gotCorrectError = false; for (auto& error : errors) { if (error.error() == QSslError::UnableToGetLocalIssuerCertificate) { gotCorrectError = true; qDebug() << "Got expected SSL error: " << error.errorString(); } else { qDebug() << "SSL error: " << error.errorString(); } } if (!gotCorrectError) { qDebug() << "Didn't get expected error (i.e." << QSslError(QSslError::UnableToGetLocalIssuerCertificate).errorString() << ")"; } } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // List SSL library in use: qDebug() << "SSL in use at build time: " << QSslSocket::sslLibraryBuildVersionString(); qDebug() << "SSL in use at run time: " << QSslSocket::sslLibraryVersionString(); QList rootCert = QSslCertificate::fromData(qtSelfSignedRoot); // Load root certificate /* * Here is the old and new way to set up a local list of trusted root certificates: * "if 0" enables the new (supported) way using QSslConfiguration::setCaCertificates(). * "if 1" enables the old (deprecated) way using QSslSocket::setDefaultCaCertificates(). */ #if 0 // Set up CA certificates using deprecated method: QSslSocket::setDefaultCaCertificates(rootCert); #else // Set up CA certificates using QSslConfiguration: auto conf = QSslConfiguration::defaultConfiguration(); conf.setCaCertificates(rootCert); QSslConfiguration::setDefaultConfiguration(conf); #endif // First try QSslSocket::verify which should fail: qDebug() << "Validating qt.io certificate:"; QList qtCertChain = QSslCertificate::fromData(qtIoCertChain); // Load certificates from memory QList errors = QSslCertificate::verify(qtCertChain); // Do the verification listSslErrors(errors); // Check issued errors // Then try actually connecting (which should also fail): qDebug() << "Connecting to qt.io:"; QSslSocket sock; QObject::connect(&sock, QOverload &>::of(&QSslSocket::sslErrors), listSslErrors); // List and check errors sock.connectToHostEncrypted("www.qt.io", 443); // Try connecting if (!sock.waitForEncrypted()) { qDebug() << "Could not connect encrypted (as expected)"; } else { qDebug() << "Connection went well (which it shouldn't have)"; } return 0; }