QHttpServer, api, https, openssl, LetsEncrypt, sslv3 alert handshake failure-alert number 40
-
Hi
There is hereunder simple api which works using http protocol but get error (sslv3 alert handshake failure-alert number 40) when using https protocol.
info: my app is running on Windows 11 (my own hosting).
What I have done in order to use https protocol for secure conection between client and server:
- Got public dynamic ip address from my isp provider
- Got dynamic dns from duckdns.org and domainname also
- Got LetsEncrypt certificate for my domainname
- I added Openssl 3.0.10 1 Aug 2023 (Library: OpenSSL 3.0.10 1 Aug 2023) using Qt maintenance tool(), and set path:
C:\Qt\Tools\OpenSSLv3\Win_x64\bin, added libs and include paths in the app .pro file as you can see in the hereunder
http_server.pro file - I did port forwarding on my router.
I am using Qt 6.4.3
//http_server.pro file
QT = core httpserver networkCONFIG += c++17 cmdline
You can make your code fail to compile if it uses deprecated APIs.
In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES +=
main.cppLIBS += -LC:/Qt/Tools/OpenSSLv3/Win_x64/lib/libssl.lib
LIBS += -LC:/Qt/Tools/OpenSSLv3/Win_x64/lib/libcrypto.libINCLUDEPATH += C:/Qt/Tools/OpenSSLv3/Win_x64/include/openssl
Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target//main.cpp file
#include <QCoreApplication>
#include <QtCore>
#include <QtHttpServer/QHttpServer>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QString>
#include <QList>#if QT_CONFIG(ssl)
include <QSslCertificate>
include <QSslKey>
include <QSslSocket>
include <QDebug>
#endif
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);QHttpServer httpServer; httpServer.route("/", []() { return "Hello world"; });
#if QT_CONFIG(ssl)
const auto sslCertificateChain = QSslCertificate::fromPath(QStringLiteral("C:/Users/piern/desktop/fullchain1.pem")); if (sslCertificateChain.empty()) { qWarning() << QCoreApplication::translate("QHttpServerExample", "Couldn't retrieve SSL fullchain certificate from file."); return -1; } QFile privateKeyFile(QStringLiteral("C:/Users/piern/desktop/privkey1.pem")); if (!privateKeyFile.open(QIODevice::ReadOnly)) { qWarning() << QCoreApplication::translate("QHttpServerExample", "Couldn't open file for reading: %1") .arg(privateKeyFile.errorString()); return -1; } httpServer.sslSetup(sslCertificateChain.front(), QSslKey(&privateKeyFile, QSsl::Rsa), QSsl::TlsV1_2OrLater); privateKeyFile.close(); const auto port = httpServer.listen(QHostAddress::Any, 443); if(!port){ qWarning() << QCoreApplication::translate("QHttpServerExample", "Server failed to listen on a port."); return 0; } qDebug() << QCoreApplication::translate("QHttpServerExample", "Running on http://www*******:%1/" "(Press CTRL+C to quit)").arg(port);
#endif
return a.exec();
As you can see the code on this site is not fully formatted in the proper way but it is easy to see what is about.What I did in order to try to fix the secure connection failure:
1.I checked if my cert is valid for my domainname - which is OK
1.I used openssl commands in order to get know what is a cause of the ssl connection failure like:a. openssl s_client -connect mydomainname.duckdns.org:443
CONNECTED(000001C0)
90330000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl\record\rec_layer_s3.c:1586:SSL alert number 40no peer certificate available
No client certificate CA names sent
SSL handshake has read 7 bytes and written 332 bytes
Verification: OKNew, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)b. I used wireshark to find the problem.
c. I used nmap to find the problem
I do not want to show all my result of search at once for it is too wide.What can cause the secure connection failure???
if you have some ideas how to solve it. Need more info please ask me for more detailes. -
@ChrisW67
The cert was ok. The problem was in configuration function
see hereunder:
was
httpServer.sslSetup(sslCertificateChain.front(), QSslKey(&privateKeyFile, QSsl::RSA ), QSsl::TlsV1_0OrLater);working config.
httpServer.sslSetup(sslCertificateChain.front(), QSslKey(&privateKeyFile, QSsl::Ec, ), QSsl::TlsV1_0OrLater);So I alter QSsl:RSA to QSsl::Ec -
this thanks to Let's Encrypt community forum. -
Hi and welcome to devnet,
Did you check that OpenSSL is properly loaded by your application ?
As for the code, you can use coding tags (three backticks before and after your code or through the </> button of the editor).
-
@SGaist
Yes I thing openssl is loaded ok:qDebug() << "Avaliable backends: " << QSslSocket::availableBackends() << Qt::endl; qDebug() << "Active backends: " << QSslSocket::activeBackend() << Qt::endl;
Active backends: "openssl"
Avaliable backends: QList("cert-only", "openssl" "schannel") -
@ChrisW67 said in QHttpServer, api, https, openssl, LetsEncrypt, sslv3 alert handshake failure-alert number 40:
Is your private key encrypted? You do not provide a passphrase.
Is sslCertificateChain.front() the certificate you think it is?
I used certbot to get LetsEncrypt certificate.
Certificate are located on...
C:\Certbot\live\mydomainname.duckdns.org, files(fullchain.pem, privkey.pem, chain.pem, cert.pem) file type .symlink...and located on:
C:\Certbot\archive\mydomainname.duckdns.org, files(fullchain1.pem, privkey1.pem, chain1.pem, cert1.pem) file type PEMI was not able to load fullchain.pem and privkey.pem or fullchain1.pem and privkey1.pem(archive dir location) so I checked permissions:
QFileInfo file("C:/Certbot/live/mydomainname.duckdns.org/fullchain.pem"); QFile f("C:/Certbot/live/mydomainname.duckdns.org/fullchain.pem"); qDebug() << "isSymLink(): " << file.QFileInfo::isSymLink() << Qt::endl; qDebug() << "symLinkTarget().isEmpty(): " << file.QFileInfo::symLinkTarget().isEmpty()<< Qt::endl; qDebug() << "file.permissions(): " << file.permissions() << Qt::endl; if(f.exists()) { qDebug() << "file exists." << Qt::endl; } if(!f.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Can not read file"; return -1; }
isSymLink(): true
symLinkTarget().isEmpty(): true
file.permissions(): QFlags(0x2|0x4|0x20|0x40|0x200|0x400|0x2000|0x4000)
file exists.
Can not read fileDespite permissions are ok I could not load fullchain.pem and fullchain1.pem to my const auto sslCertificateChain variable. I was only able to copy fullchain1.pem and privkey1.pem from archive dir to Desktop location and then load these files without any problem.
Comming back to your question:
The cert files are the correct ones.
Does sslCertificateChain pass QSslCertificate::verify()?
qDebug() << QSslCertificate::verify(sslCertificateChain, "mydomainname.duckdns.org")<< Qt::endl;
Verify cert: QList() - so there is no any QSslError
Is your private key encrypted? You do not provide a passphrase?.
I got this certificate quite long ago so I do not remember but foud this on letsEncrypt forum:
The private key generated by Certbot that goes alongside the certificate is also not password protected.
It is protected only by filesystem permissions and shouldn’t be shared. -
Is sslCertificateChain.front() the certificate you think it is?
The cert files are the correct ones.
Maybe. This is a list of QSslCertificates. Are you sure the first entry in the list is the certificate corresponding to your server and not one of the upstream CA certificates?
-
@ChrisW67 said in QHttpServer, api, https, openssl, LetsEncrypt, sslv3 alert handshake failure-alert number 40:
Maybe. This is a list of QSslCertificates. Are you sure the first entry in the list is the certificate corresponding to your server and not one of the upstream CA certificates?
I used :
openssl x509 -text -noout -in C:/users/piern/desktop/fullchain1.pemgot:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
04:63:e4:57:ca:35:e7:40:03:20:8d:3b:6f:c4:a0:01:40:d2
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Let's Encrypt, CN = R3
Validity
Not Before: Sep 3 12:54:13 2023 GMT
Not After : Dec 2 12:54:12 2023 GMT
Subject: CN = mydomainname.duckdns.org
Subject Public Key Info:
and so on...
I do not show all what was printedI have chain1.pem file in which I think there is the upstream CA
I used:
openssl x509 -text -noout -in C:/users/piern/desktop/chain1.pemI got:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
91:2b:08:4a:cf:0c:18:a7:53:f6:d6:2e:25:a7:5f:5a
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1
Validity
Not Before: Sep 4 00:00:00 2020 GMT
Not After : Sep 15 16:00:00 2025 GMT
Subject: C = US, O = Let's Encrypt, CN = R3
and so on...I do not show all what was printed
-
@ChrisW67
I execute hereunder command(in my LAN): openssl s_client -connect mydomainname.duckdns.org:443 and got response:CONNECTED(000001C0)
90330000:error:0A000410:SSL routines:ssl3_read_bytes:sslv3 alert handshake failure:ssl\record\rec_layer_s3.c:1586:SSL alert number 40
no peer certificate available
No client certificate CA names sent
SSL handshake has read 7 bytes and written 332 bytes
Verification: OK
New, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)When using firefox browser and execute https://mydomainname.duckdns.org (in my LAN) I discavered that my ZTE router cert was used instead LetsEncrypt one.
Looks like when connect from the same network router cert is used.
I execute hereunder command (outside my LAN): openssl s_client -connect mydomainname.duckdns.org:443 and got response:
CONNECTED(000001D0)
F0380000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:ssl\record\rec_layer_s3.c:304:no peer certificate available
No Client certificate CA names sent
SSL handshake has read 0 bytes and written 339 bytes
Verification: OKNew, (NONE), Cipher is (NONE)
Secure Renegotation IS NOT supported
Compression: NONE
No APLN negotiated
Early data was not sent
Verify return code: 0 (ok)When execute: openssl s_client -connect mydomainname.duckdns.org:443 -msg
I got:
CONNECTED(000001D0)TLS 1.0, RecordHeader [length 0005]
16 03 01 01 47
TLS 1.3, Handshake [length 0147], ClientHello
01 00 01 43 03 03 5d eb f5 7e c6 ea 5f 8a 8c d8
f2 09 4b cd 1f 07 ef 3f 3e 5f 57 16 f0 63 be d5
4e 07 b4 f6 90 55 20 96 40 81 01 87 2d 40 c1 d2
e2 e7 7a 73 36 84 e3 b5 3f 83 65 46 47 e0 1b f0
a2 f9 8c a1 d0 8b 0e 00 3e 13 02 13 03 13 01 c0
2c c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00
9e c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0
14 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00
1d 00 00 1a 62 6f 72 6f 77 6b 61 63 68 61 6c 75
70 79 2e 64 75 63 6b 64 6e 73 2e 6f 72 67 00 0b
00 04 03 00 01 02 00 0a 00 16 00 14 00 1d 00 17
00 1e 00 19 00 18 01 00 01 01 01 02 01 03 01 04
00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 2a
00 28 04 03 05 03 06 03 08 07 08 08 08 09 08 0a
08 0b 08 04 08 05 08 06 04 01 05 01 06 01 03 03
03 01 03 02 04 02 05 02 06 02 00 2b 00 09 08 03
04 03 03 03 02 03 01 00 2d 00 02 01 01 00 33 00
26 00 24 00 1d 00 20 8b 6d 58 60 ee 81 d9 92 f3
2f 6d 61 3f d9 f5 93 68 af 89 e3 7f 8a 7e f8 11
4f 9f 80 16 aa 08 29
TLS 1.0, RecordHeader [length 0005]
15 03 01 00 02
TLS 1.3, Alert [length 0002], fatal decode_error
02 32
B8390000:error:0A000126:SSL routines:ssl3_read_n:unexpected eof while reading:ssl\record\rec_layer_s3.c:304:
no peer certificate available
No client certificate CA names sent
SSL handshake has read 0 bytes and written 339 bytes
Verification: OKNew, (NONE), Cipher is (NONE)
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)I used: https://testconnectivity.microsoft.com/tests/exchange and then clicked "SSL Server Test"
result of the test:
Checking the SSL server mydomainname.duckdns.org on port 443.
One or more problems were found with the SSL endpoint.
Test Steps
Attempting to resolve the host name mydomainname.duckdns.org in DNS.
The host name resolved successfully.
Additional Details
Testing TCP port 443 on host (here was my dynamic IP) to ensure it's listening and open.
The port was opened successfully.
Testing the SSL certificate to make sure it's valid.
The SSL certificate failed one or more certificate validation checks.
Test Steps
The Microsoft Connectivity Analyzer is probing the TCP endpoint 37.248.128.93 on port 443 to detect which SSL/TLS protocols and cipher suites are enabled.
We were unable to determine which SSL and TLS protocols are enabled. This is usually because we couldn't connect.Any ideas???
-
I attached to more commands result which show which cipher suites openssl uses:
result:
openssl ciphers -s -vTLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD
TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD
TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD
ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD
DHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(256) Mac=AEAD
ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
DHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=DH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD
ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD
DHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AESGCM(128) Mac=AEAD
ECDHE-ECDSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA384
ECDHE-RSA-AES256-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA384
DHE-RSA-AES256-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(256) Mac=SHA256
ECDHE-ECDSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA256
ECDHE-RSA-AES128-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA256
DHE-RSA-AES128-SHA256 TLSv1.2 Kx=DH Au=RSA Enc=AES(128) Mac=SHA256
ECDHE-ECDSA-AES256-SHA TLSv1 Kx=ECDH Au=ECDSA Enc=AES(256) Mac=SHA1
ECDHE-RSA-AES256-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(256) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
ECDHE-ECDSA-AES128-SHA TLSv1 Kx=ECDH Au=ECDSA Enc=AES(128) Mac=SHA1
ECDHE-RSA-AES128-SHA TLSv1 Kx=ECDH Au=RSA Enc=AES(128) Mac=SHA1
DHE-RSA-AES128-SHA SSLv3 Kx=DH Au=RSA Enc=AES(128) Mac=SHA1
AES256-GCM-SHA384 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(256) Mac=AEAD
AES128-GCM-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AESGCM(128) Mac=AEAD
AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256
AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
AES128-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA1and the client side:
nmap -sV --script ssl-enum-ciphers -p 443 mydomainname.duckdns.org
Starting Nmap 7.94 ( https://nmap.org ) at 2023-10-08 16:31 central europe sommer time
Nmap scan report for mydomainname.duckdns.org (myip)
Host is up (0.00013s latency).
rDNS record for myip: apn-myip.myapnPORT STATE SERVICE VERSION
443/tcp open ssl/https?
| ssl-enum-ciphers:
| TLSv1.0:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 1024) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 1024) - A
| compressors:
| NULL
| cipher preference: client
| TLSv1.1:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 1024) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 1024) - A
| compressors:
| NULL
| cipher preference: client
| TLSv1.2:
| ciphers:
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (secp256r1) - A
| TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (secp256r1) - A
| TLS_RSA_WITH_AES_128_CBC_SHA (rsa 1024) - A
| TLS_RSA_WITH_AES_128_CBC_SHA256 (rsa 1024) - A
| TLS_RSA_WITH_AES_256_CBC_SHA (rsa 1024) - A
| TLS_RSA_WITH_AES_256_CBC_SHA256 (rsa 1024) - A
| compressors:
| NULL
| cipher preference: client
|_ least strength: AMaybe the cipher suits do not match??? what do you think???
-
-
@ChrisW67
The cert was ok. The problem was in configuration function
see hereunder:
was
httpServer.sslSetup(sslCertificateChain.front(), QSslKey(&privateKeyFile, QSsl::RSA ), QSsl::TlsV1_0OrLater);working config.
httpServer.sslSetup(sslCertificateChain.front(), QSslKey(&privateKeyFile, QSsl::Ec, ), QSsl::TlsV1_0OrLater);So I alter QSsl:RSA to QSsl::Ec -
this thanks to Let's Encrypt community forum. -