summaryrefslogtreecommitdiffstats
path: root/examples/sslservtest
diff options
context:
space:
mode:
Diffstat (limited to 'examples/sslservtest')
-rw-r--r--examples/sslservtest/sslservtest.cpp294
-rw-r--r--examples/sslservtest/sslservtest.pro6
2 files changed, 300 insertions, 0 deletions
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)