File indexing completed on 2024-10-13 07:16:34
0001 /* 0002 Copyright (C) 2003 Justin Karneges <justin@affinix.com> 0003 Copyright (C) 2006 Brad Hards <bradh@frogmouth.net> 0004 0005 Permission is hereby granted, free of charge, to any person obtaining a copy 0006 of this software and associated documentation files (the "Software"), to deal 0007 in the Software without restriction, including without limitation the rights 0008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 0009 copies of the Software, and to permit persons to whom the Software is 0010 furnished to do so, subject to the following conditions: 0011 0012 The above copyright notice and this permission notice shall be included in 0013 all copies or substantial portions of the Software. 0014 0015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 0016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 0017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 0018 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 0019 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 0020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 0021 */ 0022 0023 #include <QtCrypto> 0024 0025 #include <QCoreApplication> 0026 #include <QDebug> 0027 #include <QHostAddress> 0028 #include <QTcpServer> 0029 #include <QTcpSocket> 0030 #include <QTimer> 0031 0032 #ifdef QT_STATICPLUGIN 0033 #include "import_plugins.h" 0034 #endif 0035 0036 char pemdata_cert[] = 0037 "-----BEGIN CERTIFICATE-----\n" 0038 "MIICeTCCAeKgAwIBAgIRAKKKnOj6Aarmwf0phApitVAwDQYJKoZIhvcNAQEFBQAw\n" 0039 "ODELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0V4YW1wbGUgT3JnMRMwEQYDVQQDEwpF\n" 0040 "eGFtcGxlIENBMB4XDTA2MDMxNTA3MDU1MloXDTA3MDMxNTA3MDU1MlowOjEVMBMG\n" 0041 "A1UEAxMMRXhhbXBsZSBVc2VyMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRXhhbXBs\n" 0042 "ZSBPcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPkKn0FfHMvRZv+3uFcw\n" 0043 "VrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9sEAY\n" 0044 "YNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6YjR2\n" 0045 "NEvIKt1P4mHzYXLmwoF24C1bAgMBAAGjgYAwfjAdBgNVHQ4EFgQUmQIdzyDaPYWF\n" 0046 "fPJ8PPOOm1eSsucwHwYDVR0jBBgwFoAUkCglAizTO7iqwLeaO6r/8kJuqhMwDAYD\n" 0047 "VR0TAQH/BAIwADAeBgNVHREEFzAVgRNleGFtcGxlQGV4YW1wbGUuY29tMA4GA1Ud\n" 0048 "DwEB/wQEAwIF4DANBgkqhkiG9w0BAQUFAAOBgQAuhbiUgy2a++EUccaonID7eTJZ\n" 0049 "F3D5qXMqUpQxlYxU8du+9AxDD7nFxTMkQC2pzfmEc1znRNmJ1ZeLRL72VYsVndcT\n" 0050 "psyM8ABkvPp1d2jWIyccVjGpt+/RN5IPKm/YIbtIZcywvWuXrOp1lanVmppLfPnO\n" 0051 "6yneBkC9iqjOv/+Q+A==\n" 0052 "-----END CERTIFICATE-----\n"; 0053 0054 char pemdata_privkey[] = 0055 "-----BEGIN PRIVATE KEY-----\n" 0056 "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAPkKn0FfHMvRZv+3\n" 0057 "uFcwVrOadJmANzLVeVW/DHZp4CXokXSksM66ZMqFuQRBk5rnIZZpZmVp1tTRDVt9\n" 0058 "sEAYYNa8CRM4HXkVlU0lCKdey18CSq2VuSvNtw8dDpoBmQt3nr9tePvKHnpS3nm6\n" 0059 "YjR2NEvIKt1P4mHzYXLmwoF24C1bAgMBAAECgYEAyIjJHDaeVXDU42zovyxpZE4n\n" 0060 "PcOEryY+gdFJE8DFgUD4f1huFsj4iCuNg+PaG42p+hf9IARNvSho/RcEaVg4AJrV\n" 0061 "jRP8r7fSqcIGr6lGuvDFFv3SU5ddy84g5oqLYGKvuPSHMGfVsZSxAwOrzD4bH19L\n" 0062 "SNqtNcpdBsBd7ZiEE4ECQQD/oJGui9D5Dx3QVcS+QV4F8wuyN9jYIANmX/17o0fl\n" 0063 "BL0bwRU4RICwadrcybi5N0JQLIYSUm2HGqNvAJbtnuQxAkEA+WeYLLYPeawcy+WU\n" 0064 "kGcOR7BUjHiG71+6cvU4XIDW2bezA04fqWXkZRFAwHTMpQb785/XalFftgS21kql\n" 0065 "8yLDSwJAHkeT2hwftdDPlEUEmBDAJW5DvWmWGwu3u2G1cfbGZl9oUyhM7ixXHg57\n" 0066 "6VlPs0jTZxHPE86FwNIr99MXDbCbkQJBAMDFOJK+ecGirXNP1P+0GA6DFSap9inJ\n" 0067 "BRTbwx+EmgwX966DUOefEOSpbDIVVSPs/Qr2LgtIMEFA7Y0+j3wZD3cCQBsTwccd\n" 0068 "ASQx59xakpq11eOlTYz14rjwodr4QMyj26WxEPJtz7hKokx/+EH6fWuPIUSrROM5\n" 0069 "07y2gaVbYxtis0s=\n" 0070 "-----END PRIVATE KEY-----\n"; 0071 0072 class SecureServer : public QObject 0073 { 0074 Q_OBJECT 0075 0076 public: 0077 enum 0078 { 0079 Idle, 0080 Handshaking, 0081 Active, 0082 Closing 0083 }; 0084 0085 SecureServer(quint16 _port) 0086 : port(_port) 0087 { 0088 server = new QTcpServer; 0089 connect(server, &QTcpServer::newConnection, this, &SecureServer::server_handleConnection); 0090 0091 ssl = new QCA::TLS; 0092 connect(ssl, &QCA::TLS::handshaken, this, &SecureServer::ssl_handshaken); 0093 connect(ssl, &QCA::TLS::readyRead, this, &SecureServer::ssl_readyRead); 0094 connect(ssl, &QCA::TLS::readyReadOutgoing, this, &SecureServer::ssl_readyReadOutgoing); 0095 connect(ssl, &QCA::TLS::closed, this, &SecureServer::ssl_closed); 0096 connect(ssl, &QCA::TLS::error, this, &SecureServer::ssl_error); 0097 0098 cert = QCA::Certificate::fromPEM(QString::fromLatin1(pemdata_cert)); 0099 privkey = QCA::PrivateKey::fromPEM(QString::fromLatin1(pemdata_privkey)); 0100 0101 mode = Idle; 0102 } 0103 0104 ~SecureServer() override 0105 { 0106 delete ssl; 0107 delete server; 0108 } 0109 0110 void start() 0111 { 0112 if (cert.isNull()) { 0113 qDebug() << "Error loading cert!"; 0114 QTimer::singleShot(0, this, &SecureServer::quit); 0115 return; 0116 } 0117 if (privkey.isNull()) { 0118 qDebug() << "Error loading private key!"; 0119 QTimer::singleShot(0, this, &SecureServer::quit); 0120 return; 0121 } 0122 if (false == server->listen(QHostAddress::Any, port)) { 0123 qDebug() << "Error binding to port " << port; 0124 QTimer::singleShot(0, this, &SecureServer::quit); 0125 return; 0126 } 0127 qDebug() << "Listening on port" << port; 0128 } 0129 0130 Q_SIGNALS: 0131 void quit(); 0132 0133 private Q_SLOTS: 0134 void sock_readyRead() 0135 { 0136 QByteArray buf(sock->bytesAvailable(), 0x00); 0137 0138 int num = sock->read(buf.data(), buf.size()); 0139 0140 if (-1 == num) 0141 qDebug() << "Error reading data from socket"; 0142 0143 if (num < buf.size()) 0144 buf.resize(num); 0145 0146 ssl->writeIncoming(buf); 0147 } 0148 0149 void server_handleConnection() 0150 { 0151 // Note: only 1 connection supported at a time in this example! 0152 if (mode != Idle) { 0153 QTcpSocket *tmp = server->nextPendingConnection(); 0154 tmp->close(); 0155 connect(tmp, &QTcpSocket::disconnected, tmp, &QTcpSocket::deleteLater); 0156 qDebug() << "throwing away extra connection"; 0157 return; 0158 } 0159 mode = Handshaking; 0160 sock = server->nextPendingConnection(); 0161 connect(sock, &QTcpSocket::readyRead, this, &SecureServer::sock_readyRead); 0162 connect(sock, &QTcpSocket::disconnected, this, &SecureServer::sock_disconnected); 0163 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) 0164 connect(sock, &QTcpSocket::errorOccurred, this, &SecureServer::sock_error); 0165 #else 0166 connect(sock, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error), this, &SecureServer::sock_error); 0167 #endif 0168 connect(sock, &QTcpSocket::bytesWritten, this, &SecureServer::sock_bytesWritten); 0169 0170 qDebug() << "Connection received! Starting TLS handshake."; 0171 ssl->setCertificate(cert, privkey); 0172 ssl->startServer(); 0173 } 0174 0175 void sock_disconnected() 0176 { 0177 qDebug() << "Connection closed."; 0178 } 0179 0180 void sock_bytesWritten(qint64 x) 0181 { 0182 if (mode == Active && sent) { 0183 qint64 bytes = ssl->convertBytesWritten(x); 0184 bytesLeft -= bytes; 0185 0186 if (bytesLeft == 0) { 0187 mode = Closing; 0188 qDebug() << "Data transfer complete - SSL shutting down"; 0189 ssl->close(); 0190 } 0191 } 0192 } 0193 0194 void sock_error(QAbstractSocket::SocketError error) 0195 { 0196 qDebug() << "Socket error: " << (unsigned)error; 0197 } 0198 0199 void ssl_handshaken() 0200 { 0201 qDebug() << "Successful SSL handshake. Waiting for newline."; 0202 bytesLeft = 0; 0203 sent = false; 0204 mode = Active; 0205 ssl->continueAfterStep(); 0206 } 0207 0208 void ssl_readyRead() 0209 { 0210 ssl->read(); 0211 QByteArray b = 0212 "<html>\n" 0213 "<head><title>Test</title></head>\n" 0214 "<body>this is only a test</body>\n" 0215 "</html>\n"; 0216 0217 qDebug() << "Sending test response."; 0218 sent = true; 0219 ssl->write(b); 0220 } 0221 0222 void ssl_readyReadOutgoing() 0223 { 0224 int plainBytes; 0225 QByteArray outgoingData = ssl->readOutgoing(&plainBytes); 0226 sock->write(outgoingData); 0227 } 0228 0229 void ssl_closed() 0230 { 0231 qDebug() << "Closing socket."; 0232 sock->close(); 0233 mode = Idle; 0234 } 0235 0236 void ssl_error() 0237 { 0238 if (ssl->errorCode() == QCA::TLS::ErrorHandshake) { 0239 qDebug() << "SSL Handshake Error! Closing."; 0240 sock->close(); 0241 } else { 0242 qDebug() << "SSL Error! Closing."; 0243 sock->close(); 0244 } 0245 mode = Idle; 0246 } 0247 0248 private: 0249 quint16 port; 0250 QTcpServer *server; 0251 QTcpSocket *sock; 0252 QCA::TLS *ssl; 0253 QCA::Certificate cert; 0254 QCA::PrivateKey privkey; 0255 0256 bool sent; 0257 int mode; 0258 qint64 bytesLeft; 0259 }; 0260 0261 #include "sslservtest.moc" 0262 0263 int main(int argc, char **argv) 0264 { 0265 QCA::Initializer init; 0266 0267 QCoreApplication app(argc, argv); 0268 int port = argc > 1 ? QString::fromLatin1(argv[1]).toInt() : 8000; 0269 0270 if (!QCA::isSupported("tls")) { 0271 qDebug() << "TLS not supported!"; 0272 return 1; 0273 } 0274 0275 SecureServer *server = new SecureServer(port); 0276 QObject::connect(server, &SecureServer::quit, &app, &QCoreApplication::quit); 0277 server->start(); 0278 app.exec(); 0279 delete server; 0280 0281 return 0; 0282 }