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 }