File indexing completed on 2024-05-26 08:35:48

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 }