examples!

svn path=/trunk/kdesupport/qca/; revision=251709
This commit is contained in:
Justin Karneges 2003-09-17 00:53:41 +00:00
parent 772c9ba704
commit 471671d4f8
18 changed files with 1641 additions and 0 deletions

View File

@ -0,0 +1,65 @@
#include<qdom.h>
#include<qfile.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(" 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());
}
int main()
{
if(!QCA::isSupported(QCA::CAP_X509)) {
printf("X509 not supported!\n");
return 1;
}
// open the Psi rootcerts file
QFile f("/usr/local/share/psi/certs/rootcert.xml");
if(!f.open(IO_ReadOnly)) {
printf("unable to open %s\n", f.name().latin1());
return 1;
}
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 1;
}
QDomNodeList cl = base.elementsByTagName("certificate");
if(cl.count() == 0) {
printf("no certs found in %s\n", f.name().latin1());
return 1;
}
for(int n = 0; n < (int)cl.count(); ++n) {
printf("-- Cert %d --\n", n);
QCA::Cert cert = readCertXml(cl.item(n).toElement());
if(cert.isNull()) {
printf("error reading cert\n");
continue;
}
showCertInfo(cert);
}
return 0;
}

View File

@ -0,0 +1,8 @@
TEMPLATE = app
CONFIG += thread
TARGET = certtest
INCLUDEPATH += ../common
HEADERS += ../common/base64.h
SOURCES += ../common/base64.cpp certtest.cpp
include(../examples.pri)

View File

@ -0,0 +1,89 @@
#include"qca.h"
#include<stdio.h>
static QCString arrayToCString(const QByteArray &);
static QByteArray cstringToArray(const QCString &);
static void doDynTest(QCA::Cipher *c, const QString &name, const QCString &cs);
int main(int argc, char **argv)
{
QCA::init();
QCString cs = (argc >= 2) ? argv[1] : "hello";
// AES128 test
if(!QCA::isSupported(QCA::CAP_AES128))
printf("AES128 not supported!\n");
else {
// encrypt
QByteArray key = QCA::AES128::generateKey();
QByteArray iv = QCA::AES128::generateIV();
printf("aes128:key:%s\n", QCA::arrayToHex(key).latin1());
printf("aes128:iv:%s\n", QCA::arrayToHex(iv).latin1());
QCA::AES128 c(QCA::Encrypt, QCA::CBC, key, iv);
c.update(cstringToArray(cs));
QByteArray f = c.final();
QString result = QCA::arrayToHex(f);
printf(">aes128(\"%s\") = [%s]\n", cs.data(), result.latin1());
// decrypt
QCA::AES128 d(QCA::Decrypt, QCA::CBC, key, iv);
d.update(f);
QCString dec = arrayToCString(d.final());
printf("<aes128(\"%s\") = [%s]\n", result.latin1(), dec.data());
}
// BlowFish, TripleDES, and AES256 tested dynamically
if(!QCA::isSupported(QCA::CAP_BlowFish))
printf("BlowFish not supported!\n");
else
doDynTest(new QCA::BlowFish, "bfish", cs);
if(!QCA::isSupported(QCA::CAP_TripleDES))
printf("TripleDES not supported!\n");
else
doDynTest(new QCA::TripleDES, "3des", cs);
if(!QCA::isSupported(QCA::CAP_AES256))
printf("AES256 not supported!\n");
else
doDynTest(new QCA::AES256, "aes256", cs);
return 0;
}
QCString arrayToCString(const QByteArray &a)
{
QCString cs;
cs.resize(a.size()+1);
memcpy(cs.data(), a.data(), a.size());
return cs;
}
QByteArray cstringToArray(const QCString &cs)
{
QByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
return a;
}
void doDynTest(QCA::Cipher *c, const QString &name, const QCString &cs)
{
// encrypt
QByteArray key = c->dyn_generateKey();
QByteArray iv = c->dyn_generateIV();
printf("%s:key:%s\n", name.latin1(), QCA::arrayToHex(key).latin1());
printf("%s:iv:%s\n", name.latin1(), QCA::arrayToHex(iv).latin1());
c->reset(QCA::Encrypt, QCA::CBC, key, iv);
c->update(cstringToArray(cs));
QByteArray f = c->final();
QString result = QCA::arrayToHex(f);
printf(">%s(\"%s\") = [%s]\n", name.latin1(), cs.data(), result.latin1());
// decrypt
c->reset(QCA::Decrypt, QCA::CBC, key, iv);
c->update(f);
QCString dec = arrayToCString(c->final());
printf("<%s(\"%s\") = [%s]\n", name.latin1(), result.latin1(), dec.data());
delete c;
}

