mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-29 13:04:31 +00:00
show the two ways to do a basic hash. Also, an example of some of the options for working with providers. More comments to explain everything. This also adds copyright notices for everything, and notes on the pre-QCA2 examples. svn path=/trunk/kdesupport/qca/; revision=374181
299 lines
7.0 KiB
C++
299 lines
7.0 KiB
C++
/*
|
|
Copyright (C) 2003 Justin Karneges
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
// TODO: this code needs to be updated for QCA2
|
|
#include<qapplication.h>
|
|
#include<qdom.h>
|
|
#include<qfile.h>
|
|
#include<qsocket.h>
|
|
#include<qptrlist.h>
|
|
#include"base64.h"
|
|
#include"qca.h"
|
|
|
|
QCA::Cert readCertXml(const QDomElement &e)
|
|
{
|
|
QCA::Cert cert;
|
|
// there should be one child data tag
|
|
QDomElement data = e.elementsByTagName("data").item(0).toElement();
|
|
if(!data.isNull())
|
|
cert.fromDER(Base64::stringToArray(data.text()));
|
|
return cert;
|
|
}
|
|
|
|
void showCertInfo(const QCA::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());
|
|
}
|
|
|
|
QPtrList<QCA::Cert> getRootCerts(const QString &store)
|
|
{
|
|
QPtrList<QCA::Cert> list;
|
|
|
|
// open the Psi rootcerts file
|
|
QFile f(store);
|
|
if(!f.open(IO_ReadOnly)) {
|
|
printf("unable to open %s\n", f.name().latin1());
|
|
return list;
|
|
}
|
|
QDomDocument doc;
|
|
doc.setContent(&f);
|
|
f.close();
|
|
|
|
QDomElement base = doc.documentElement();
|
|
if(base.tagName() != "store") {
|
|
printf("wrong format of %s\n", f.name().latin1());
|
|
return list;
|
|
}
|
|
QDomNodeList 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) {
|
|
QCA::Cert *cert = new QCA::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;
|
|
}
|
|
|
|
QString resultToString(int result)
|
|
{
|
|
QString s;
|
|
switch(result) {
|
|
case QCA::TLS::NoCert:
|
|
s = QObject::tr("No certificate presented.");
|
|
break;
|
|
case QCA::TLS::Valid:
|
|
break;
|
|
case QCA::TLS::HostMismatch:
|
|
s = QObject::tr("Hostname mismatch.");
|
|
break;
|
|
case QCA::TLS::Rejected:
|
|
s = QObject::tr("Root CA rejects the specified purpose.");
|
|
break;
|
|
case QCA::TLS::Untrusted:
|
|
s = QObject::tr("Not trusted for the specified purpose.");
|
|
break;
|
|
case QCA::TLS::SignatureFailed:
|
|
s = QObject::tr("Invalid signature.");
|
|
break;
|
|
case QCA::TLS::InvalidCA:
|
|
s = QObject::tr("Invalid CA certificate.");
|
|
break;
|
|
case QCA::TLS::InvalidPurpose:
|
|
s = QObject::tr("Invalid certificate purpose.");
|
|
break;
|
|
case QCA::TLS::SelfSigned:
|
|
s = QObject::tr("Certificate is self-signed.");
|
|
break;
|
|
case QCA::TLS::Revoked:
|
|
s = QObject::tr("Certificate has been revoked.");
|
|
break;
|
|
case QCA::TLS::PathLengthExceeded:
|
|
s = QObject::tr("Maximum cert chain length exceeded.");
|
|
break;
|
|
case QCA::TLS::Expired:
|
|
s = QObject::tr("Certificate has expired.");
|
|
break;
|
|
case QCA::TLS::Unknown:
|
|
default:
|
|
s = QObject::tr("General validation error.");
|
|
break;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
class SecureTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
SecureTest()
|
|
{
|
|
sock = new QSocket;
|
|
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 QCA::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 QString &_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()
|
|
{
|
|
QByteArray 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 == QCA::TLS::Valid)
|
|
printf("Valid certificate.\n");
|
|
else
|
|
printf("Invalid certificate: %s\n", resultToString(vr).latin1());
|
|
|
|
printf("Let's try a GET request now.\n");
|
|
QString req = "GET / HTTP/1.0\nHost: " + host + "\n\n";
|
|
QCString cs = req.latin1();
|
|
QByteArray buf(cs.length());
|
|
memcpy(buf.data(), cs.data(), buf.size());
|
|
ssl->write(buf);
|
|
}
|
|
|
|
void ssl_readyRead()
|
|
{
|
|
QByteArray a = ssl->read();
|
|
QCString cs;
|
|
cs.resize(a.size()+1);
|
|
memcpy(cs.data(), a.data(), a.size());
|
|
printf("%s", cs.data());
|
|
}
|
|
|
|
void ssl_readyReadOutgoing(int)
|
|
{
|
|
QByteArray a = ssl->readOutgoing();
|
|
sock->writeBlock(a.data(), a.size());
|
|
}
|
|
|
|
void ssl_closed()
|
|
{
|
|
printf("SSL session closed\n");
|
|
}
|
|
|
|
void ssl_error(int x)
|
|
{
|
|
if(x == QCA::TLS::ErrHandshake) {
|
|
printf("SSL Handshake Error!\n");
|
|
quit();
|
|
}
|
|
else {
|
|
printf("SSL Error!\n");
|
|
quit();
|
|
}
|
|
}
|
|
|
|
private:
|
|
QString host;
|
|
QSocket *sock;
|
|
QCA::TLS *ssl;
|
|
QCA::Cert cert;
|
|
QPtrList<QCA::Cert> rootCerts;
|
|
};
|
|
|
|
#include"ssltest.moc"
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
QApplication app(argc, argv, false);
|
|
QString host = argc > 1 ? argv[1] : "andbit.net";
|
|
|
|
if(!QCA::isSupported(QCA::CAP_TLS)) {
|
|
printf("TLS not supported!\n");
|
|
return 1;
|
|
}
|
|
|
|
SecureTest *s = new SecureTest;
|
|
QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
|
|
s->start(host);
|
|
app.exec();
|
|
delete s;
|
|
|
|
return 0;
|
|
}
|