tlssocket.cpp

The code below shows how to create a socket that can operate over an Transport Layer Security (TLS, also known as SSL) connection.
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 #ifndef TLSSOCKET_H
00023 
00024 #include <QtCrypto>
00025 #include <QTcpSocket>
00026 
00027 class TLSSocket : public QTcpSocket
00028 {
00029 public:
00030         TLSSocket(QObject *parent = 0);
00031         ~TLSSocket();
00032 
00033         void connectToHostEncrypted(const QString &host, quint16 port);
00034         QCA::TLS *tls();
00035 
00036         bool waitForReadyRead(int msecs = -1);
00037 
00038 protected:
00039         // from qiodevice
00040         virtual qint64 readData(char *data, qint64 maxlen);
00041         virtual qint64 writeData(const char *data, qint64 len);
00042 
00043 private:
00044         class Private;
00045         friend class Private;
00046         Private *d;
00047 };
00048 
00049 #endif
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 #include <QCoreApplication>
00025 
00026 int main(int argc, char **argv)
00027 {
00028         QCA::Initializer init;
00029         QCoreApplication qapp(argc, argv);
00030 
00031         TLSSocket socket;
00032         socket.connectToHostEncrypted("www.paypal.com", 443);
00033         socket.write("GET / HTTP/1.0\r\n\r\n");
00034         while(socket.waitForReadyRead())
00035                 printf("%s", socket.readAll().data());
00036 
00037         return 0;
00038 }

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"

Generated on Thu Sep 6 19:13:35 2007 for Qt Cryptographic Architecture by  doxygen 1.5.2