ssltest.cpp

The code below shows how to create an SSL client

00001 /*
00002  Copyright (C) 2003-2005 Justin Karneges <justin@affinix.com>
00003 
00004  Permission is hereby granted, free of charge, to any person obtaining a copy
00005  of this software and associated documentation files (the "Software"), to deal
00006  in the Software without restriction, including without limitation the rights
00007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  copies of the Software, and to permit persons to whom the Software is
00009  furnished to do so, subject to the following conditions:
00010 
00011  The above copyright notice and this permission notice shall be included in
00012  all copies or substantial portions of the Software.
00013 
00014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00020 */
00021 
00022 #include <QtCrypto>
00023 
00024 #include <QCoreApplication>
00025 #include <QTcpSocket>
00026 
00027 char exampleCA_cert[] =
00028         "-----BEGIN CERTIFICATE-----\n"
00029         "MIICSzCCAbSgAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRMwEQYDVQQDEwpFeGFt\n"
00030         "cGxlIENBMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwHhcNMDYw\n"
00031         "MzE1MDY1ODMyWhcNMDYwNDE1MDY1ODMyWjA4MRMwEQYDVQQDEwpFeGFtcGxlIENB\n"
00032         "MQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBsZSBPcmcwgZ8wDQYJKoZIhvcN\n"
00033         "AQEBBQADgY0AMIGJAoGBAL6ULdOxmpeZ+G/ypV12eNO4qnHSVIPTrYPkQuweXqPy\n"
00034         "atwGFheG+hLVsNIh9GGOS0tCe7a3hBBKN0BJg1ppfk2x39cDx7hefYqjBuZvp/0O\n"
00035         "8Ja3qlQiJLezITZKLxMBrsibcvcuH8zpfUdys2yaN+YGeqNfjQuoNN3Byl1TwuGJ\n"
00036         "AgMBAAGjZTBjMB0GA1UdDgQWBBSQKCUCLNM7uKrAt5o7qv/yQm6qEzASBgNVHRMB\n"
00037         "Af8ECDAGAQEBAgEIMB4GA1UdEQQXMBWBE2V4YW1wbGVAZXhhbXBsZS5jb20wDgYD\n"
00038         "VR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4GBAAh+SIeT1Ao5qInw8oMSoTdO\n"
00039         "lQ6h67ec/Jk5KmK4OoskuimmHI0Sp0C5kOCLehXbsVWW8pXsNC2fv0d2HkdaSUcX\n"
00040         "hwLzqgyZXd4mupIYlaOTZhuHDwWPCAOZS4LVsi2tndTRHKCP12441JjNKhmZRhkR\n"
00041         "u5zzD60nWgM9dKTaxuZM\n"
00042         "-----END CERTIFICATE-----\n";
00043 
00044 void showCertInfo(const QCA::Certificate &cert)
00045 {
00046         printf("-- Cert --\n");
00047         printf(" CN: %s\n", qPrintable(cert.commonName()));
00048         printf(" Valid from: %s, until %s\n",
00049                 qPrintable(cert.notValidBefore().toString()),
00050                 qPrintable(cert.notValidAfter().toString()));
00051         printf(" PEM:\n%s\n", qPrintable(cert.toPEM()));
00052 }
00053 
00054 static QString validityToString(QCA::Validity v)
00055 {
00056         QString s;
00057         switch(v)
00058         {
00059                 case QCA::ValidityGood:
00060                         s = "Validated";
00061                         break;
00062                 case QCA::ErrorRejected:
00063                         s = "Root CA is marked to reject the specified purpose";
00064                         break;
00065                 case QCA::ErrorUntrusted:
00066                         s = "Certificate not trusted for the required purpose";
00067                         break;
00068                 case QCA::ErrorSignatureFailed:
00069                         s = "Invalid signature";
00070                         break;
00071                 case QCA::ErrorInvalidCA:
00072                         s = "Invalid CA certificate";
00073                         break;
00074                 case QCA::ErrorInvalidPurpose:
00075                         s = "Invalid certificate purpose";
00076                         break;
00077                 case QCA::ErrorSelfSigned:
00078                         s = "Certificate is self-signed";
00079                         break;
00080                 case QCA::ErrorRevoked:
00081                         s = "Certificate has been revoked";
00082                         break;
00083                 case QCA::ErrorPathLengthExceeded:
00084                         s = "Maximum certificate chain length exceeded";
00085                         break;
00086                 case QCA::ErrorExpired:
00087                         s = "Certificate has expired";
00088                         break;
00089                 case QCA::ErrorExpiredCA:
00090                         s = "CA has expired";
00091                         break;
00092                 case QCA::ErrorValidityUnknown:
00093                 default:
00094                         s = "General certificate validation error";
00095                         break;
00096         }
00097         return s;
00098 }
00099 
00100 class SecureTest : public QObject
00101 {
00102         Q_OBJECT
00103 public:
00104         SecureTest()
00105         {
00106                 sock_done = false;
00107                 ssl_done = false;
00108 
00109                 sock = new QTcpSocket;
00110                 connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
00111                 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
00112                 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)),
00113                         SLOT(sock_error(QAbstractSocket::SocketError)));
00114 
00115                 ssl = new QCA::TLS;
00116                 connect(ssl, SIGNAL(certificateRequested()), SLOT(ssl_certificateRequested()));
00117                 connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
00118                 connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
00119                 connect(ssl, SIGNAL(readyReadOutgoing()),
00120                         SLOT(ssl_readyReadOutgoing()));
00121                 connect(ssl, SIGNAL(closed()), SLOT(ssl_closed()));
00122                 connect(ssl, SIGNAL(error()), SLOT(ssl_error()));
00123         }
00124 
00125         ~SecureTest()
00126         {
00127                 delete ssl;
00128                 delete sock;
00129         }
00130 
00131         void start(const QString &_host)
00132         {
00133                 int n = _host.indexOf(':');
00134                 int port;
00135                 if(n != -1)
00136                 {
00137                         host = _host.mid(0, n);
00138                         port = _host.mid(n+1).toInt();
00139                 }
00140                 else
00141                 {
00142                         host = _host;
00143                         port = 443;
00144                 }
00145 
00146                 printf("Trying %s:%d...\n", qPrintable(host), port);
00147                 sock->connectToHost(host, port);
00148         }
00149 
00150 signals:
00151         void quit();
00152 
00153 private slots:
00154         void sock_connected()
00155         {
00156                 // We just do this to help doxygen...
00157                 QCA::TLS *ssl = SecureTest::ssl;
00158 
00159                 printf("Connected, starting TLS handshake...\n");
00160 
00161                 QCA::CertificateCollection rootCerts = QCA::systemStore();
00162 
00163                 // We add this one to show how, and to make it work with
00164                 // the server example.
00165                 rootCerts.addCertificate(QCA::Certificate::fromPEM(exampleCA_cert));
00166 
00167                 if(!QCA::haveSystemStore())
00168                         printf("Warning: no root certs\n");
00169                 else
00170                         ssl->setTrustedCertificates(rootCerts);
00171 
00172                 ssl->startClient(host);
00173         }
00174 
00175         void sock_readyRead()
00176         {
00177                 // We just do this to help doxygen...
00178                 QCA::TLS *ssl = SecureTest::ssl;
00179 
00180                 ssl->writeIncoming(sock->readAll());
00181         }
00182 
00183         void sock_connectionClosed()
00184         {
00185                 printf("\nConnection closed.\n");
00186                 sock_done = true;
00187 
00188                 if(ssl_done && sock_done)
00189                         emit quit();
00190         }
00191 
00192         void sock_error(QAbstractSocket::SocketError x)
00193         {
00194                 if(x == QAbstractSocket::RemoteHostClosedError)
00195                 {
00196                         sock_connectionClosed();
00197                         return;
00198                 }
00199 
00200                 printf("\nSocket error.\n");
00201                 emit quit();
00202         }
00203 
00204         void ssl_handshaken()
00205         {
00206                 // We just do this to help doxygen...
00207                 QCA::TLS *ssl = SecureTest::ssl;
00208 
00209                 QCA::TLS::IdentityResult r = ssl->peerIdentityResult();
00210 
00211                 printf("Successful SSL handshake using %s (%i of %i bits)\n",
00212                        qPrintable(ssl->cipherSuite()),
00213                        ssl->cipherBits(),
00214                        ssl->cipherMaxBits() );
00215                 if(r != QCA::TLS::NoCertificate)
00216                 {
00217                         cert = ssl->peerCertificateChain().primary();
00218                         if(!cert.isNull())
00219                                 showCertInfo(cert);
00220                 }
00221 
00222                 QString str = "Peer Identity: ";
00223                 if(r == QCA::TLS::Valid)
00224                         str += "Valid";
00225                 else if(r == QCA::TLS::HostMismatch)
00226                         str += "Error: Wrong certificate";
00227                 else if(r == QCA::TLS::InvalidCertificate)
00228                         str += "Error: Invalid certificate.\n -> Reason: " +
00229                                 validityToString(ssl->peerCertificateValidity());
00230                 else
00231                         str += "Error: No certificate";
00232                 printf("%s\n", qPrintable(str));
00233 
00234                 ssl->continueAfterStep();
00235 
00236                 printf("Let's try a GET request now.\n");
00237                 QString req = "GET / HTTP/1.0\nHost: " + host + "\n\n";
00238                 ssl->write(req.toLatin1());
00239         }
00240 
00241         void ssl_certificateRequested()
00242         {
00243                 // We just do this to help doxygen...
00244                 QCA::TLS *ssl = SecureTest::ssl;
00245 
00246                 printf("Server requested client certificate.\n");
00247                 QList<QCA::CertificateInfoOrdered> issuerList = ssl->issuerList();
00248                 if(!issuerList.isEmpty())
00249                 {
00250                         printf("Allowed issuers:\n");
00251                         foreach(QCA::CertificateInfoOrdered i, issuerList)
00252                                 printf("  %s\n", qPrintable(i.toString()));
00253                 }
00254 
00255                 ssl->continueAfterStep();
00256         }
00257 
00258         void ssl_readyRead()
00259         {
00260                 // We just do this to help doxygen...
00261                 QCA::TLS *ssl = SecureTest::ssl;
00262 
00263                 QByteArray a = ssl->read();
00264                 printf("%s", a.data());
00265         }
00266 
00267         void ssl_readyReadOutgoing()
00268         {
00269                 // We just do this to help doxygen...
00270                 QCA::TLS *ssl = SecureTest::ssl;
00271 
00272                 sock->write(ssl->readOutgoing());
00273         }
00274 
00275         void ssl_closed()
00276         {
00277                 printf("SSL session closed.\n");
00278                 ssl_done = true;
00279 
00280                 if(ssl_done && sock_done)
00281                         emit quit();
00282         }
00283 
00284         void ssl_error()
00285         {
00286                 // We just do this to help doxygen...
00287                 QCA::TLS *ssl = SecureTest::ssl;
00288 
00289                 int x = ssl->errorCode();
00290                 if(x == QCA::TLS::ErrorHandshake)
00291                 {
00292                         printf("SSL Handshake Error!\n");
00293                         emit quit();
00294                 }
00295                 else
00296                 {
00297                         printf("SSL Error!\n");
00298                         emit quit();
00299                 }
00300         }
00301 
00302 private:
00303         QString host;
00304         QTcpSocket *sock;
00305         QCA::TLS *ssl;
00306         QCA::Certificate cert;
00307         bool sock_done, ssl_done;
00308 };
00309 
00310 #include "ssltest.moc"
00311 
00312 int main(int argc, char **argv)
00313 {
00314         QCA::Initializer init;
00315 
00316         QCoreApplication app(argc, argv);
00317         QString host = argc > 1 ? argv[1] : "andbit.net";
00318 
00319         if(!QCA::isSupported("tls"))
00320         {
00321                 printf("TLS not supported!\n");
00322                 return 1;
00323         }
00324 
00325         SecureTest *s = new SecureTest;
00326         QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
00327         s->start(host);
00328         app.exec();
00329         delete s;
00330 
00331         return 0;
00332 }

Generated on Thu Sep 6 19:13:35 2007 for Qt Cryptographic Architecture by  doxygen 1.5.2