You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tqca/examples/sslservtest/sslservtest.cpp

295 lines
7.0 KiB

#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
{
TQ_OBJECT
public:
enum { Idle, Handshaking, Active, Closing };
SecureServerTest(int _port) : QServerSocket(_port), port(_port)
{
sock = new TQSocket;
connect(sock, TQ_SIGNAL(readyRead()), TQ_SLOT(sock_readyRead()));
connect(sock, TQ_SIGNAL(connectionClosed()), TQ_SLOT(sock_connectionClosed()));
connect(sock, TQ_SIGNAL(error(int)), TQ_SLOT(sock_error(int)));
connect(sock, TQ_SIGNAL(bytesWritten(int)), TQ_SLOT(sock_bytesWritten(int)));
ssl = new QCA::TLS;
connect(ssl, TQ_SIGNAL(handshaken()), TQ_SLOT(ssl_handshaken()));
connect(ssl, TQ_SIGNAL(readyRead()), TQ_SLOT(ssl_readyRead()));
connect(ssl, TQ_SIGNAL(readyReadOutgoing(int)), TQ_SLOT(ssl_readyReadOutgoing(int)));
connect(ssl, TQ_SIGNAL(closed()), TQ_SLOT(ssl_closed()));
connect(ssl, TQ_SIGNAL(error(int)), TQ_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");
TQTimer::singleShot(0, this, TQ_SIGNAL(quit()));
return;
}
if(!ok()) {
printf("Error binding to port %d!\n", port);
TQTimer::singleShot(0, this, TQ_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, TQ_SIGNAL(quit()), &app, TQ_SLOT(quit()));
s->start();
app.exec();
delete s;
return 0;
}