View File

@ -0,0 +1,6 @@
TEMPLATE = app
CONFIG += thread
TARGET = ciphertest
SOURCES += ciphertest.cpp
include(../examples.pri)

173
examples/common/base64.cpp Normal file
View File

@ -0,0 +1,173 @@
/*
* base64.cpp - Base64 converting functions
* Copyright (C) 2003 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include"base64.h"
//! \class Base64 base64.h
//! \brief Base64 conversion functions.
//!
//! Converts Base64 data between arrays and strings.
//!
//! \code
//! #include "base64.h"
//!
//! ...
//!
//! // encode a block of data into base64
//! QByteArray block(1024);
//! QByteArray enc = Base64::encode(block);
//!
//! \endcode
//!
//! Encodes array \a s and returns the result.
QByteArray Base64::encode(const QByteArray &s)
{
int i;
int len = s.size();
char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
int a, b, c;
QByteArray p((len+2)/3*4);
int at = 0;
for( i = 0; i < len; i += 3 ) {
a = ((unsigned char)s[i] & 3) << 4;
if(i + 1 < len) {
a += (unsigned char)s[i + 1] >> 4;
b = ((unsigned char)s[i + 1] & 0xF) << 2;
if(i + 2 < len) {
b += (unsigned char)s[i + 2] >> 6;
c = (unsigned char)s[i + 2] & 0x3F;
}
else
c = 64;
}
else
b = c = 64;
p[at++] = tbl[(unsigned char)s[i] >> 2];
p[at++] = tbl[a];
p[at++] = tbl[b];
p[at++] = tbl[c];
}
return p;
}
//!
//! Decodes array \a s and returns the result.
QByteArray Base64::decode(const QByteArray &s)
{
// return value
QByteArray p;
// -1 specifies invalid
// 64 specifies eof
// everything else specifies data
char tbl[] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63,
52,53,54,55,56,57,58,59,60,61,-1,-1,-1,64,-1,-1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,
-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
};
// this should be a multiple of 4
int len = s.size();
if(len % 4)
return p;
p.resize(len / 4 * 3);
int i;
int at = 0;
int a, b, c, d;
c = d = 0;
for( i = 0; i < len; i += 4 ) {
a = tbl[(int)s[i]];
b = tbl[(int)s[i + 1]];
c = tbl[(int)s[i + 2]];
d = tbl[(int)s[i + 3]];
if((a == 64 || b == 64) || (a < 0 || b < 0 || c < 0 || d < 0)) {
p.resize(0);
return p;
}
p[at++] = ((a & 0x3F) << 2) | ((b >> 4) & 0x03);
p[at++] = ((b & 0x0F) << 4) | ((c >> 2) & 0x0F);
p[at++] = ((c & 0x03) << 6) | ((d >> 0) & 0x3F);
}
if(c & 64)
p.resize(at - 2);
else if(d & 64)
p.resize(at - 1);
return p;
}
//!
//! Encodes array \a a and returns the result as a string.
QString Base64::arrayToString(const QByteArray &a)
{
QByteArray b = encode(a);
QCString c;
c.resize(b.size()+1);
memcpy(c.data(), b.data(), b.size());
return QString::fromLatin1(c);
}
//!
//! Decodes string \a s and returns the result as an array.
QByteArray Base64::stringToArray(const QString &s)
{
if(s.isEmpty())
return QByteArray();
const char *c = s.latin1();
int len = strlen(c);
QByteArray b(len);
memcpy(b.data(), c, len);
QByteArray a = decode(b);
return a;
}
//!
//! Encodes string \a s and returns the result as a string.
QString Base64::encodeString(const QString &s)
{
QCString c = s.utf8();
int len = c.length();
QByteArray b(len);
memcpy(b.data(), c.data(), len);
return arrayToString(b);
}

36
examples/common/base64.h Normal file
View File

@ -0,0 +1,36 @@
/*
* base64.h - Base64 converting functions
* Copyright (C) 2003 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef CS_BASE64_H
#define CS_BASE64_H
#include<qstring.h>
class Base64
{
public:
static QByteArray encode(const QByteArray &);
static QByteArray decode(const QByteArray &);
static QString arrayToString(const QByteArray &);
static QByteArray stringToArray(const QString &);
static QString encodeString(const QString &);
};
#endif

6
examples/examples.pri Normal file
View File

@ -0,0 +1,6 @@
QCA_CPP = ../../src
INCLUDEPATH += $$QCA_CPP
HEADERS += $$QCA_CPP/qca.h $$QCA_CPP/qcaprovider.h
SOURCES += $$QCA_CPP/qca.cpp

11
examples/examples.pro Normal file
View File

@ -0,0 +1,11 @@
TEMPLATE = subdirs
SUBDIRS += \
hashtest \
ciphertest \
rsatest \
certtest \
ssltest \
sslservtest \
sasltest

View File

@ -0,0 +1,25 @@
#include"qca.h"
#include<stdio.h>
int main(int argc, char **argv)
{
QCA::init();
QCString cs = (argc >= 2) ? argv[1] : "hello";
if(!QCA::isSupported(QCA::CAP_SHA1))
printf("SHA1 not supported!\n");
else {
QString result = QCA::SHA1::hashToString(cs);
printf("sha1(\"%s\") = [%s]\n", cs.data(), result.latin1());
}
if(!QCA::isSupported(QCA::CAP_MD5))
printf("MD5 not supported!\n");
else {
QString result = QCA::MD5::hashToString(cs);
printf("md5(\"%s\") = [%s]\n", cs.data(), result.latin1());
}
return 0;
}

View File

@ -0,0 +1,6 @@
TEMPLATE = app
CONFIG += thread
TARGET = hashtest
SOURCES += hashtest.cpp
include(../examples.pri)

View File

@ -0,0 +1,86 @@
#include<qfile.h>
#include<qfileinfo.h>
#include"qca.h"
#include<stdio.h>
//#define USE_FILE
QCA::RSAKey readKeyFile(const QString &name)
{
QCA::RSAKey k;
QFile f(name);
if(!f.open(IO_ReadOnly)) {
printf("Unable to open %s\n", name.latin1());
return k;
}
QByteArray der = f.readAll();
f.close();
printf("Read %s [%d bytes]\n", name.latin1(), der.size());
if(!k.fromDER(der)) {
printf("%s: Error importing DER format.\n", name.latin1());
return k;
}
char *yes = "yes";
char *no = "no";
printf("Successfully imported %s (enc=%s, dec=%s)\n",
name.latin1(),
k.havePublic() ? yes : no,
k.havePrivate() ? yes : no);
printf("Converting to DER: %d bytes\n", k.toDER().size());
printf("Converting to PEM:\n%s\n", k.toPEM().latin1());
return k;
}
int main(int argc, char **argv)
{
QCA::init();
QCString cs = (argc >= 2) ? argv[1] : "hello";
if(!QCA::isSupported(QCA::CAP_RSA))
printf("RSA not supported!\n");
else {
#ifdef USE_FILE
QCA::RSAKey pubkey = readKeyFile("keypublic.der");
if(pubkey.isNull())
return 1;
QCA::RSAKey seckey = readKeyFile("keyprivate.der");
if(seckey.isNull())
return 1;
#else
QCA::RSAKey seckey = QCA::RSA::generateKey(1024);
if(seckey.isNull())
return 1;
QCA::RSAKey pubkey = seckey;
#endif
// encrypt some data
QByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
QCA::RSA op;
op.setKey(pubkey);
QByteArray result;
if(!op.encrypt(a, &result)) {
printf("Error encrypting.\n");
return 1;
}
QString rstr = QCA::arrayToHex(result);
printf(">rsa(\"%s\") = [%s]\n", cs.data(), rstr.latin1());
// now decrypt it
op.setKey(seckey);
QByteArray dec;
if(!op.decrypt(result, &dec)) {
printf("Error decrypting.\n");
return 1;
}
QCString dstr;
dstr.resize(dec.size()+1);
memcpy(dstr.data(), dec.data(), dec.size());
printf("<rsa(\"%s\") = [%s]\n", rstr.latin1(), dstr.data());
}
return 0;
}

View File

@ -0,0 +1,6 @@
TEMPLATE = app
CONFIG += thread
TARGET = rsatest
SOURCES += rsatest.cpp
include(../examples.pri)

View File

@ -0,0 +1,611 @@
#include<qapplication.h>
#include<qtimer.h>
#include<qsocket.h>
#include<qserversocket.h>
#include<stdio.h>
#include<unistd.h>
#include"base64.h"
#include"qca.h"
#define PROTO_NAME "foo"
#define PROTO_PORT 8001
static QString prompt(const QString &s)
{
printf("* %s ", s.latin1());
fflush(stdout);
char line[256];
fgets(line, 255, stdin);
QString result = line;
if(result[result.length()-1] == '\n')
result.truncate(result.length()-1);
return result;
}
class ClientTest : public QObject
{
Q_OBJECT
public:
ClientTest()
{
sock = new QSocket;
connect(sock, SIGNAL(connected()), SLOT(sock_connected()));
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
sasl = new QCA::SASL;
connect(sasl, SIGNAL(clientFirstStep(const QString &, const QByteArray *)), SLOT(sasl_clientFirstStep(const QString &, const QByteArray *)));
connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
connect(sasl, SIGNAL(needParams(bool, bool, bool, bool)), SLOT(sasl_needParams(bool, bool, bool, bool)));
connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
}
~ClientTest()
{
delete sock;
delete sasl;
}
void start(const QString &_host, int port, const QString &user="", const QString &pass="")
{
mode = 0;
host = _host;
sock->connectToHost(host, port);
sasl->setMinimumSSF(0);
sasl->setMaximumSSF(256);
if(!user.isEmpty()) {
sasl->setUsername(user);
sasl->setAuthzid(user);
}
if(!pass.isEmpty())
sasl->setPassword(pass);
}
signals:
void quit();
private slots:
void sock_connected()
{
printf("Connected to server. Awaiting mechanism list...\n");
}
void sock_connectionClosed()
{
printf("Connection closed by peer.\n");
quit();
}
void sock_error(int x)
{
QString s;
if(x == QSocket::ErrConnectionRefused)
s = "connection refused or timed out";
else if(x == QSocket::ErrHostNotFound)
s = "host not found";
else if(x == QSocket::ErrSocketRead)
s = "read error";
printf("Socket error: %s\n", s.latin1());
quit();
}
void sock_readyRead()
{
if(mode == 2) {
int avail = sock->bytesAvailable();
QByteArray a(avail);
int n = sock->readBlock(a.data(), a.size());
a.resize(n);
printf("Read %d bytes\n", a.size());
sasl->writeIncoming(a);
}
else {
if(sock->canReadLine()) {
QString line = sock->readLine();
line.truncate(line.length()-1); // chop the newline
handleLine(line);
}
}
}
void sasl_clientFirstStep(const QString &mech, const QByteArray *clientInit)
{
printf("Choosing mech: %s\n", mech.latin1());
QString line = mech;
if(clientInit) {
QCString cs(clientInit->data(), clientInit->size()+1);
line += ' ';
line += cs;
}
sendLine(line);
}
void sasl_nextStep(const QByteArray &stepData)
{
QCString cs(stepData.data(), stepData.size()+1);
QString line = "C";
if(!stepData.isEmpty()) {
line += ',';
line += cs;
}
sendLine(line);
}
void sasl_needParams(bool user, bool authzid, bool pass, bool realm)
{
QString username;
if(user || authzid)
username = prompt("Username:");
if(user) {
sasl->setUsername(username);
}
if(authzid) {
sasl->setAuthzid(username);
}
if(pass) {
sasl->setPassword(prompt("Password (not hidden!) :"));
}
if(realm) {
sasl->setRealm(prompt("Realm:"));
}
sasl->continueAfterParams();
}
void sasl_authenticated()
{
printf("SASL success!\n");
printf("SSF: %d\n", sasl->ssf());
}
void sasl_readyRead()
{
QByteArray a = sasl->read();
int oldsize = inbuf.size();
inbuf.resize(oldsize + a.size());
memcpy(inbuf.data() + oldsize, a.data(), a.size());
processInbuf();
}
void sasl_readyReadOutgoing()
{
QByteArray a = sasl->readOutgoing();
sock->writeBlock(a.data(), a.size());
}
void sasl_error(int)
{
printf("SASL error!\n");
quit();
return;
}
private:
QSocket *sock;
QCA::SASL *sasl;
int mode;
QString host;
QByteArray inbuf;
void processInbuf()
{
QStringList list;
for(int n = 0; n < (int)inbuf.size(); ++n) {
if(inbuf[n] == '\n') {
QCString cs(inbuf.data(), n+1);
char *p = inbuf.data();
++n;
int x = inbuf.size() - n;
memmove(p, p + n, x);
inbuf.resize(x);
list += QString::fromUtf8(cs);
// start over, basically
n = -1;
}
}
for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
handleLine(*it);
}
void handleLine(const QString &line)
{
printf("Reading: [%s]\n", line.latin1());
if(mode == 0) {
// first line is the method list
QStringList mechlist = QStringList::split(' ', line);
++mode;
// kick off the client
sasl->setAllowAnonymous(false);
if(!sasl->startClient(PROTO_NAME, host, mechlist)) {
printf("Error starting client!\n");
quit();
}
}
else if(mode == 1) {
QString type, rest;
int n = line.find(',');
if(n != -1) {
type = line.mid(0, n);
rest = line.mid(n+1);
}
else {
type = line;
rest = "";
}
if(type == "C") {
QCString cs = rest.latin1();
QByteArray buf(cs.length());
memcpy(buf.data(), cs.data(), buf.size());
sasl->putStep(buf);
}
else if(type == "E") {
printf("Authentication failed.\n");
quit();
return;
}
else if(type == "A") {
printf("Authentication success.\n");
++mode;
sock_readyRead(); // any extra data?
return;
}
else {
printf("Bad format from peer, closing.\n");
quit();
return;
}
}
else {
}
}
void sendLine(const QString &line)
{
printf("Writing: {%s}\n", line.latin1());
QString s = line + '\n';
QCString cs = s.latin1();
if(mode == 2) {
QByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
sasl->write(a);
}
else
sock->writeBlock(cs.data(), cs.length());
}
};
class ServerTest : public QServerSocket
{
Q_OBJECT
public:
ServerTest(const QString &_str, int _port) : QServerSocket(_port), port(_port)
{
sock = 0;
sasl = 0;
realm = QString::null;
str = _str;
}
~ServerTest()
{
delete sock;
delete sasl;
}
void start()
{
if(!ok()) {
printf("Error binding to port %d!\n", port);
QTimer::singleShot(0, this, SIGNAL(quit()));
return;
}
char myhostname[256];
int r = gethostname(myhostname, sizeof(myhostname)-1);
if(r == -1) {
printf("Error getting hostname!\n");
QTimer::singleShot(0, this, SIGNAL(quit()));
return;
}
host = myhostname;
printf("Listening on %s:%d ...\n", host.latin1(), port);
}
void newConnection(int s)
{
// Note: only 1 connection supported at a time in this example!
if(sock) {
QSocket tmp;
tmp.setSocket(s);
printf("Connection ignored, already have one active.\n");
return;
}
printf("Connection received! Starting SASL handshake...\n");
sock = new QSocket;
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
sasl = new QCA::SASL;
connect(sasl, SIGNAL(authCheck(const QString &, const QString &)), SLOT(sasl_authCheck(const QString &, const QString &)));
connect(sasl, SIGNAL(nextStep(const QByteArray &)), SLOT(sasl_nextStep(const QByteArray &)));
connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
connect(sasl, SIGNAL(readyReadOutgoing()), SLOT(sasl_readyReadOutgoing()));
connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
sock->setSocket(s);
mode = 0;
inbuf.resize(0);
sasl->setMinimumSSF(0);
sasl->setMaximumSSF(256);
QStringList mechlist;
if(!sasl->startServer(PROTO_NAME, host, realm, &mechlist)) {
printf("Error starting server!\n");
quit();
}
QString str;
bool first = true;
for(QStringList::ConstIterator it = mechlist.begin(); it != mechlist.end(); ++it) {
if(!first)
str += ' ';
str += *it;
first = false;
}
sendLine(str);
}
signals:
void quit();
private slots:
void sock_connectionClosed()
{
printf("Connection closed by peer.\n");
close();
}
void sock_error(int x)
{
QString s;
if(x == QSocket::ErrConnectionRefused)
s = "connection refused or timed out";
else if(x == QSocket::ErrHostNotFound)
s = "host not found";
else if(x == QSocket::ErrSocketRead)
s = "read error";
printf("Socket error: %s\n", s.latin1());
close();
}
void sock_readyRead()
{
if(sock->canReadLine()) {
QString line = sock->readLine();
line.truncate(line.length()-1); // chop the newline
handleLine(line);
}
}
void sock_bytesWritten(int x)
{
if(mode == 2) {
toWrite -= x;
if(toWrite <= 0) {
printf("Sent, closing.\n");
close();
}
}
}
void sasl_nextStep(const QByteArray &stepData)
{
QCString cs(stepData.data(), stepData.size()+1);
QString line = "C";
if(!stepData.isEmpty()) {
line += ',';
line += cs;
}
sendLine(line);
}
void sasl_authCheck(const QString &user, const QString &authzid)
{
printf("AuthCheck: User: [%s], Authzid: [%s]\n", user.latin1(), authzid.latin1());
sasl->continueAfterAuthCheck();
}
void sasl_authenticated()
{
sendLine("A");
printf("Authentication success.\n");
++mode;
printf("SSF: %d\n", sasl->ssf());
sendLine(str);
}
void sasl_readyRead()
{
QByteArray a = sasl->read();
int oldsize = inbuf.size();
inbuf.resize(oldsize + a.size());
memcpy(inbuf.data() + oldsize, a.data(), a.size());
processInbuf();
}
void sasl_readyReadOutgoing()
{
QByteArray a = sasl->readOutgoing();
toWrite = a.size();
sock->writeBlock(a.data(), a.size());
}
void sasl_error(int x)
{
if(x == QCA::SASL::ErrAuth) {
sendLine("E");
printf("Authentication failed.\n");
close();
}
else {
printf("SASL security layer error!\n");
close();
}
}
private:
QSocket *sock;
QCA::SASL *sasl;
QString host, realm;
int port;
int mode;
QString str;
QByteArray inbuf;
int toWrite;
void processInbuf()
{
}
void handleLine(const QString &line)
{
printf("Reading: [%s]\n", line.latin1());
if(mode == 0) {
int n = line.find(' ');
if(n != -1) {
QString mech = line.mid(0, n);
QCString cs = line.mid(n+1).latin1();
QByteArray clientInit(cs.length());
memcpy(clientInit.data(), cs.data(), clientInit.size());
sasl->putServerFirstStep(mech, clientInit);
}
else
sasl->putServerFirstStep(line);
++mode;
}
else if(mode == 1) {
QString type, rest;
int n = line.find(',');
if(n != -1) {
type = line.mid(0, n);
rest = line.mid(n+1);
}
else {
type = line;
rest = "";
}
if(type == "C") {
QCString cs = rest.latin1();
QByteArray buf(cs.length());
memcpy(buf.data(), cs.data(), buf.size());
sasl->putStep(buf);
}
else {
printf("Bad format from peer, closing.\n");
close();
return;
}
}
}
void sendLine(const QString &line)
{
printf("Writing: {%s}\n", line.latin1());
QString s = line + '\n';
QCString cs = s.latin1();
if(mode == 2) {
QByteArray a(cs.length());
memcpy(a.data(), cs.data(), a.size());
sasl->write(a);
}
else
sock->writeBlock(cs.data(), cs.length());
}
void close()
{
sock->deleteLater();
sock = 0;
delete sasl;
sasl = 0;
}
};
#include"sasltest.moc"
void usage()
{
printf("usage: sasltest client [host] [user] [pass]\n");
printf(" sasltest server [string]\n\n");
}
int main(int argc, char **argv)
{
QApplication app(argc, argv, false);
QString host, user, pass;
QString str = "Hello, World";
bool server;
if(argc < 2) {
usage();
return 0;
}
QString arg = argv[1];
if(arg == "client") {
if(argc < 3) {
usage();
return 0;
}
host = argv[2];
if(argc >= 4)
user = argv[3];
if(argc >= 5)
pass = argv[4];
server = false;
}
else if(arg == "server") {
if(argc >= 3)
str = argv[2];
server = true;
}
else {
usage();
return 0;
}
if(!QCA::isSupported(QCA::CAP_SASL)) {
printf("SASL not supported!\n");
return 1;
}
if(server) {
ServerTest *s = new ServerTest(str, PROTO_PORT);
QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
s->start();
app.exec();
delete s;
}
else {
ClientTest *c = new ClientTest;
QObject::connect(c, SIGNAL(quit()), &app, SLOT(quit()));
c->start(host, PROTO_PORT, user, pass);
app.exec();
delete c;
}
return 0;
}

View File

@ -0,0 +1,8 @@
TEMPLATE = app
CONFIG += thread
TARGET = sasltest
INCLUDEPATH += ../common
HEADERS += ../common/base64.h
SOURCES += ../common/base64.cpp sasltest.cpp
include(../examples.pri)

View File

@ -0,0 +1,221 @@
#include<qapplication.h>
#include<qfile.h>
#include<qsocket.h>
#include<qserversocket.h>
#include<qtimer.h>
#include"qca.h"
char pemdata_cert[] =
"-----BEGIN CERTIFICATE-----\n"
"MIIDbjCCAtegAwIBAgIBADANBgkqhkiG9w0BAQQFADCBhzELMAkGA1UEBhMCVVMx\n"
"EzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNVBAcTBklydmluZTEYMBYGA1UEChMP\n"
"RXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtleGFtcGxlLmNvbTEiMCAGCSqGSIb3\n"
"DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbTAeFw0wMzA3MjQwNzMwMDBaFw0wMzA4\n"
"MjMwNzMwMDBaMIGHMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEP\n"
"MA0GA1UEBxMGSXJ2aW5lMRgwFgYDVQQKEw9FeGFtcGxlIENvbXBhbnkxFDASBgNV\n"
"BAMTC2V4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNleGFtcGxlQGV4YW1wbGUu\n"
"Y29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCobzCF268K2sRp473gvBTT\n"
"4AgSL1kjeF8N57vxS1P8zWrWMXNs4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwW\n"
"WZToesxebu3m9VeA8dqWyOaUMjoxAcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8m\n"
"a+AAPByfTORbzpSTmXAQAwIDAQABo4HnMIHkMB0GA1UdDgQWBBTvFierzLmmYMq0\n"
"cB/+5rK1bNR56zCBtAYDVR0jBIGsMIGpgBTvFierzLmmYMq0cB/+5rK1bNR566GB\n"
"jaSBijCBhzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDzANBgNV\n"
"BAcTBklydmluZTEYMBYGA1UEChMPRXhhbXBsZSBDb21wYW55MRQwEgYDVQQDEwtl\n"
"eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZXhhbXBsZUBleGFtcGxlLmNvbYIB\n"
"ADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBAUAA4GBAGqGhXf7xNOnYNtFO7gz\n"
"K6RdZGHFI5q1DAEz4hhNBC9uElh32XGX4wN7giz3zLC8v9icL/W4ff/K5NDfv3Gf\n"
"gQe/+Wo9Be3H3ul6uwPPFnx4+PIOF2a5TW99H9smyxWdNjnFtcUte4al3RszcMWG\n"
"x3iqsWosGtj6F+ridmKoqKLu\n"
"-----END CERTIFICATE-----\n";
char pemdata_privkey[] =
"-----BEGIN RSA PRIVATE KEY-----\n"
"MIICXAIBAAKBgQCobzCF268K2sRp473gvBTT4AgSL1kjeF8N57vxS1P8zWrWMXNs\n"
"4LuH0NRZmKTajeboy0br8xw+smIy3AbaKAwWWZToesxebu3m9VeA8dqWyOaUMjox\n"
"AcgVYesgVaMpjRe7fcWdJnX1wJoVVPuIcO8ma+AAPByfTORbzpSTmXAQAwIDAQAB\n"
"AoGAP83u+aYghuIcaWhmM03MLf69z/WztKYSi/fu0BcS977w67bL3MC9CVPoPRB/\n"
"0nLSt/jZIuRzHKUCYfXLerSU7v0oXDTy6GPzWMh/oXIrpF0tYNbwWF7LSq2O2gGZ\n"
"XtA9MSmUNNJaKzQQeXjqdVFOY8A0Pho+k2KByBiCi+ChkcECQQDRUuyX0+PKJtA2\n"
"M36BOTFpy61BAv+JRlXUnHuevOfQWl6NR6YGygqCyH1sWtP1sa9S4wWys3DFH+5A\n"
"DkuAqk7zAkEAzf4eUH2hp5CIMsXH+WpIzKj09oY1it2CAKjVq4rUELf8iXvmGoFl\n"
"000spua4MjHNUYm7LR0QaKesKrMyGZUesQJAL8aLdYPJI+SD9Tr/jqLtIkZ4frQe\n"
"eshw4pvsoyheiHF3zyshO791crAr4EVCx3sMlxB1xnmqLXPCPyCEHxO//QJBAIBY\n"
"IYkjDZJ6ofGIe1UyXJNvfdkPu9J+ut4wU5jjEcgs6mK62J6RGuFxhy2iOQfFMdjo\n"
"yL+OCUg7mDCun7uCxrECQAtSvnLOFMjO5qExRjFtwi+b1rcSekd3Osk/izyRFSzg\n"
"Or+AL56/EKfiogNnFipgaXIbb/xj785Cob6v96XoW1I=\n"
"-----END RSA PRIVATE KEY-----\n";
class SecureServerTest : public QServerSocket
{
Q_OBJECT
public:
SecureServerTest(int _port) : QServerSocket(_port), port(_port)
{
sock = new QSocket;
connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
connect(sock, SIGNAL(error(int)), SLOT(sock_error(int)));
connect(sock, SIGNAL(bytesWritten(int)), SLOT(sock_bytesWritten(int)));
ssl = new QCA::TLS;
connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
connect(ssl, SIGNAL(readyReadOutgoing()), SLOT(ssl_readyReadOutgoing()));
connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int)));
cert.fromPEM(pemdata_cert);
privkey.fromPEM(pemdata_privkey);
fin_mode = 0;
}
~SecureServerTest()
{
delete ssl;
delete sock;
}
void start()
{
if(cert.isNull() || privkey.isNull()) {
printf("Error loading cert and/or private key!\n");
QTimer::singleShot(0, this, SIGNAL(quit()));
return;
}
if(!ok()) {
printf("Error binding to port %d!\n", port);
QTimer::singleShot(0, this, SIGNAL(quit()));
return;
}
printf("Listening on port %d ...\n", port);
}
void newConnection(int s)
{
// Note: only 1 connection supported at a time in this example!
if(sock->isOpen()) {
QSocket tmp;
tmp.setSocket(s);
printf("throwing away extra connection\n");
return;
}
sock->setSocket(s);
printf("Connection received! Starting TLS handshake...\n");
ssl->setCertificate(cert, privkey);
ssl->startServer();
}
signals:
void quit();
private slots:
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("Connection closed.\n");
}
void sock_bytesWritten(int x)
{
if(fin_mode == 2) {
fin_bytes -= x;
// last of the bytes written that we care about?
if(fin_bytes == 0) {
printf("Closing.\n");
sock->close();
fin_mode = 0;
}
}
}
void sock_error(int)
{
printf("Socket error.\n");
}
void ssl_handshaken()
{
printf("Successful SSL handshake. Waiting for newline.\n");
}
void ssl_readyRead()
{
QByteArray a = ssl->read();
QString str =
"<html>\n"
"<head><title>Test</title></head>\n"
"<body>this is only a test</body>\n"
"</html>\n";
QCString cs = str.latin1();
QByteArray b(cs.length());
memcpy(b.data(), cs.data(), b.size());
printf("Sending test response...\n");
fin_mode = 1; // we want to shut down after this block is written
ssl->write(b);
}
void ssl_readyReadOutgoing()
{
QByteArray a = ssl->readOutgoing();
// The readyReadOutgoing signal following a write will have ALL written data encrypted,
// so to ensure data is sent, just ensure the whole encrypted data is sent.
if(fin_mode == 1) {
fin_bytes = a.size(); // we want to make sure all of it is sent
fin_mode = 2;
}
sock->writeBlock(a.data(), a.size());
}
void ssl_error(int x)
{
if(x == QCA::TLS::ErrHandshake) {
printf("SSL Handshake Error! Closing.\n");
sock->close();
}
else {
printf("SSL Error! Closing.\n");
sock->close();
}
}
private:
int port;
QSocket *sock;
QCA::TLS *ssl;
QCA::Cert cert;
QCA::RSAKey privkey;
int fin_mode;
int fin_bytes;
};
#include"sslservtest.moc"
int main(int argc, char **argv)
{
QApplication app(argc, argv, false);
int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
if(!QCA::isSupported(QCA::CAP_TLS)) {
printf("TLS not supported!\n");
return 1;
}
SecureServerTest *s = new SecureServerTest(port);
QObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
s->start();
app.exec();
delete s;
return 0;
}

View File

@ -0,0 +1,6 @@
TEMPLATE = app
CONFIG += thread
TARGET = sslservtest
SOURCES += sslservtest.cpp
include(../examples.pri)

View File

@ -0,0 +1,270 @@
#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()), SLOT(ssl_readyReadOutgoing()));
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()
{
QByteArray a = ssl->readOutgoing();
sock->writeBlock(a.data(), a.size());
}
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;
}

View File

@ -0,0 +1,8 @@
TEMPLATE = app
CONFIG += thread
TARGET = ssltest
INCLUDEPATH += ../common
HEADERS += ../common/base64.h
SOURCES += ../common/base64.cpp ssltest.cpp
include(../examples.pri)