00001 /* 00002 Copyright (C) 2007 Justin Karneges <justin@affinix.com> 00003 00004 Permission is hereby granted, free of charge, to any person obtaining a copy 00005 of this software and associated documentation files (the "Software"), to deal 00006 in the Software without restriction, including without limitation the rights 00007 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00008 copies of the Software, and to permit persons to whom the Software is 00009 furnished to do so, subject to the following conditions: 00010 00011 The above copyright notice and this permission notice shall be included in 00012 all copies or substantial portions of the Software. 00013 00014 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00015 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00016 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00017 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 00018 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 00019 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00020 */ 00021 00022 #include "tlssocket.h" 00023 00024 class TLSSocket::Private : public QObject 00025 { 00026 Q_OBJECT 00027 public: 00028 TLSSocket *q; 00029 QTcpSocket *sock; 00030 QCA::TLS *tls; 00031 QString host; 00032 bool encrypted; 00033 bool error, done; 00034 QByteArray readbuf, writebuf; 00035 QCA::Synchronizer sync; 00036 bool waiting; 00037 00038 Private(TLSSocket *_q) : QObject(_q), q(_q), sync(_q) 00039 { 00040 sock = new QTcpSocket(this); 00041 connect(sock, SIGNAL(connected()), SLOT(sock_connected())); 00042 connect(sock, SIGNAL(readyRead()), SLOT(sock_readyRead())); 00043 connect(sock, SIGNAL(bytesWritten(qint64)), SLOT(sock_bytesWritten(qint64))); 00044 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), SLOT(sock_error(QAbstractSocket::SocketError))); 00045 00046 tls = new QCA::TLS(this); 00047 connect(tls, SIGNAL(handshaken()), SLOT(tls_handshaken())); 00048 connect(tls, SIGNAL(readyRead()), SLOT(tls_readyRead())); 00049 connect(tls, SIGNAL(readyReadOutgoing()), SLOT(tls_readyReadOutgoing())); 00050 connect(tls, SIGNAL(closed()), SLOT(tls_closed())); 00051 connect(tls, SIGNAL(error()), SLOT(tls_error())); 00052 tls->setTrustedCertificates(QCA::systemStore()); 00053 encrypted = false; 00054 error = false; 00055 waiting = false; 00056 done = false; 00057 } 00058 00059 bool waitForReadyRead(int msecs) 00060 { 00061 waiting = true; 00062 bool ok = sync.waitForCondition(msecs); 00063 //while(1) 00064 // QCoreApplication::instance()->processEvents(); 00065 waiting = false; 00066 if(error || done) 00067 return false; 00068 return ok; 00069 } 00070 00071 private slots: 00072 void sock_connected() 00073 { 00074 //printf("sock connected\n"); 00075 tls->startClient(host); 00076 } 00077 00078 void sock_readyRead() 00079 { 00080 //printf("sock ready read\n"); 00081 QByteArray buf = sock->readAll(); 00082 //printf("%d bytes\n", buf.size()); 00083 tls->writeIncoming(buf); 00084 } 00085 00086 void sock_bytesWritten(qint64 x) 00087 { 00088 Q_UNUSED(x); 00089 //printf("sock bytes written: %d\n", (int)x); 00090 } 00091 00092 void sock_error(QAbstractSocket::SocketError x) 00093 { 00094 //printf("sock error: %d\n", x); 00095 Q_UNUSED(x); 00096 done = true; 00097 if(waiting) 00098 sync.conditionMet(); 00099 } 00100 00101 void tls_handshaken() 00102 { 00103 //printf("tls handshaken\n"); 00104 if(tls->peerIdentityResult() != QCA::TLS::Valid) 00105 { 00106 printf("not valid\n"); 00107 sock->abort(); 00108 tls->reset(); 00109 error = true; 00110 } 00111 else 00112 { 00113 //printf("valid\n"); 00114 encrypted = true; 00115 //printf("%d bytes in writebuf\n", writebuf.size()); 00116 if(!writebuf.isEmpty()) 00117 { 00118 //printf("[%s]\n", writebuf.data()); 00119 tls->write(writebuf); 00120 writebuf.clear(); 00121 } 00122 } 00123 if(waiting) 00124 sync.conditionMet(); 00125 } 00126 00127 void tls_readyRead() 00128 { 00129 //printf("tls ready read\n"); 00130 if(waiting) 00131 sync.conditionMet(); 00132 } 00133 00134 void tls_readyReadOutgoing() 00135 { 00136 //printf("tls ready read outgoing\n"); 00137 QByteArray buf = tls->readOutgoing(); 00138 //printf("%d bytes\n", buf.size()); 00139 sock->write(buf); 00140 } 00141 00142 void tls_closed() 00143 { 00144 //printf("tls closed\n"); 00145 } 00146 00147 void tls_error() 00148 { 00149 //printf("tls error\n"); 00150 } 00151 }; 00152 00153 TLSSocket::TLSSocket(QObject *parent) 00154 :QTcpSocket(parent) 00155 { 00156 d = new Private(this); 00157 00158 } 00159 00160 TLSSocket::~TLSSocket() 00161 { 00162 delete d; 00163 } 00164 00165 void TLSSocket::connectToHostEncrypted(const QString &host, quint16 port) 00166 { 00167 d->host = host; 00168 setOpenMode(QIODevice::ReadWrite); 00169 d->sock->connectToHost(host, port); 00170 } 00171 00172 QCA::TLS *TLSSocket::tls() 00173 { 00174 return d->tls; 00175 } 00176 00177 bool TLSSocket::waitForReadyRead(int msecs) 00178 { 00179 /*if(d->readbuf.isEmpty()) 00180 return false; 00181 00182 if(d->tls->bytesAvailable() == 0) 00183 return false;*/ 00184 00185 return d->waitForReadyRead(msecs); 00186 } 00187 00188 qint64 TLSSocket::readData(char *data, qint64 maxlen) 00189 { 00190 if(!d->error) 00191 d->readbuf += d->tls->read(); 00192 unsigned char *p = (unsigned char *)d->readbuf.data(); 00193 int size = d->readbuf.size(); 00194 int readsize = qMin(size, (int)maxlen); 00195 int newsize = size - readsize; 00196 memcpy(data, p, readsize); 00197 memmove(p, p + readsize, newsize); 00198 d->readbuf.resize(newsize); 00199 return readsize; 00200 } 00201 00202 qint64 TLSSocket::writeData(const char *data, qint64 len) 00203 { 00204 //printf("write %d bytes\n", (int)len); 00205 QByteArray buf(data, len); 00206 if(d->encrypted) 00207 d->tls->write(buf); 00208 else 00209 d->writebuf += buf; 00210 return len; 00211 } 00212 00213 #include "tlssocket.moc"