#include #include #include #include #include #include"base64.h" #include"qca.h" TQCA::Cert readCertXml(const TQDomElement &e) { TQCA::Cert cert; // there should be one child data tag TQDomElement data = e.elementsByTagName("data").item(0).toElement(); if(!data.isNull()) cert.fromDER(Base64::stringToArray(data.text())); return cert; } void showCertInfo(const TQCA::Cert &cert) { printf("-- Cert --\n"); printf(" CN: %s\n", cert.subject()["CN"].latin1()); printf(" Valid from: %s, until %s\n", cert.notBefore().toString().latin1(), cert.notAfter().toString().latin1()); printf(" PEM:\n%s\n", cert.toPEM().latin1()); } TQPtrList getRootCerts(const TQString &store) { TQPtrList list; // open the Psi rootcerts file TQFile f(store); if(!f.open(IO_ReadOnly)) { printf("unable to open %s\n", f.name().latin1()); return list; } TQDomDocument doc; doc.setContent(&f); f.close(); TQDomElement base = doc.documentElement(); if(base.tagName() != "store") { printf("wrong format of %s\n", f.name().latin1()); return list; } TQDomNodeList cl = base.elementsByTagName("certificate"); if(cl.count() == 0) { printf("no certs found in %s\n", f.name().latin1()); return list; } int num = 0; for(int n = 0; n < (int)cl.count(); ++n) { TQCA::Cert *cert = new TQCA::Cert(readCertXml(cl.item(n).toElement())); if(cert->isNull()) { printf("error reading cert\n"); delete cert; continue; } ++num; list.append(cert); } printf("imported %d root certs\n", num); return list; } TQString resultToString(int result) { TQString s; switch(result) { case TQCA::TLS::NoCert: s = TQObject::tr("No certificate presented."); break; case TQCA::TLS::Valid: break; case TQCA::TLS::HostMismatch: s = TQObject::tr("Hostname mismatch."); break; case TQCA::TLS::Rejected: s = TQObject::tr("Root CA rejects the specified purpose."); break; case TQCA::TLS::Untrusted: s = TQObject::tr("Not trusted for the specified purpose."); break; case TQCA::TLS::SignatureFailed: s = TQObject::tr("Invalid signature."); break; case TQCA::TLS::InvalidCA: s = TQObject::tr("Invalid CA certificate."); break; case TQCA::TLS::InvalidPurpose: s = TQObject::tr("Invalid certificate purpose."); break; case TQCA::TLS::SelfSigned: s = TQObject::tr("Certificate is self-signed."); break; case TQCA::TLS::Revoked: s = TQObject::tr("Certificate has been revoked."); break; case TQCA::TLS::PathLengthExceeded: s = TQObject::tr("Maximum cert chain length exceeded."); break; case TQCA::TLS::Expired: s = TQObject::tr("Certificate has expired."); break; case TQCA::TLS::Unknown: default: s = TQObject::tr("General validation error."); break; } return s; } class SecureTest : public TQObject { Q_OBJECT public: SecureTest() { sock = new TQSocket; connect(sock, SIGNAL(connected()), SLOT(sock_connected())); connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed())); connect(sock, SIGNAL(error(int)), SLOT(sock_error(int))); ssl = new TQCA::TLS; connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken())); connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead())); connect(ssl, SIGNAL(readyReadOutgoing(int)), SLOT(ssl_readyReadOutgoing(int))); connect(ssl, SIGNAL(closed()), SLOT(ssl_closed())); connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int))); rootCerts.setAutoDelete(true); rootCerts = getRootCerts("/usr/local/share/psi/certs/rootcert.xml"); } ~SecureTest() { delete ssl; delete sock; } void start(const TQString &_host) { int n = _host.find(':'); int port; if(n != -1) { host = _host.mid(0, n); port = _host.mid(n+1).toInt(); } else { host = _host; port = 443; } printf("Trying %s:%d...\n", host.latin1(), port); sock->connectToHost(host, port); } signals: void quit(); private slots: void sock_connected() { printf("Connected, starting TLS handshake...\n"); ssl->setCertificateStore(rootCerts); ssl->startClient(host); } void sock_readyRead() { TQByteArray buf(sock->bytesAvailable()); int num = sock->readBlock(buf.data(), buf.size()); if(num < (int)buf.size()) buf.resize(num); ssl->writeIncoming(buf); } void sock_connectionClosed() { printf("\nConnection closed.\n"); quit(); } void sock_error(int) { printf("\nSocket error.\n"); quit(); } void ssl_handshaken() { cert = ssl->peerCertificate(); int vr = ssl->certificateValidityResult(); printf("Successful SSL handshake.\n"); if(!cert.isNull()) showCertInfo(cert); if(vr == TQCA::TLS::Valid) printf("Valid certificate.\n"); else printf("Invalid certificate: %s\n", resultToString(vr).latin1()); printf("Let's try a GET request now.\n"); TQString req = "GET / HTTP/1.0\nHost: " + host + "\n\n"; TQCString cs = req.latin1(); TQByteArray buf(cs.length()); memcpy(buf.data(), cs.data(), buf.size()); ssl->write(buf); } void ssl_readyRead() { TQByteArray a = ssl->read(); TQCString cs; cs.resize(a.size()+1); memcpy(cs.data(), a.data(), a.size()); printf("%s", cs.data()); } void ssl_readyReadOutgoing(int) { TQByteArray a = ssl->readOutgoing(); sock->writeBlock(a.data(), a.size()); } void ssl_closed() { printf("SSL session closed\n"); } void ssl_error(int x) { if(x == TQCA::TLS::ErrHandshake) { printf("SSL Handshake Error!\n"); quit(); } else { printf("SSL Error!\n"); quit(); } } private: TQString host; TQSocket *sock; TQCA::TLS *ssl; TQCA::Cert cert; TQPtrList rootCerts; }; #include"ssltest.moc" int main(int argc, char **argv) { TQApplication app(argc, argv, false); TQString host = argc > 1 ? argv[1] : "andbit.net"; if(!TQCA::isSupported(TQCA::CAP_TLS)) { printf("TLS not supported!\n"); return 1; } SecureTest *s = new SecureTest; TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit())); s->start(host); app.exec(); delete s; return 0; }