QCA

ssltest.cpp
1 /*
2  Copyright (C) 2003-2005 Justin Karneges <[email protected]>
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 
31 char 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 
48 void 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 
58 static QString validityToString(QCA::Validity v)
59 {
60  QString s;
61  switch (v) {
62  case QCA::ValidityGood:
63  s = QStringLiteral("Validated");
64  break;
65  case QCA::ErrorRejected:
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;
83  case QCA::ErrorRevoked:
84  s = QStringLiteral("Certificate has been revoked");
85  break;
87  s = QStringLiteral("Maximum certificate chain length exceeded");
88  break;
89  case QCA::ErrorExpired:
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 
103 class SecureTest : public QObject
104 {
105  Q_OBJECT
106 public:
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 
156 Q_SIGNALS:
157  void quit();
158 
159 private 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 
173  if (!QCA::haveSystemStore())
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 
302 private:
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 
312 int 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 }
bool isNull() const
Test if the certificate is empty (null)
QString toString(Qt::DateFormat format) const const
int toInt(bool *ok, int base) const const
void handshaken()
Emitted when the protocol handshake is complete.
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
The root CA rejected the certificate purpose.
Definition: qca_cert.h:499
const Certificate & primary() const
Return the primary (end-user) Certificate.
Definition: qca_cert.h:1249
int cipherBits() const
The number of effective bits of security being used for this connection.
QString toPEM() const
Export the Certificate into a PEM format.
void setTrustedCertificates(const CertificateCollection &trusted)
Set up the set of trusted certificates that will be used to verify that the certificate provided is v...
The certificate is self-signed, and is not found in the list of trusted certificates.
Definition: qca_cert.h:504
QString cipherSuite() const
The cipher suite that has been negotiated for this connection.
void readyRead()
This signal is emitted when SecureLayer has decrypted (application side) data ready to be read...
identity is verified
Validity
The validity (or otherwise) of a certificate.
Definition: qca_cert.h:496
QAbstractSocket::SocketError error() const const
QCA_EXPORT bool haveSystemStore()
Test if QCA can access the root CA certificates.
Q_SIGNALSQ_SIGNALS
void closed()
This signal is emitted when the SecureLayer connection is closed.
The certificate has been revoked.
Definition: qca_cert.h:505
static Certificate fromPEM(const QString &s, ConvertResult *result=nullptr, const QString &provider=QString())
Import the certificate from PEM format.
Validity is unknown.
Definition: qca_cert.h:510
void addCertificate(const Certificate &cert)
Append a Certificate to this collection.
The certificate is not trusted.
Definition: qca_cert.h:500
QString fromLocal8Bit(const char *str, int size)
The signature does not match.
Definition: qca_cert.h:501
void continueAfterStep()
Resumes TLS processing.
Transport Layer Security / Secure Socket Layer.
void certificateRequested()
Emitted when the server requests a certificate.
Q_OBJECTQ_OBJECT
QCA_EXPORT bool isSupported(const char *features, const QString &provider=QString())
Test if a capability (algorithm) is available.
QByteArray read() override
This method reads decrypted (plain) data from the SecureLayer implementation.
IdentityResult peerIdentityResult() const
After the SSL/TLS handshake is complete, this method allows you to determine if the other end of the ...
bool isEmpty() const const
valid cert provided, but wrong owner
void readyReadOutgoing()
This signal is emitted when SecureLayer has encrypted (network side) data ready to be read...
Ordered certificate properties type.
Definition: qca_cert.h:547
QString toString() const
Convert to RFC 1779 string format.
Definition: qca_cert.h:577
void writeIncoming(const QByteArray &a) override
This method accepts encoded (typically encrypted) data for processing.
The path length from the root CA to this certificate is too long.
Definition: qca_cert.h:506
The certificate has expired, or is not yet valid (e.g.
Definition: qca_cert.h:507
The Certificate Authority has expired.
Definition: qca_cert.h:509
QCA_EXPORT CertificateCollection systemStore()
Get system-wide root Certificate Authority (CA) certificates.
The purpose does not match the intended usage.
Definition: qca_cert.h:503
QStringRef midRef(int position, int n) const const
QCA_EXPORT void init()
Initialise QCA.
IdentityResult
Type of identity.
void startClient(const QString &host=QString())
Start the TLS/SSL connection as a client.
QByteArray toLatin1() const const
QString mid(int position, int n) const const
QDateTime notValidBefore() const
The earliest date that the certificate is valid.
void errorOccurred(QAbstractSocket::SocketError socketError)
QDateTime notValidAfter() const
The latest date that the certificate is valid.
QString commonName() const
The common name of the subject of the certificate.
CertificateChain peerCertificateChain() const
The CertificateChain from the peer (other end of the connection to the trusted root certificate)...
QByteArray readOutgoing(int *plainBytes=nullptr) override
This method provides encoded (typically encrypted) data.
int cipherMaxBits() const
The number of bits of security that the cipher could use.
void error()
This signal is emitted when an error is detected.
Error errorCode() const
This method returns the type of error that has occurred.
char * data()
Convenience method for initialising and cleaning up QCA.
Definition: qca_core.h:659
QString fromLatin1(const char *str, int size)
The certificate is valid.
Definition: qca_cert.h:498
void write(const QByteArray &a) override
This method writes unencrypted (plain) data to the SecureLayer implementation.
QList< CertificateInfoOrdered > issuerList() const
Retrieve the list of allowed issuers by the server, if the server has provided them.
Public Key (X.509) certificate.
Definition: qca_cert.h:856
problem during the negotiation
void readyRead()
Q_SLOTSQ_SLOTS
Validity peerCertificateValidity() const
After the SSL/TLS handshake is valid, this method allows you to check if the received certificate fro...
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
Bundle of Certificates and CRLs.
Definition: qca_cert.h:1928
QStringView mid(qsizetype start) const const
const QList< QKeySequence > & quit()
The Certificate Authority is invalid.
Definition: qca_cert.h:502
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Sep 25 2021 23:05:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.