You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqca/examples/ssltest/ssltest.cpp

277 lines
6.0 KiB

#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;
}