File indexing completed on 2024-10-13 07:16:34

0001 /*
0002  Copyright (C) 2007 Justin Karneges <justin@affinix.com>
0003 
0004  Permission is hereby granted, free of charge, to any person obtaining a copy
0005  of this software and associated documentation files (the "Software"), to deal
0006  in the Software without restriction, including without limitation the rights
0007  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008  copies of the Software, and to permit persons to whom the Software is
0009  furnished to do so, subject to the following conditions:
0010 
0011  The above copyright notice and this permission notice shall be included in
0012  all copies or substantial portions of the Software.
0013 
0014  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
0017  AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
0018  AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
0019  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0020 */
0021 
0022 #include "tlssocket.h"
0023 
0024 #ifdef QT_STATICPLUGIN
0025 #include "import_plugins.h"
0026 #endif
0027 
0028 class TLSSocket::Private : public QObject
0029 {
0030     Q_OBJECT
0031 public:
0032     TLSSocket        *q;
0033     QTcpSocket       *sock;
0034     QCA::TLS         *tls;
0035     QString           host;
0036     bool              encrypted;
0037     bool              error, done;
0038     QByteArray        readbuf, writebuf;
0039     QCA::Synchronizer sync;
0040     bool              waiting;
0041 
0042     Private(TLSSocket *_q)
0043         : QObject(_q)
0044         , q(_q)
0045         , sync(_q)
0046     {
0047         sock = new QTcpSocket(this);
0048         connect(sock, &QTcpSocket::connected, this, &TLSSocket::Private::sock_connected);
0049         connect(sock, &QTcpSocket::readyRead, this, &TLSSocket::Private::sock_readyRead);
0050         connect(sock, &QTcpSocket::bytesWritten, this, &TLSSocket::Private::sock_bytesWritten);
0051 #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
0052         connect(sock, &QTcpSocket::errorOccurred, this, &TLSSocket::Private::sock_error);
0053 #else
0054         connect(sock,
0055                 QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::error),
0056                 this,
0057                 &TLSSocket::Private::sock_error);
0058 #endif
0059 
0060         tls = new QCA::TLS(this);
0061         connect(tls, &QCA::TLS::handshaken, this, &TLSSocket::Private::tls_handshaken);
0062         connect(tls, &QCA::TLS::readyRead, this, &TLSSocket::Private::tls_readyRead);
0063         connect(tls, &QCA::TLS::readyReadOutgoing, this, &TLSSocket::Private::tls_readyReadOutgoing);
0064         connect(tls, &QCA::TLS::closed, this, &TLSSocket::Private::tls_closed);
0065         connect(tls, &QCA::TLS::error, this, &TLSSocket::Private::tls_error);
0066         tls->setTrustedCertificates(QCA::systemStore());
0067         encrypted = false;
0068         error     = false;
0069         waiting   = false;
0070         done      = false;
0071     }
0072 
0073     bool waitForReadyRead(int msecs)
0074     {
0075         waiting = true;
0076         bool ok = sync.waitForCondition(msecs);
0077         // while(1)
0078         //  QCoreApplication::instance()->processEvents();
0079         waiting = false;
0080         if (error || done)
0081             return false;
0082         return ok;
0083     }
0084 
0085 private Q_SLOTS:
0086     void sock_connected()
0087     {
0088         // printf("sock connected\n");
0089         tls->startClient(host);
0090     }
0091 
0092     void sock_readyRead()
0093     {
0094         // printf("sock ready read\n");
0095         QByteArray buf = sock->readAll();
0096         // printf("%d bytes\n", buf.size());
0097         tls->writeIncoming(buf);
0098     }
0099 
0100     void sock_bytesWritten(qint64 x)
0101     {
0102         Q_UNUSED(x);
0103         // printf("sock bytes written: %d\n", (int)x);
0104     }
0105 
0106     void sock_error(QAbstractSocket::SocketError x)
0107     {
0108         // printf("sock error: %d\n", x);
0109         Q_UNUSED(x);
0110         done = true;
0111         if (waiting)
0112             sync.conditionMet();
0113     }
0114 
0115     void tls_handshaken()
0116     {
0117         // printf("tls handshaken\n");
0118         if (tls->peerIdentityResult() != QCA::TLS::Valid) {
0119             printf("not valid\n");
0120             sock->abort();
0121             tls->reset();
0122             error = true;
0123         } else {
0124             // printf("valid\n");
0125             encrypted = true;
0126             // printf("%d bytes in writebuf\n", writebuf.size());
0127             if (!writebuf.isEmpty()) {
0128                 // printf("[%s]\n", writebuf.data());
0129                 tls->write(writebuf);
0130                 writebuf.clear();
0131             }
0132         }
0133         if (waiting)
0134             sync.conditionMet();
0135     }
0136 
0137     void tls_readyRead()
0138     {
0139         // printf("tls ready read\n");
0140         if (waiting)
0141             sync.conditionMet();
0142     }
0143 
0144     void tls_readyReadOutgoing()
0145     {
0146         // printf("tls ready read outgoing\n");
0147         QByteArray buf = tls->readOutgoing();
0148         // printf("%d bytes\n", buf.size());
0149         sock->write(buf);
0150     }
0151 
0152     void tls_closed()
0153     {
0154         // printf("tls closed\n");
0155     }
0156 
0157     void tls_error()
0158     {
0159         // printf("tls error\n");
0160     }
0161 };
0162 
0163 TLSSocket::TLSSocket(QObject *parent)
0164     : QTcpSocket(parent)
0165 {
0166     d = new Private(this);
0167 }
0168 
0169 TLSSocket::~TLSSocket()
0170 {
0171     delete d;
0172 }
0173 
0174 void TLSSocket::connectToHostEncrypted(const QString &host, quint16 port)
0175 {
0176     d->host = host;
0177     setOpenMode(QIODevice::ReadWrite);
0178     d->sock->connectToHost(host, port);
0179 }
0180 
0181 QCA::TLS *TLSSocket::tls()
0182 {
0183     return d->tls;
0184 }
0185 
0186 bool TLSSocket::waitForReadyRead(int msecs)
0187 {
0188     /*if(d->readbuf.isEmpty())
0189         return false;
0190 
0191     if(d->tls->bytesAvailable() == 0)
0192         return false;*/
0193 
0194     return d->waitForReadyRead(msecs);
0195 }
0196 
0197 qint64 TLSSocket::readData(char *data, qint64 maxlen)
0198 {
0199     if (!d->error)
0200         d->readbuf += d->tls->read();
0201     unsigned char *p        = (unsigned char *)d->readbuf.data();
0202     int            size     = d->readbuf.size();
0203     int            readsize = qMin(size, (int)maxlen);
0204     int            newsize  = size - readsize;
0205     memcpy(data, p, readsize);
0206     memmove(p, p + readsize, newsize);
0207     d->readbuf.resize(newsize);
0208     return readsize;
0209 }
0210 
0211 qint64 TLSSocket::writeData(const char *data, qint64 len)
0212 {
0213     // printf("write %d bytes\n", (int)len);
0214     QByteArray buf(data, len);
0215     if (d->encrypted)
0216         d->tls->write(buf);
0217     else
0218         d->writebuf += buf;
0219     return len;
0220 }
0221 
0222 #include "tlssocket.moc"