QCA

ssltest.cpp
1/*
2 Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20*/
21
22#include <QtCrypto>
23
24#include <QCoreApplication>
25#include <QTcpSocket>
26
27#ifdef QT_STATICPLUGIN
28#include "import_plugins.h"
29#endif
30
31char exampleCA_cert[] =
32 "-----BEGIN CERTIFICATE-----\n"
33 "MIICSzCCAbSgAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRMwEQYDVQQDEwpFeGFt\n"
34 "cGxlIENBMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwHhcNMDYw\n"
35 "MzE1MDY1ODMyWhcNMDYwNDE1MDY1ODMyWjA4MRMwEQYDVQQDEwpFeGFtcGxlIENB\n"
36 "MQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwgZ8wDQYJKoZIhvcN\n"
37 "AQEBBQADgY0AMIGJAoGBAL6ULdOxmpeZ+G/ypV12eNO4qnHSVIPTrYPkQuweXqPy\n"
38 "atwGFheG+hLVsNIh9GGOS0tCe7a3hBBKN0BJg1ppfk2x39cDx7hefYqjBuZvp/0O\n"
39 "8Ja3qlQiJLezITZKLxMBrsibcvcuH8zpfUdys2yaN+YGeqNfjQuoNN3Byl1TwuGJ\n"
40 "AgMBAAGjZTBjMB0GA1UdDgQWBBSQKCUCLNM7uKrAt5o7qv/yQm6qEzASBgNVHRMB\n"
41 "Af8ECDAGAQEBAgEIMB4GA1UdEQQXMBWBE2V4YW1wbGVAZXhhbXBsZS5jb20wDgYD\n"
42 "VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAAh+SIeT1Ao5qInw8oMSoTdO\n"
43 "lQ6h67ec/Jk5KmK4OoskuimmHI0Sp0C5kOCLehXbsVWW8pXsNC2fv0d2HkdaSUcX\n"
44 "hwLzqgyZXd4mupIYlaOTZhuHDwWPCAOZS4LVsi2tndTRHKCP12441JjNKhmZRhkR\n"
45 "u5zzD60nWgM9dKTaxuZM\n"
46 "-----END CERTIFICATE-----\n";
47
48void showCertInfo(const QCA::Certificate &cert)
49{
50 printf("-- Cert --\n");
51 printf(" CN: %s\n", qPrintable(cert.commonName()));
52 printf(" Valid from: %s, until %s\n",
53 qPrintable(cert.notValidBefore().toString()),
54 qPrintable(cert.notValidAfter().toString()));
55 printf(" PEM:\n%s\n", qPrintable(cert.toPEM()));
56}
57
58static QString validityToString(QCA::Validity v)
59{
60 QString s;
61 switch (v) {
63 s = QStringLiteral("Validated");
64 break;
66 s = QStringLiteral("Root CA is marked to reject the specified purpose");
67 break;
69 s = QStringLiteral("Certificate not trusted for the required purpose");
70 break;
72 s = QStringLiteral("Invalid signature");
73 break;
75 s = QStringLiteral("Invalid CA certificate");
76 break;
78 s = QStringLiteral("Invalid certificate purpose");
79 break;
81 s = QStringLiteral("Certificate is self-signed");
82 break;
84 s = QStringLiteral("Certificate has been revoked");
85 break;
87 s = QStringLiteral("Maximum certificate chain length exceeded");
88 break;
90 s = QStringLiteral("Certificate has expired");
91 break;
93 s = QStringLiteral("CA has expired");
94 break;
96 default:
97 s = QStringLiteral("General certificate validation error");
98 break;
99 }
100 return s;
101}
102
103class SecureTest : public QObject
104{
106public:
107 SecureTest()
108 {
109 sock_done = false;
110 ssl_done = false;
111
112 sock = new QTcpSocket;
113 connect(sock, &QTcpSocket::connected, this, &SecureTest::sock_connected);
114 connect(sock, &QTcpSocket::readyRead, this, &SecureTest::sock_readyRead);
115#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
116 connect(sock, &QTcpSocket::errorOccurred, this, &SecureTest::sock_error);
117#else
118 connect(sock, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &SecureTest::sock_error);
119#endif
120
121 ssl = new QCA::TLS;
122 connect(ssl, &QCA::TLS::certificateRequested, this, &SecureTest::ssl_certificateRequested);
123 connect(ssl, &QCA::TLS::handshaken, this, &SecureTest::ssl_handshaken);
124 connect(ssl, &QCA::TLS::readyRead, this, &SecureTest::ssl_readyRead);
125 connect(ssl, &QCA::TLS::readyReadOutgoing, this, &SecureTest::ssl_readyReadOutgoing);
126 connect(ssl, &QCA::TLS::closed, this, &SecureTest::ssl_closed);
127 connect(ssl, &QCA::TLS::error, this, &SecureTest::ssl_error);
128 }
129
130 ~SecureTest() override
131 {
132 delete ssl;
133 delete sock;
134 }
135
136 void start(const QString &_host)
137 {
138 int n = _host.indexOf(QLatin1Char(':'));
139 int port;
140 if (n != -1) {
141 host = _host.mid(0, n);
142#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
143 port = QStringView(_host).mid(n + 1).toInt();
144#else
145 port = _host.midRef(n + 1).toInt();
146#endif
147 } else {
148 host = _host;
149 port = 443;
150 }
151
152 printf("Trying %s:%d...\n", qPrintable(host), port);
153 sock->connectToHost(host, port);
154 }
155
157 void quit();
158
159private Q_SLOTS:
160 void sock_connected()
161 {
162 // We just do this to help doxygen...
163 QCA::TLS *ssl = SecureTest::ssl;
164
165 printf("Connected, starting TLS handshake...\n");
166
168
169 // We add this one to show how, and to make it work with
170 // the server example.
172
174 printf("Warning: no root certs\n");
175 else
176 ssl->setTrustedCertificates(rootCerts);
177
178 ssl->startClient(host);
179 }
180
181 void sock_readyRead()
182 {
183 // We just do this to help doxygen...
184 QCA::TLS *ssl = SecureTest::ssl;
185
186 ssl->writeIncoming(sock->readAll());
187 }
188
189 void sock_connectionClosed()
190 {
191 printf("\nConnection closed.\n");
192 sock_done = true;
193
194 if (ssl_done && sock_done)
195 emit quit();
196 }
197
198 void sock_error(QAbstractSocket::SocketError x)
199 {
201 sock_connectionClosed();
202 return;
203 }
204
205 printf("\nSocket error.\n");
206 emit quit();
207 }
208
209 void ssl_handshaken()
210 {
211 // We just do this to help doxygen...
212 QCA::TLS *ssl = SecureTest::ssl;
213
215
216 printf("Successful SSL handshake using %s (%i of %i bits)\n",
217 qPrintable(ssl->cipherSuite()),
218 ssl->cipherBits(),
219 ssl->cipherMaxBits());
220 if (r != QCA::TLS::NoCertificate) {
221 cert = ssl->peerCertificateChain().primary();
222 if (!cert.isNull())
223 showCertInfo(cert);
224 }
225
226 QString str = QStringLiteral("Peer Identity: ");
227 if (r == QCA::TLS::Valid)
228 str += QStringLiteral("Valid");
229 else if (r == QCA::TLS::HostMismatch)
230 str += QStringLiteral("Error: Wrong certificate");
231 else if (r == QCA::TLS::InvalidCertificate)
232 str += QStringLiteral("Error: Invalid certificate.\n -> Reason: ") +
233 validityToString(ssl->peerCertificateValidity());
234 else
235 str += QStringLiteral("Error: No certificate");
236 printf("%s\n", qPrintable(str));
237
238 ssl->continueAfterStep();
239
240 printf("Let's try a GET request now.\n");
241 QString req = QStringLiteral("GET / HTTP/1.0\nHost: ") + host + QStringLiteral("\n\n");
242 ssl->write(req.toLatin1());
243 }
244
245 void ssl_certificateRequested()
246 {
247 // We just do this to help doxygen...
248 QCA::TLS *ssl = SecureTest::ssl;
249
250 printf("Server requested client certificate.\n");
252 if (!issuerList.isEmpty()) {
253 printf("Allowed issuers:\n");
254 foreach (QCA::CertificateInfoOrdered i, issuerList)
255 printf(" %s\n", qPrintable(i.toString()));
256 }
257
258 ssl->continueAfterStep();
259 }
260
261 void ssl_readyRead()
262 {
263 // We just do this to help doxygen...
264 QCA::TLS *ssl = SecureTest::ssl;
265
266 QByteArray a = ssl->read();
267 printf("%s", a.data());
268 }
269
270 void ssl_readyReadOutgoing()
271 {
272 // We just do this to help doxygen...
273 QCA::TLS *ssl = SecureTest::ssl;
274
275 sock->write(ssl->readOutgoing());
276 }
277
278 void ssl_closed()
279 {
280 printf("SSL session closed.\n");
281 ssl_done = true;
282
283 if (ssl_done && sock_done)
284 emit quit();
285 }
286
287 void ssl_error()
288 {
289 // We just do this to help doxygen...
290 QCA::TLS *ssl = SecureTest::ssl;
291
292 int x = ssl->errorCode();
293 if (x == QCA::TLS::ErrorHandshake) {
294 printf("SSL Handshake Error!\n");
295 emit quit();
296 } else {
297 printf("SSL Error!\n");
298 emit quit();
299 }
300 }
301
302private:
303 QString host;
304 QTcpSocket *sock;
305 QCA::TLS *ssl;
306 QCA::Certificate cert;
307 bool sock_done, ssl_done;
308};
309
310#include "ssltest.moc"
311
312int main(int argc, char **argv)
313{
315
316 QCoreApplication app(argc, argv);
317 QString host = argc > 1 ? QString::fromLocal8Bit(argv[1]) : QStringLiteral("andbit.net");
318
319 if (!QCA::isSupported("tls")) {
320 printf("TLS not supported!\n");
321 return 1;
322 }
323
324 SecureTest *s = new SecureTest;
325 QObject::connect(s, &SecureTest::quit, &app, &QCoreApplication::quit);
326 s->start(host);
327 app.exec();
328 delete s;
329
330 return 0;
331}
const Certificate & primary() const
Return the primary (end-user) Certificate.
Definition qca_cert.h:1249
Bundle of Certificates and CRLs.
Definition qca_cert.h:1929
void addCertificate(const Certificate &cert)
Append a Certificate to this collection.
Ordered certificate properties type.
Definition qca_cert.h:548
QString toString() const
Convert to RFC 1779 string format.
Definition qca_cert.h:577
Public Key (X.509) certificate.
Definition qca_cert.h:857
static Certificate fromPEM(const QString &s, ConvertResult *result=nullptr, const QString &provider=QString())
Import the certificate from PEM format.
QString commonName() const
The common name of the subject of the certificate.
QDateTime notValidBefore() const
The earliest date that the certificate is valid.
QString toPEM() const
Export the Certificate into a PEM format.
QDateTime notValidAfter() const
The latest date that the certificate is valid.
bool isNull() const
Test if the certificate is empty (null)
Convenience method for initialising and cleaning up QCA.
Definition qca_core.h:660
void error()
This signal is emitted when an error is detected.
void readyReadOutgoing()
This signal is emitted when SecureLayer has encrypted (network side) data ready to be read.
void closed()
This signal is emitted when the SecureLayer connection is closed.
void readyRead()
This signal is emitted when SecureLayer has decrypted (application side) data ready to be read.
Transport Layer Security / Secure Socket Layer.
int cipherMaxBits() const
The number of bits of security that the cipher could use.
void write(const QByteArray &a) override
This method writes unencrypted (plain) data to the SecureLayer implementation.
void startClient(const QString &host=QString())
Start the TLS/SSL connection as a client.
void writeIncoming(const QByteArray &a) override
This method accepts encoded (typically encrypted) data for processing.
void continueAfterStep()
Resumes TLS processing.
int cipherBits() const
The number of effective bits of security being used for this connection.
@ ErrorHandshake
problem during the negotiation
void setTrustedCertificates(const CertificateCollection &trusted)
Set up the set of trusted certificates that will be used to verify that the certificate provided is v...
QList< CertificateInfoOrdered > issuerList() const
IdentityResult peerIdentityResult() const
After the SSL/TLS handshake is complete, this method allows you to determine if the other end of the ...
QByteArray readOutgoing(int *plainBytes=nullptr) override
This method provides encoded (typically encrypted) data.
IdentityResult
Type of identity.
@ HostMismatch
valid cert provided, but wrong owner
@ InvalidCertificate
invalid cert
@ Valid
identity is verified
@ NoCertificate
identity unknown
QByteArray read() override
This method reads decrypted (plain) data from the SecureLayer implementation.
Validity peerCertificateValidity() const
After the SSL/TLS handshake is valid, this method allows you to check if the received certificate fro...
Error errorCode() const
This method returns the type of error that has occurred.
CertificateChain peerCertificateChain() const
The CertificateChain from the peer (other end of the connection to the trusted root certificate).
QString cipherSuite() const
The cipher suite that has been negotiated for this connection.
void handshaken()
Emitted when the protocol handshake is complete.
void certificateRequested()
Emitted when the server requests a certificate.
Q_SCRIPTABLE Q_NOREPLY void start()
void init(KXmlGuiWindow *window, KGameDifficulty *difficulty=nullptr)
Validity
The validity (or otherwise) of a certificate.
Definition qca_cert.h:497
@ ErrorValidityUnknown
Validity is unknown.
Definition qca_cert.h:510
@ ErrorRevoked
The certificate has been revoked.
Definition qca_cert.h:505
@ ErrorUntrusted
The certificate is not trusted.
Definition qca_cert.h:500
@ ErrorExpired
The certificate has expired, or is not yet valid (e.g.
Definition qca_cert.h:507
@ ErrorPathLengthExceeded
The path length from the root CA to this certificate is too long.
Definition qca_cert.h:506
@ ErrorSignatureFailed
The signature does not match.
Definition qca_cert.h:501
@ ErrorInvalidPurpose
The purpose does not match the intended usage.
Definition qca_cert.h:503
@ ErrorExpiredCA
The Certificate Authority has expired.
Definition qca_cert.h:509
@ ErrorSelfSigned
The certificate is self-signed, and is not found in the list of trusted certificates.
Definition qca_cert.h:504
@ ErrorInvalidCA
The Certificate Authority is invalid.
Definition qca_cert.h:502
@ ValidityGood
The certificate is valid.
Definition qca_cert.h:498
@ ErrorRejected
The root CA rejected the certificate purpose.
Definition qca_cert.h:499
QCA_EXPORT bool haveSystemStore()
Test if QCA can access the root CA certificates.
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
QCA_EXPORT CertificateCollection systemStore()
Get system-wide root Certificate Authority (CA) certificates.
void connectToHost(const QHostAddress &address, quint16 port, OpenMode openMode)
SocketError error() const const
void errorOccurred(QAbstractSocket::SocketError socketError)
char * data()
QString toString(QStringView format, QCalendar cal) const const
QByteArray readAll()
void readyRead()
qint64 write(const QByteArray &data)
bool isEmpty() const const
Q_OBJECTQ_OBJECT
Q_SIGNALSQ_SIGNALS
Q_SLOTSQ_SLOTS
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString fromLatin1(QByteArrayView str)
QString fromLocal8Bit(QByteArrayView str)
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
QString mid(qsizetype position, qsizetype n) const const
int toInt(bool *ok, int base) const const
QByteArray toLatin1() const const
QStringView mid(qsizetype start, qsizetype length) const const
int toInt(bool *ok, int base) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri May 24 2024 11:53:51 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.