File indexing completed on 2024-10-13 10:11:14
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"