sslservtest.cpp

The code below shows how to create an SSL server.Note that this server returns a self-signed certificate for "example.com", and that the certificate is expired.

The design used here only allows for one connection at a time. If you want to allow for more, you should probably create a "TlsConnection" object that agregates a QCA::TLS object and a QTcpSocket (plus a little bit of state information) that handles a single connection. Then just create a TlsConnection for each server connection.

00001 /*
00002  Copyright (C) 2003 Justin Karneges <justin@affinix.com>
00003  Copyright (C) 2006 Brad Hards <bradh@frogmouth.net>
00004 
00005  Permission is hereby granted, free of charge, to any person obtaining a copy
00006  of this software and associated documentation files (the "Software"), to deal
00007  in the Software without restriction, including without limitation the rights
00008  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009  copies of the Software, and to permit persons to whom the Software is
00010  furnished to do so, subject to the following conditions:
00011 
00012  The above copyright notice and this permission notice shall be included in
00013  all copies or substantial portions of the Software.
00014 
00015  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00018  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00019  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00020  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 */
00022 
00023 #include <QtCrypto>
00024 
00025 #include <QCoreApplication>
00026 #include <QDebug>
00027 #include <QHostAddress>
00028 #include <QTcpServer>
00029 #include <QTcpSocket>
00030 #include <QTimer>
00031 
00032 char pemdata_cert[] =
00033         "-----BEGIN CERTIFICATE-----\n"
00034         "MIICeTCCAeKgAwIBAgIRAKKKnOj6Aarmwf0phApitVAwDQYJKoZIhvcNAQEFBQAw\n"
00035         "ODELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0V4YW1wbGUgT3JnMRMwEQYDVQQDEwpF\n"
00036         "eGFtcGxlIENBMB4XDTA2MDMxNTA3MDU1MloXDTA3MDMxNTA3MDU1MlowOjEVMBMG\n"
00037         "A1UEAxMMRXhhbXBsZSBVc2VyMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBs\n"
00038         "ZSBPcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPkKn0FfHMvRZv+3uFcw\n"
00039         "VrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9sEAY\n"
00040         "YNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6YjR2\n"
00041         "NEvIKt1P4mHzYXLmwoF24C1bAgMBAAGjgYAwfjAdBgNVHQ4EFgQUmQIdzyDaPYWF\n"
00042         "fPJ8PPOOm1eSsucwHwYDVR0jBBgwFoAUkCglAizTO7iqwLeaO6r/8kJuqhMwDAYD\n"
00043         "VR0TAQH/BAIwADAeBgNVHREEFzAVgRNleGFtcGxlQGV4YW1wbGUuY29tMA4GA1Ud\n"
00044         "DwEB/wQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQAuhbiUgy2a++EUccaonID7eTJZ\n"
00045         "F3D5qXMqUpQxlYxU8du+9AxDD7nFxTMkQC2pzfmEc1znRNmJ1ZeLRL72VYsVndcT\n"
00046         "psyM8ABkvPp1d2jWIyccVjGpt+/RN5IPKm/YIbtIZcywvWuXrOp1lanVmppLfPnO\n"
00047         "6yneBkC9iqjOv/+Q+A==\n"
00048         "-----END CERTIFICATE-----\n";
00049 
00050 char pemdata_privkey[] =
00051         "-----BEGIN PRIVATE KEY-----\n"
00052         "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPkKn0FfHMvRZv+3\n"
00053         "uFcwVrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9\n"
00054         "sEAYYNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6\n"
00055         "YjR2NEvIKt1P4mHzYXLmwoF24C1bAgMBAAECgYEAyIjJHDaeVXDU42zovyxpZE4n\n"
00056         "PcOEryY+gdFJE8DFgUD4f1huFsj4iCuNg+PaG42p+hf9IARNvSho/RcEaVg4AJrV\n"
00057         "jRP8r7fSqcIGr6lGuvDFFv3SU5ddy84g5oqLYGKvuPSHMGfVsZSxAwOrzD4bH19L\n"
00058         "SNqtNcpdBsBd7ZiEE4ECQQD/oJGui9D5Dx3QVcS+QV4F8wuyN9jYIANmX/17o0fl\n"
00059         "BL0bwRU4RICwadrcybi5N0JQLIYSUm2HGqNvAJbtnuQxAkEA+WeYLLYPeawcy+WU\n"
00060         "kGcOR7BUjHiG71+6cvU4XIDW2bezA04fqWXkZRFAwHTMpQb785/XalFftgS21kql\n"
00061         "8yLDSwJAHkeT2hwftdDPlEUEmBDAJW5DvWmWGwu3u2G1cfbGZl9oUyhM7ixXHg57\n"
00062         "6VlPs0jTZxHPE86FwNIr99MXDbCbkQJBAMDFOJK+ecGirXNP1P+0GA6DFSap9inJ\n"
00063         "BRTbwx+EmgwX966DUOefEOSpbDIVVSPs/Qr2LgtIMEFA7Y0+j3wZD3cCQBsTwccd\n"
00064         "ASQx59xakpq11eOlTYz14rjwodr4QMyj26WxEPJtz7hKokx/+EH6fWuPIUSrROM5\n"
00065         "07y2gaVbYxtis0s=\n"
00066         "-----END PRIVATE KEY-----\n";
00067 
00068 class SecureServer : public QObject
00069 {
00070     Q_OBJECT
00071 
00072 public:
00073     enum { Idle, Handshaking, Active, Closing };
00074 
00075     SecureServer(quint16 _port) : port(_port)
00076     {
00077         server = new QTcpServer;
00078         connect( server, SIGNAL(newConnection()), SLOT(server_handleConnection()) );
00079 
00080         ssl = new QCA::TLS;
00081         connect(ssl, SIGNAL(handshaken()), SLOT(ssl_handshaken()));
00082         connect(ssl, SIGNAL(readyRead()), SLOT(ssl_readyRead()));
00083         connect(ssl, SIGNAL(readyReadOutgoing()), SLOT(ssl_readyReadOutgoing()));
00084         connect(ssl, SIGNAL(closed()), SLOT(ssl_closed()));
00085         connect(ssl, SIGNAL(error()), SLOT(ssl_error()));
00086 
00087         cert = QCA::Certificate::fromPEM(pemdata_cert);
00088         privkey = QCA::PrivateKey::fromPEM(pemdata_privkey);
00089 
00090         mode = Idle;
00091     }
00092 
00093     ~SecureServer()
00094     {
00095         delete ssl;
00096         delete server;
00097     }
00098 
00099     void start()
00100     {
00101         if(cert.isNull()) {
00102             qDebug() << "Error loading cert!";
00103             QTimer::singleShot(0, this, SIGNAL(quit()));
00104             return;
00105         }
00106         if(privkey.isNull()) {
00107             qDebug() << "Error loading private key!";
00108             QTimer::singleShot(0, this, SIGNAL(quit()));
00109             return;
00110         }
00111         if(false == server->listen(QHostAddress::Any, port)) {
00112             qDebug() << "Error binding to port " << port;
00113             QTimer::singleShot(0, this, SIGNAL(quit()));
00114             return;
00115         }
00116         qDebug() << "Listening on port" << port;
00117     }
00118 
00119 signals:
00120     void quit();
00121 
00122 private slots:
00123     void sock_readyRead()
00124     {
00125         QByteArray buf(sock->bytesAvailable(), 0x00);
00126 
00127         int num = sock->read(buf.data(), buf.size());
00128 
00129         if ( -1 == num )
00130             qDebug() << "Error reading data from socket";
00131 
00132         if (num < buf.size() )
00133             buf.resize(num);
00134 
00135         ssl->writeIncoming(buf);
00136     }
00137 
00138     void server_handleConnection()
00139     {
00140         // Note: only 1 connection supported at a time in this example!
00141         if(mode != Idle) {
00142             QTcpSocket* tmp = server->nextPendingConnection();
00143             tmp->close();
00144             connect(tmp, SIGNAL(disconnected()), tmp, SLOT(deleteLater()));
00145             qDebug() << "throwing away extra connection";
00146             return;
00147         }
00148         mode = Handshaking;
00149         sock = server->nextPendingConnection();
00150         connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead()));
00151         connect(sock, SIGNAL(disconnected()), SLOT(sock_disconnected()));
00152         connect(sock, SIGNAL(error(QAbstractSocket::SocketError)),
00153                 SLOT(sock_error(QAbstractSocket::SocketError)));
00154         connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64)));
00155 
00156         qDebug() << "Connection received!  Starting TLS handshake.";
00157         ssl->setCertificate(cert, privkey);
00158         ssl->startServer();
00159     }
00160 
00161     void sock_disconnected()
00162     {
00163         qDebug() << "Connection closed.";
00164     }
00165 
00166     void sock_bytesWritten(qint64 x)
00167     {
00168         if(mode == Active && sent) {
00169             qint64 bytes = ssl->convertBytesWritten(x);
00170             bytesLeft -= bytes;
00171 
00172             if(bytesLeft == 0) {
00173                 mode = Closing;
00174                 qDebug() << "Data transfer complete - SSL shutting down";
00175                 ssl->close();
00176             }
00177         }
00178     }
00179 
00180     void sock_error(QAbstractSocket::SocketError error)
00181     {
00182         qDebug() << "Socket error: " << (unsigned) error;
00183     }
00184 
00185     void ssl_handshaken()
00186     {
00187         qDebug() << "Successful SSL handshake.  Waiting for newline.";
00188         bytesLeft = 0;
00189         sent = false;
00190         mode = Active;
00191         ssl->continueAfterStep();
00192     }
00193 
00194     void ssl_readyRead()
00195     {
00196         QByteArray a = ssl->read();
00197         QByteArray b =
00198             "<html>\n"
00199             "<head><title>Test</title></head>\n"
00200             "<body>this is only a test</body>\n"
00201             "</html>\n";
00202 
00203         qDebug() << "Sending test response.";
00204         sent = true;
00205         ssl->write(b);
00206     }
00207 
00208     void ssl_readyReadOutgoing()
00209     {
00210         int plainBytes;
00211         QByteArray outgoingData = ssl->readOutgoing(&plainBytes);
00212         sock->write( outgoingData );
00213     }
00214 
00215     void ssl_closed()
00216     {
00217         qDebug() << "Closing socket.";
00218         sock->close();
00219         mode = Idle;
00220     }
00221 
00222     void ssl_error()
00223     {
00224         if(ssl->errorCode() == QCA::TLS::ErrorHandshake) {
00225             qDebug() << "SSL Handshake Error!  Closing.";
00226             sock->close();
00227         }
00228         else {
00229             qDebug() << "SSL Error!  Closing.";
00230             sock->close();
00231         }
00232         mode = Idle;
00233     }
00234 
00235 private:
00236     quint16 port;
00237     QTcpServer *server;
00238     QTcpSocket *sock;
00239     QCA::TLS *ssl;
00240     QCA::Certificate cert;
00241     QCA::PrivateKey privkey;
00242 
00243     bool sent;
00244     int mode;
00245     qint64 bytesLeft;
00246 };
00247 
00248 #include "sslservtest.moc"
00249 
00250 int main(int argc, char **argv)
00251 {
00252     QCA::Initializer init;
00253 
00254     QCoreApplication app(argc, argv);
00255     int port = argc > 1 ? QString(argv[1]).toInt() : 8000;
00256 
00257     if(!QCA::isSupported("tls")) {
00258         qDebug() << "TLS not supported!";
00259         return 1;
00260     }
00261 
00262     SecureServer *server = new SecureServer(port);
00263     QObject::connect(server, SIGNAL(quit()), &app, SLOT(quit()));
00264     server->start();
00265     app.exec();
00266     delete server;
00267 
00268     return 0;
00269 }

Generated on Thu Sep 6 19:13:35 2007 for Qt Cryptographic Architecture by  doxygen 1.5.2