diff options
Diffstat (limited to 'examples/ssltest/ssltest.cpp')
-rw-r--r-- | examples/ssltest/ssltest.cpp | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/examples/ssltest/ssltest.cpp b/examples/ssltest/ssltest.cpp new file mode 100644 index 0000000..f26f293 --- /dev/null +++ b/examples/ssltest/ssltest.cpp @@ -0,0 +1,276 @@ +#include<tqapplication.h> +#include<tqdom.h> +#include<tqfile.h> +#include<tqsocket.h> +#include<tqptrlist.h> +#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<TQCA::Cert> getRootCerts(const TQString &store) +{ + TQPtrList<TQCA::Cert> 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<TQCA::Cert> 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; +} |