summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorDarrell Anderson <humanreadable@yahoo.com>2012-04-17 19:51:44 -0500
committerDarrell Anderson <humanreadable@yahoo.com>2012-04-17 19:51:44 -0500
commitc663e43e7172bb80a8fb779e4dc74f579a60ec45 (patch)
treefd72db9c80e6c1aacf67e8bd24f75a4da57c4a2e /examples
downloadtqca-c663e43e7172bb80a8fb779e4dc74f579a60ec45.tar.gz
tqca-c663e43e7172bb80a8fb779e4dc74f579a60ec45.zip
Added tqca package to the sources tree. This module is from
the original qca-1.0 sources with the TQt layer added. This resolves bug report 817.
Diffstat (limited to 'examples')
-rw-r--r--examples/certtest/certtest.cpp65
-rw-r--r--examples/certtest/certtest.pro8
-rw-r--r--examples/ciphertest/ciphertest.cpp89
-rw-r--r--examples/ciphertest/ciphertest.pro6
-rw-r--r--examples/common/base64.cpp173
-rw-r--r--examples/common/base64.h36
-rw-r--r--examples/examples.pri7
-rw-r--r--examples/examples.pro11
-rw-r--r--examples/hashtest/hashtest.cpp25
-rw-r--r--examples/hashtest/hashtest.pro6
-rw-r--r--examples/rsatest/rsatest.cpp86
-rw-r--r--examples/rsatest/rsatest.pro6
-rw-r--r--examples/sasltest/sasltest.cpp615
-rw-r--r--examples/sasltest/sasltest.pro8
-rw-r--r--examples/sslservtest/sslservtest.cpp294
-rw-r--r--examples/sslservtest/sslservtest.pro6
-rw-r--r--examples/ssltest/ssltest.cpp276
-rw-r--r--examples/ssltest/ssltest.pro8
18 files changed, 1725 insertions, 0 deletions
diff --git a/examples/certtest/certtest.cpp b/examples/certtest/certtest.cpp
new file mode 100644
index 0000000..db82993
--- /dev/null
+++ b/examples/certtest/certtest.cpp
@@ -0,0 +1,65 @@
+#include<tqdom.h>
+#include<tqfile.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(" 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(!TQCA::isSupported(TQCA::CAP_X509)) {
+ printf("X509 not supported!\n");
+ return 1;
+ }
+
+ // open the Psi rootcerts file
+ TQFile f("/usr/local/share/psi/certs/rootcert.xml");
+ if(!f.open(IO_ReadOnly)) {
+ printf("unable to open %s\n", f.name().latin1());
+ return 1;
+ }
+ 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 1;
+ }
+ TQDomNodeList 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);
+ TQCA::Cert cert = readCertXml(cl.item(n).toElement());
+ if(cert.isNull()) {
+ printf("error reading cert\n");
+ continue;
+ }
+ showCertInfo(cert);
+ }
+
+ return 0;
+}
+
diff --git a/examples/certtest/certtest.pro b/examples/certtest/certtest.pro
new file mode 100644
index 0000000..75d4141
--- /dev/null
+++ b/examples/certtest/certtest.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = certtest
+
+INCLUDEPATH += ../common
+HEADERS += ../common/base64.h
+SOURCES += ../common/base64.cpp certtest.cpp
+include(../examples.pri)
diff --git a/examples/ciphertest/ciphertest.cpp b/examples/ciphertest/ciphertest.cpp
new file mode 100644
index 0000000..3f2107e
--- /dev/null
+++ b/examples/ciphertest/ciphertest.cpp
@@ -0,0 +1,89 @@
+#include"qca.h"
+#include<stdio.h>
+
+static TQCString arrayToCString(const TQByteArray &);
+static TQByteArray cstringToArray(const TQCString &);
+static void doDynTest(TQCA::Cipher *c, const TQString &name, const TQCString &cs);
+
+int main(int argc, char **argv)
+{
+ TQCA::init();
+ TQCString cs = (argc >= 2) ? argv[1] : "hello";
+
+ // AES128 test
+ if(!TQCA::isSupported(TQCA::CAP_AES128))
+ printf("AES128 not supported!\n");
+ else {
+ // encrypt
+ TQByteArray key = TQCA::AES128::generateKey();
+ TQByteArray iv = TQCA::AES128::generateIV();
+ printf("aes128:key:%s\n", TQCA::arrayToHex(key).latin1());
+ printf("aes128:iv:%s\n", TQCA::arrayToHex(iv).latin1());
+ TQCA::AES128 c(TQCA::Encrypt, TQCA::CBC, key, iv);
+ c.update(cstringToArray(cs));
+ TQByteArray f = c.final();
+ TQString result = TQCA::arrayToHex(f);
+ printf(">aes128(\"%s\") = [%s]\n", cs.data(), result.latin1());
+
+ // decrypt
+ TQCA::AES128 d(TQCA::Decrypt, TQCA::CBC, key, iv);
+ d.update(f);
+ TQCString dec = arrayToCString(d.final());
+ printf("<aes128(\"%s\") = [%s]\n", result.latin1(), dec.data());
+ }
+
+ // BlowFish, TripleDES, and AES256 tested dynamically
+ if(!TQCA::isSupported(TQCA::CAP_BlowFish))
+ printf("BlowFish not supported!\n");
+ else
+ doDynTest(new TQCA::BlowFish, "bfish", cs);
+
+ if(!TQCA::isSupported(TQCA::CAP_TripleDES))
+ printf("TripleDES not supported!\n");
+ else
+ doDynTest(new TQCA::TripleDES, "3des", cs);
+
+ if(!TQCA::isSupported(TQCA::CAP_AES256))
+ printf("AES256 not supported!\n");
+ else
+ doDynTest(new TQCA::AES256, "aes256", cs);
+
+ return 0;
+}
+
+TQCString arrayToCString(const TQByteArray &a)
+{
+ TQCString cs;
+ cs.resize(a.size()+1);
+ memcpy(cs.data(), a.data(), a.size());
+ return cs;
+}
+
+TQByteArray cstringToArray(const TQCString &cs)
+{
+ TQByteArray a(cs.length());
+ memcpy(a.data(), cs.data(), a.size());
+ return a;
+}
+
+void doDynTest(TQCA::Cipher *c, const TQString &name, const TQCString &cs)
+{
+ // encrypt
+ TQByteArray key = c->dyn_generateKey();
+ TQByteArray iv = c->dyn_generateIV();
+ printf("%s:key:%s\n", name.latin1(), TQCA::arrayToHex(key).latin1());
+ printf("%s:iv:%s\n", name.latin1(), TQCA::arrayToHex(iv).latin1());
+ c->reset(TQCA::Encrypt, TQCA::CBC, key, iv);
+ c->update(cstringToArray(cs));
+ TQByteArray f = c->final();
+ TQString result = TQCA::arrayToHex(f);
+ printf(">%s(\"%s\") = [%s]\n", name.latin1(), cs.data(), result.latin1());
+
+ // decrypt
+ c->reset(TQCA::Decrypt, TQCA::CBC, key, iv);
+ c->update(f);
+ TQCString dec = arrayToCString(c->final());
+ printf("<%s(\"%s\") = [%s]\n", name.latin1(), result.latin1(), dec.data());
+ delete c;
+}
+
diff --git a/examples/ciphertest/ciphertest.pro b/examples/ciphertest/ciphertest.pro
new file mode 100644
index 0000000..c4119c5
--- /dev/null
+++ b/examples/ciphertest/ciphertest.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = ciphertest
+
+SOURCES += ciphertest.cpp
+include(../examples.pri)
diff --git a/examples/common/base64.cpp b/examples/common/base64.cpp
new file mode 100644
index 0000000..5938680
--- /dev/null
+++ b/examples/common/base64.cpp
@@ -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
+//! TQByteArray block(1024);
+//! TQByteArray enc = Base64::encode(block);
+//!
+//! \endcode
+
+//!
+//! Encodes array \a s and returns the result.
+TQByteArray Base64::encode(const TQByteArray &s)
+{
+ int i;
+ int len = s.size();
+ char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+ int a, b, c;
+
+ TQByteArray 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.
+TQByteArray Base64::decode(const TQByteArray &s)
+{
+ // return value
+ TQByteArray 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.
+TQString Base64::arrayToString(const TQByteArray &a)
+{
+ TQByteArray b = encode(a);
+ TQCString c;
+ c.resize(b.size()+1);
+ memcpy(c.data(), b.data(), b.size());
+ return TQString::fromLatin1(c);
+}
+
+//!
+//! Decodes string \a s and returns the result as an array.
+TQByteArray Base64::stringToArray(const TQString &s)
+{
+ if(s.isEmpty())
+ return TQByteArray();
+ const char *c = s.latin1();
+ int len = strlen(c);
+ TQByteArray b(len);
+ memcpy(b.data(), c, len);
+ TQByteArray a = decode(b);
+ return a;
+}
+
+//!
+//! Encodes string \a s and returns the result as a string.
+TQString Base64::encodeString(const TQString &s)
+{
+ TQCString c = s.utf8();
+ int len = c.length();
+ TQByteArray b(len);
+ memcpy(b.data(), c.data(), len);
+ return arrayToString(b);
+}
diff --git a/examples/common/base64.h b/examples/common/base64.h
new file mode 100644
index 0000000..93c6023
--- /dev/null
+++ b/examples/common/base64.h
@@ -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 TQByteArray encode(const TQByteArray &);
+ static TQByteArray decode(const TQByteArray &);
+ static TQString arrayToString(const TQByteArray &);
+ static TQByteArray stringToArray(const TQString &);
+ static TQString encodeString(const TQString &);
+};
+
+#endif
diff --git a/examples/examples.pri b/examples/examples.pri
new file mode 100644
index 0000000..b1c4f91
--- /dev/null
+++ b/examples/examples.pri
@@ -0,0 +1,7 @@
+# change/remove these entries, depending on the installation prefix
+INCLUDEPATH += /usr/local/include
+LIBS += -L/usr/local/lib
+
+# link
+LIBS += -lqca
+
diff --git a/examples/examples.pro b/examples/examples.pro
new file mode 100644
index 0000000..457b282
--- /dev/null
+++ b/examples/examples.pro
@@ -0,0 +1,11 @@
+TEMPLATE = subdirs
+
+SUBDIRS += \
+ hashtest \
+ ciphertest \
+ rsatest \
+ certtest \
+ ssltest \
+ sslservtest \
+ sasltest
+
diff --git a/examples/hashtest/hashtest.cpp b/examples/hashtest/hashtest.cpp
new file mode 100644
index 0000000..917c396
--- /dev/null
+++ b/examples/hashtest/hashtest.cpp
@@ -0,0 +1,25 @@
+#include"qca.h"
+#include<stdio.h>
+
+int main(int argc, char **argv)
+{
+ TQCA::init();
+ TQCString cs = (argc >= 2) ? argv[1] : "hello";
+
+ if(!TQCA::isSupported(TQCA::CAP_SHA1))
+ printf("SHA1 not supported!\n");
+ else {
+ TQString result = TQCA::SHA1::hashToString(cs);
+ printf("sha1(\"%s\") = [%s]\n", cs.data(), result.latin1());
+ }
+
+ if(!TQCA::isSupported(TQCA::CAP_MD5))
+ printf("MD5 not supported!\n");
+ else {
+ TQString result = TQCA::MD5::hashToString(cs);
+ printf("md5(\"%s\") = [%s]\n", cs.data(), result.latin1());
+ }
+
+ return 0;
+}
+
diff --git a/examples/hashtest/hashtest.pro b/examples/hashtest/hashtest.pro
new file mode 100644
index 0000000..d642131
--- /dev/null
+++ b/examples/hashtest/hashtest.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = hashtest
+
+SOURCES += hashtest.cpp
+include(../examples.pri)
diff --git a/examples/rsatest/rsatest.cpp b/examples/rsatest/rsatest.cpp
new file mode 100644
index 0000000..bd513fd
--- /dev/null
+++ b/examples/rsatest/rsatest.cpp
@@ -0,0 +1,86 @@
+#include<tqfile.h>
+#include<tqfileinfo.h>
+#include"qca.h"
+#include<stdio.h>
+
+//#define USE_FILE
+
+TQCA::RSAKey readKeyFile(const TQString &name)
+{
+ TQCA::RSAKey k;
+ TQFile f(name);
+ if(!f.open(IO_ReadOnly)) {
+ printf("Unable to open %s\n", name.latin1());
+ return k;
+ }
+ TQByteArray 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)
+{
+ TQCA::init();
+ TQCString cs = (argc >= 2) ? argv[1] : "hello";
+
+ if(!TQCA::isSupported(TQCA::CAP_RSA))
+ printf("RSA not supported!\n");
+ else {
+#ifdef USE_FILE
+ TQCA::RSAKey pubkey = readKeyFile("keypublic.der");
+ if(pubkey.isNull())
+ return 1;
+ TQCA::RSAKey seckey = readKeyFile("keyprivate.der");
+ if(seckey.isNull())
+ return 1;
+#else
+ TQCA::RSAKey seckey = TQCA::RSA::generateKey(1024);
+ if(seckey.isNull())
+ return 1;
+ TQCA::RSAKey pubkey = seckey;
+#endif
+ // encrypt some data
+ TQByteArray a(cs.length());
+ memcpy(a.data(), cs.data(), a.size());
+
+ TQCA::RSA op;
+ op.setKey(pubkey);
+ TQByteArray result;
+ if(!op.encrypt(a, &result)) {
+ printf("Error encrypting.\n");
+ return 1;
+ }
+ TQString rstr = TQCA::arrayToHex(result);
+ printf(">rsa(\"%s\") = [%s]\n", cs.data(), rstr.latin1());
+
+ // now decrypt it
+ op.setKey(seckey);
+ TQByteArray dec;
+ if(!op.decrypt(result, &dec)) {
+ printf("Error decrypting.\n");
+ return 1;
+ }
+ TQCString dstr;
+ dstr.resize(dec.size()+1);
+ memcpy(dstr.data(), dec.data(), dec.size());
+ printf("<rsa(\"%s\") = [%s]\n", rstr.latin1(), dstr.data());
+ }
+
+ return 0;
+}
+
diff --git a/examples/rsatest/rsatest.pro b/examples/rsatest/rsatest.pro
new file mode 100644
index 0000000..fc293ad
--- /dev/null
+++ b/examples/rsatest/rsatest.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = rsatest
+
+SOURCES += rsatest.cpp
+include(../examples.pri)
diff --git a/examples/sasltest/sasltest.cpp b/examples/sasltest/sasltest.cpp
new file mode 100644
index 0000000..dd4f858
--- /dev/null
+++ b/examples/sasltest/sasltest.cpp
@@ -0,0 +1,615 @@
+#include<tqapplication.h>
+#include<tqtimer.h>
+#include<tqsocket.h>
+#include<tqserversocket.h>
+#include<stdio.h>
+
+#ifdef Q_OS_UNIX
+#include<unistd.h>
+#endif
+
+#include"base64.h"
+#include"qca.h"
+
+#define PROTO_NAME "foo"
+#define PROTO_PORT 8001
+
+static TQString prompt(const TQString &s)
+{
+ printf("* %s ", s.latin1());
+ fflush(stdout);
+ char line[256];
+ fgets(line, 255, stdin);
+ TQString result = line;
+ if(result[result.length()-1] == '\n')
+ result.truncate(result.length()-1);
+ return result;
+}
+
+class ClientTest : public TQObject
+{
+ Q_OBJECT
+public:
+ ClientTest()
+ {
+ sock = new TQSocket;
+ 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 TQString &, const TQByteArray *)), SLOT(sasl_clientFirstStep(const TQString &, const TQByteArray *)));
+ connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &)));
+ 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(int)), SLOT(sasl_readyReadOutgoing(int)));
+ connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
+ }
+
+ ~ClientTest()
+ {
+ delete sock;
+ delete sasl;
+ }
+
+ void start(const TQString &_host, int port, const TQString &user="", const TQString &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)
+ {
+ TQString s;
+ if(x == TQSocket::ErrConnectionRefused)
+ s = "connection refused or timed out";
+ else if(x == TQSocket::ErrHostNotFound)
+ s = "host not found";
+ else if(x == TQSocket::ErrSocketRead)
+ s = "read error";
+
+ printf("Socket error: %s\n", s.latin1());
+ quit();
+ }
+
+ void sock_readyRead()
+ {
+ if(mode == 2) {
+ int avail = sock->bytesAvailable();
+ TQByteArray 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()) {
+ TQString line = sock->readLine();
+ line.truncate(line.length()-1); // chop the newline
+ handleLine(line);
+ }
+ }
+ }
+
+ void sasl_clientFirstStep(const TQString &mech, const TQByteArray *clientInit)
+ {
+ printf("Choosing mech: %s\n", mech.latin1());
+ TQString line = mech;
+ if(clientInit) {
+ TQCString cs(clientInit->data(), clientInit->size()+1);
+ line += ' ';
+ line += cs;
+ }
+ sendLine(line);
+ }
+
+ void sasl_nextStep(const TQByteArray &stepData)
+ {
+ TQCString cs(stepData.data(), stepData.size()+1);
+ TQString line = "C";
+ if(!stepData.isEmpty()) {
+ line += ',';
+ line += cs;
+ }
+ sendLine(line);
+ }
+
+ void sasl_needParams(bool user, bool authzid, bool pass, bool realm)
+ {
+ TQString 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()
+ {
+ TQByteArray a = sasl->read();
+ int oldsize = inbuf.size();
+ inbuf.resize(oldsize + a.size());
+ memcpy(inbuf.data() + oldsize, a.data(), a.size());
+ processInbuf();
+ }
+
+ void sasl_readyReadOutgoing(int)
+ {
+ TQByteArray a = sasl->readOutgoing();
+ sock->writeBlock(a.data(), a.size());
+ }
+
+ void sasl_error(int)
+ {
+ printf("SASL error!\n");
+ quit();
+ return;
+ }
+
+private:
+ TQSocket *sock;
+ QCA::SASL *sasl;
+ int mode;
+ TQString host;
+ TQByteArray inbuf;
+
+ void processInbuf()
+ {
+ TQStringList list;
+ for(int n = 0; n < (int)inbuf.size(); ++n) {
+ if(inbuf[n] == '\n') {
+ TQCString cs(inbuf.data(), n+1);
+ char *p = inbuf.data();
+ ++n;
+ int x = inbuf.size() - n;
+ memmove(p, p + n, x);
+ inbuf.resize(x);
+ list += TQString::fromUtf8(cs);
+ // start over, basically
+ n = -1;
+ }
+ }
+
+ for(TQStringList::ConstIterator it = list.begin(); it != list.end(); ++it)
+ handleLine(*it);
+ }
+
+ void handleLine(const TQString &line)
+ {
+ printf("Reading: [%s]\n", line.latin1());
+ if(mode == 0) {
+ // first line is the method list
+ TQStringList mechlist = TQStringList::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) {
+ TQString 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") {
+ TQCString cs = rest.latin1();
+ TQByteArray 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 TQString &line)
+ {
+ printf("Writing: {%s}\n", line.latin1());
+ TQString s = line + '\n';
+ TQCString cs = s.latin1();
+ if(mode == 2) {
+ TQByteArray 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 TQString &_str, int _port) : QServerSocket(_port), port(_port)
+ {
+ sock = 0;
+ sasl = 0;
+ realm = TQString::null;
+ str = _str;
+ }
+
+ ~ServerTest()
+ {
+ delete sock;
+ delete sasl;
+ }
+
+ void start()
+ {
+ if(!ok()) {
+ printf("Error binding to port %d!\n", port);
+ TTQTimer::singleShot(0, this, SIGNAL(quit()));
+ return;
+ }
+ char myhostname[256];
+ int r = gethostname(myhostname, sizeof(myhostname)-1);
+ if(r == -1) {
+ printf("Error getting hostname!\n");
+ TTQTimer::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) {
+ TQSocket tmp;
+ tmp.setSocket(s);
+ printf("Connection ignored, already have one active.\n");
+ return;
+ }
+
+ printf("Connection received! Starting SASL handshake...\n");
+
+ sock = new TQSocket;
+ 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 TQString &, const TQString &)), SLOT(sasl_authCheck(const TQString &, const TQString &)));
+ connect(sasl, SIGNAL(nextStep(const TQByteArray &)), SLOT(sasl_nextStep(const TQByteArray &)));
+ connect(sasl, SIGNAL(authenticated()), SLOT(sasl_authenticated()));
+ connect(sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
+ connect(sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
+ connect(sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
+
+ sock->setSocket(s);
+ mode = 0;
+ inbuf.resize(0);
+
+ sasl->setMinimumSSF(0);
+ sasl->setMaximumSSF(256);
+
+ TQStringList mechlist;
+ if(!sasl->startServer(PROTO_NAME, host, realm, &mechlist)) {
+ printf("Error starting server!\n");
+ quit();
+ }
+ TQString str;
+ bool first = true;
+ for(TQStringList::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)
+ {
+ TQString s;
+ if(x == TQSocket::ErrConnectionRefused)
+ s = "connection refused or timed out";
+ else if(x == TQSocket::ErrHostNotFound)
+ s = "host not found";
+ else if(x == TQSocket::ErrSocketRead)
+ s = "read error";
+
+ printf("Socket error: %s\n", s.latin1());
+ close();
+ }
+
+ void sock_readyRead()
+ {
+ if(sock->canReadLine()) {
+ TQString 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 TQByteArray &stepData)
+ {
+ TQCString cs(stepData.data(), stepData.size()+1);
+ TQString line = "C";
+ if(!stepData.isEmpty()) {
+ line += ',';
+ line += cs;
+ }
+ sendLine(line);
+ }
+
+ void sasl_authCheck(const TQString &user, const TQString &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()
+ {
+ TQByteArray a = sasl->read();
+ int oldsize = inbuf.size();
+ inbuf.resize(oldsize + a.size());
+ memcpy(inbuf.data() + oldsize, a.data(), a.size());
+ processInbuf();
+ }
+
+ void sasl_readyReadOutgoing(int)
+ {
+ TQByteArray 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:
+ TQSocket *sock;
+ QCA::SASL *sasl;
+ TQString host, realm;
+ int port;
+ int mode;
+ TQString str;
+ TQByteArray inbuf;
+ int toWrite;
+
+ void processInbuf()
+ {
+ }
+
+ void handleLine(const TQString &line)
+ {
+ printf("Reading: [%s]\n", line.latin1());
+ if(mode == 0) {
+ int n = line.find(' ');
+ if(n != -1) {
+ TQString mech = line.mid(0, n);
+ TQCString cs = line.mid(n+1).latin1();
+ TQByteArray clientInit(cs.length());
+ memcpy(clientInit.data(), cs.data(), clientInit.size());
+ sasl->putServerFirstStep(mech, clientInit);
+ }
+ else
+ sasl->putServerFirstStep(line);
+ ++mode;
+ }
+ else if(mode == 1) {
+ TQString 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") {
+ TQCString cs = rest.latin1();
+ TQByteArray 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 TQString &line)
+ {
+ printf("Writing: {%s}\n", line.latin1());
+ TQString s = line + '\n';
+ TQCString cs = s.latin1();
+ if(mode == 2) {
+ TQByteArray 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)
+{
+ TQApplication app(argc, argv, false);
+
+ TQString host, user, pass;
+ TQString str = "Hello, World";
+ bool server;
+ if(argc < 2) {
+ usage();
+ return 0;
+ }
+ TQString 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);
+ TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
+ s->start();
+ app.exec();
+ delete s;
+ }
+ else {
+ ClientTest *c = new ClientTest;
+ TQObject::connect(c, SIGNAL(quit()), &app, SLOT(quit()));
+ c->start(host, PROTO_PORT, user, pass);
+ app.exec();
+ delete c;
+ }
+
+ return 0;
+}
diff --git a/examples/sasltest/sasltest.pro b/examples/sasltest/sasltest.pro
new file mode 100644
index 0000000..f7d1c98
--- /dev/null
+++ b/examples/sasltest/sasltest.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = sasltest
+
+INCLUDEPATH += ../common
+HEADERS += ../common/base64.h
+SOURCES += ../common/base64.cpp sasltest.cpp
+include(../examples.pri)
diff --git a/examples/sslservtest/sslservtest.cpp b/examples/sslservtest/sslservtest.cpp
new file mode 100644
index 0000000..384558f
--- /dev/null
+++ b/examples/sslservtest/sslservtest.cpp
@@ -0,0 +1,294 @@
+#include<tqapplication.h>
+#include<tqfile.h>
+#include<tqsocket.h>
+#include<tqserversocket.h>
+#include<tqvaluelist.h>
+#include<tqtimer.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 LayerTracker
+{
+public:
+ struct Item
+ {
+ int plain;
+ int encoded;
+ };
+
+ LayerTracker()
+ {
+ p = 0;
+ }
+
+ void reset()
+ {
+ p = 0;
+ list.clear();
+ }
+
+ void addPlain(int plain)
+ {
+ p += plain;
+ }
+
+ void specifyEncoded(int encoded, int plain)
+ {
+ // can't specify more bytes than we have
+ if(plain > p)
+ plain = p;
+ p -= plain;
+ Item i;
+ i.plain = plain;
+ i.encoded = encoded;
+ list += i;
+ }
+
+ int finished(int encoded)
+ {
+ int plain = 0;
+ for(TQValueList<Item>::Iterator it = list.begin(); it != list.end();) {
+ Item &i = *it;
+
+ // not enough?
+ if(encoded < i.encoded) {
+ i.encoded -= encoded;
+ break;
+ }
+
+ encoded -= i.encoded;
+ plain += i.plain;
+ it = list.remove(it);
+ }
+ return plain;
+ }
+
+ int p;
+ TQValueList<Item> list;
+};
+
+class SecureServerTest : public QServerSocket
+{
+ Q_OBJECT
+public:
+ enum { Idle, Handshaking, Active, Closing };
+
+ SecureServerTest(int _port) : QServerSocket(_port), port(_port)
+ {
+ sock = new TQSocket;
+ 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(int)), SLOT(ssl_readyReadOutgoing(int)));
+ connect(ssl, SIGNAL(closed()), SLOT(ssl_closed()));
+ connect(ssl, SIGNAL(error(int)), SLOT(ssl_error(int)));
+
+ cert.fromPEM(pemdata_cert);
+ privkey.fromPEM(pemdata_privkey);
+
+ mode = Idle;
+ }
+
+ ~SecureServerTest()
+ {
+ delete ssl;
+ delete sock;
+ }
+
+ void start()
+ {
+ if(cert.isNull() || privkey.isNull()) {
+ printf("Error loading cert and/or private key!\n");
+ TTQTimer::singleShot(0, this, SIGNAL(quit()));
+ return;
+ }
+ if(!ok()) {
+ printf("Error binding to port %d!\n", port);
+ TTQTimer::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()) {
+ TQSocket tmp;
+ tmp.setSocket(s);
+ printf("throwing away extra connection\n");
+ return;
+ }
+ mode = Handshaking;
+ sock->setSocket(s);
+ printf("Connection received! Starting TLS handshake...\n");
+ ssl->setCertificate(cert, privkey);
+ ssl->startServer();
+ }
+
+signals:
+ void quit();
+
+private slots:
+ 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("Connection closed.\n");
+ }
+
+ void sock_bytesWritten(int x)
+ {
+ if(mode == Active && sent) {
+ int bytes = layer.finished(x);
+ bytesLeft -= bytes;
+
+ if(bytesLeft == 0) {
+ mode = Closing;
+ printf("SSL shutdown\n");
+ ssl->close();
+ }
+ }
+ }
+
+ void sock_error(int)
+ {
+ printf("Socket error.\n");
+ }
+
+ void ssl_handshaken()
+ {
+ printf("Successful SSL handshake. Waiting for newline.\n");
+ layer.reset();
+ bytesLeft = 0;
+ sent = false;
+ mode = Active;
+ }
+
+ void ssl_readyRead()
+ {
+ TQByteArray a = ssl->read();
+ TQString str =
+ "<html>\n"
+ "<head><title>Test</title></head>\n"
+ "<body>this is only a test</body>\n"
+ "</html>\n";
+ TQCString cs = str.latin1();
+ TQByteArray b(cs.length());
+ memcpy(b.data(), cs.data(), b.size());
+
+ printf("Sending test response...\n");
+ sent = true;
+ layer.addPlain(b.size());
+ ssl->write(b);
+ }
+
+ void ssl_readyReadOutgoing(int plainBytes)
+ {
+ TQByteArray a = ssl->readOutgoing();
+ layer.specifyEncoded(a.size(), plainBytes);
+ sock->writeBlock(a.data(), a.size());
+ }
+
+ void ssl_closed()
+ {
+ printf("Closing.\n");
+ sock->close();
+ }
+
+ 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;
+ TQSocket *sock;
+ QCA::TLS *ssl;
+ QCA::Cert cert;
+ QCA::RSAKey privkey;
+
+ bool sent;
+ int mode;
+ int bytesLeft;
+ LayerTracker layer;
+};
+
+#include"sslservtest.moc"
+
+int main(int argc, char **argv)
+{
+ TQApplication app(argc, argv, false);
+ int port = argc > 1 ? TQString(argv[1]).toInt() : 8000;
+
+ if(!QCA::isSupported(QCA::CAP_TLS)) {
+ printf("TLS not supported!\n");
+ return 1;
+ }
+
+ SecureServerTest *s = new SecureServerTest(port);
+ TQObject::connect(s, SIGNAL(quit()), &app, SLOT(quit()));
+ s->start();
+ app.exec();
+ delete s;
+
+ return 0;
+}
diff --git a/examples/sslservtest/sslservtest.pro b/examples/sslservtest/sslservtest.pro
new file mode 100644
index 0000000..028d5ab
--- /dev/null
+++ b/examples/sslservtest/sslservtest.pro
@@ -0,0 +1,6 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = sslservtest
+
+SOURCES += sslservtest.cpp
+include(../examples.pri)
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;
+}
diff --git a/examples/ssltest/ssltest.pro b/examples/ssltest/ssltest.pro
new file mode 100644
index 0000000..44ae325
--- /dev/null
+++ b/examples/ssltest/ssltest.pro
@@ -0,0 +1,8 @@
+TEMPLATE = app
+CONFIG += thread console
+TARGET = ssltest
+
+INCLUDEPATH += ../common
+HEADERS += ../common/base64.h
+SOURCES += ../common/base64.cpp ssltest.cpp
+include(../examples.pri)