00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00157 QCA::TLS *ssl = SecureTest::ssl;
00158
00159 printf("Connected, starting TLS handshake...\n");
00160
00161 QCA::CertificateCollection rootCerts = QCA::systemStore();
00162
00163
00164
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
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
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
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
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
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
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 }