mirror of
https://github.com/QuasarApp/qca.git
synced 2025-04-27 03:54:31 +00:00
Initial port of the SSL server example to QCA2. This still
has a little bit of Q3Support code, which I'll fix soon. svn path=/trunk/kdesupport/qca/; revision=520189
This commit is contained in:
parent
b00a8b2885
commit
1ee33d741d
1
Doxyfile
1
Doxyfile
@ -499,6 +499,7 @@ EXAMPLE_PATH = examples/aes-cmac \
|
||||
examples/hextest \
|
||||
examples/certtest \
|
||||
examples/ssltest \
|
||||
examples/sslservtest \
|
||||
examples/rsatest
|
||||
|
||||
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*
|
||||
Copyright (C) 2003 Justin Karneges
|
||||
Copyright (C) 2006 Brad Hards
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@ -19,14 +20,10 @@
|
||||
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<qfile.h>
|
||||
#include<qsocket.h>
|
||||
#include<qserversocket.h>
|
||||
#include<qvaluelist.h>
|
||||
#include<qtimer.h>
|
||||
#include"qca.h"
|
||||
#include <QtCore>
|
||||
#include <QtNetwork>
|
||||
#include<q3serversocket.h>
|
||||
#include <QtCrypto>
|
||||
|
||||
char pemdata_cert[] =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
@ -71,246 +68,252 @@ char pemdata_privkey[] =
|
||||
class LayerTracker
|
||||
{
|
||||
public:
|
||||
struct Item
|
||||
{
|
||||
int plain;
|
||||
int encoded;
|
||||
};
|
||||
struct Item
|
||||
{
|
||||
int plain;
|
||||
int encoded;
|
||||
};
|
||||
|
||||
LayerTracker()
|
||||
{
|
||||
p = 0;
|
||||
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(QList<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);
|
||||
}
|
||||
|
||||
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(QValueList<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;
|
||||
QValueList<Item> list;
|
||||
return plain;
|
||||
}
|
||||
|
||||
int p;
|
||||
QList<Item> list;
|
||||
};
|
||||
|
||||
class SecureServerTest : public QServerSocket
|
||||
class SecureServerTest : public Q3ServerSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum { Idle, Handshaking, Active, Closing };
|
||||
enum { Idle, Handshaking, Active, Closing };
|
||||
|
||||
SecureServerTest(int _port) : Q3ServerSocket(_port), port(_port)
|
||||
{
|
||||
sock = new QTcpSocket;
|
||||
connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
|
||||
connect(sock, SIGNAL(connectionClosed()), SLOT(sock_connectionClosed()));
|
||||
connect(sock, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
SLOT(sock_error(QAbstractSocket::SocketError)));
|
||||
connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64)));
|
||||
|
||||
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(closed()), SLOT(ssl_closed()));
|
||||
connect(ssl, SIGNAL(error()), SLOT(ssl_error()));
|
||||
|
||||
cert = QCA::Certificate::fromPEM(pemdata_cert);
|
||||
QCA::PrivateKey key = QCA::PrivateKey::fromPEM(pemdata_privkey);
|
||||
privkey = key.toRSA();
|
||||
|
||||
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)));
|
||||
mode = Idle;
|
||||
}
|
||||
|
||||
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)));
|
||||
~SecureServerTest()
|
||||
{
|
||||
delete ssl;
|
||||
delete sock;
|
||||
}
|
||||
|
||||
cert.fromPEM(pemdata_cert);
|
||||
privkey.fromPEM(pemdata_privkey);
|
||||
|
||||
mode = Idle;
|
||||
void start()
|
||||
{
|
||||
if(cert.isNull()) {
|
||||
printf("Error loading cert!\n");
|
||||
QTimer::singleShot(0, this, SIGNAL(quit()));
|
||||
return;
|
||||
}
|
||||
|
||||
~SecureServerTest()
|
||||
{
|
||||
delete ssl;
|
||||
delete sock;
|
||||
if(privkey.isNull()) {
|
||||
printf("Error loading private key!\n");
|
||||
QTimer::singleShot(0, this, SIGNAL(quit()));
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
mode = Handshaking;
|
||||
sock->setSocket(s);
|
||||
printf("Connection received! Starting TLS handshake...\n");
|
||||
ssl->setCertificate(cert, privkey);
|
||||
ssl->startServer();
|
||||
void newConnection(int s)
|
||||
{
|
||||
// Note: only 1 connection supported at a time in this example!
|
||||
if(sock->isOpen()) {
|
||||
QTcpSocket 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();
|
||||
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_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(qint64 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_connectionClosed()
|
||||
{
|
||||
printf("Connection closed.\n");
|
||||
void sock_error(QAbstractSocket::SocketError error)
|
||||
{
|
||||
qDebug() << "Socket error: " << error;
|
||||
}
|
||||
|
||||
void ssl_handshaken()
|
||||
{
|
||||
printf("Successful SSL handshake. Waiting for newline.\n");
|
||||
layer.reset();
|
||||
bytesLeft = 0;
|
||||
sent = false;
|
||||
mode = Active;
|
||||
}
|
||||
|
||||
void ssl_readyRead()
|
||||
{
|
||||
QByteArray a = ssl->read();
|
||||
QByteArray b =
|
||||
"<html>\n"
|
||||
"<head><title>Test</title></head>\n"
|
||||
"<body>this is only a test</body>\n"
|
||||
"</html>\n";
|
||||
|
||||
printf("Sending test response...\n");
|
||||
sent = true;
|
||||
layer.addPlain(b.size());
|
||||
ssl->write(b);
|
||||
}
|
||||
|
||||
void ssl_readyReadOutgoing()
|
||||
{
|
||||
QByteArray a = ssl->readOutgoing();
|
||||
layer.specifyEncoded(a.size(), ssl->bytesOutgoingAvailable());
|
||||
sock->writeBlock(a.data(), a.size());
|
||||
}
|
||||
|
||||
void ssl_closed()
|
||||
{
|
||||
printf("Closing.\n");
|
||||
sock->close();
|
||||
}
|
||||
|
||||
void ssl_error()
|
||||
{
|
||||
if(ssl->errorCode() == QCA::TLS::ErrorHandshake) {
|
||||
printf("SSL Handshake Error! Closing.\n");
|
||||
sock->close();
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
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");
|
||||
sent = true;
|
||||
layer.addPlain(b.size());
|
||||
ssl->write(b);
|
||||
}
|
||||
|
||||
void ssl_readyReadOutgoing(int plainBytes)
|
||||
{
|
||||
QByteArray 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();
|
||||
}
|
||||
else {
|
||||
printf("SSL Error! Closing.\n");
|
||||
sock->close();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int port;
|
||||
QSocket *sock;
|
||||
QCA::TLS *ssl;
|
||||
QCA::Cert cert;
|
||||
QCA::RSAKey privkey;
|
||||
|
||||
bool sent;
|
||||
int mode;
|
||||
int bytesLeft;
|
||||
LayerTracker layer;
|
||||
int port;
|
||||
QTcpSocket *sock;
|
||||
QCA::TLS *ssl;
|
||||
QCA::Certificate cert;
|
||||
QCA::RSAPrivateKey privkey;
|
||||
|
||||
bool sent;
|
||||
int mode;
|
||||
int bytesLeft;
|
||||
LayerTracker layer;
|
||||
};
|
||||
|
||||
#include"sslservtest.moc"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QApplication app(argc, argv, false);
|
||||
int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
|
||||
QCA::Initializer init;
|
||||
|
||||
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;
|
||||
QCoreApplication app(argc, argv);
|
||||
int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
|
||||
|
||||
if(!QCA::isSupported("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;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
TEMPLATE = app
|
||||
CONFIG += thread console
|
||||
TARGET = sslservtest
|
||||
CONFIG -= app_bundle
|
||||
CONFIG += thread console
|
||||
QT += network
|
||||
QT += qt3support
|
||||
|
||||
SOURCES += sslservtest.cpp
|
||||
include(../examples.pri)
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user