2
* securestream.cpp - combines a ByteStream with TLS and SASL
3
* Copyright (C) 2004 Justin Karneges
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 2.1 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
Note: SecureStream depends on the underlying security layers to signal
23
plain-to-encrypted results immediately (as opposed to waiting for the
24
event loop) so that the user cannot add/remove security layers during
25
this conversion moment. QCA::TLS and QCA::SASL behave as expected,
26
but future layers might not.
29
#include"securestream.h"
31
#include<qguardedptr.h>
32
#include<qvaluelist.h>
39
//----------------------------------------------------------------------------
41
//----------------------------------------------------------------------------
54
void addPlain(int plain);
55
void specifyEncoded(int encoded, int plain);
56
int finished(int encoded);
59
QValueList<Item> list;
62
LayerTracker::LayerTracker()
67
void LayerTracker::reset()
73
void LayerTracker::addPlain(int plain)
78
void LayerTracker::specifyEncoded(int encoded, int plain)
80
// can't specify more bytes than we have
90
int LayerTracker::finished(int encoded)
93
for(QValueList<Item>::Iterator it = list.begin(); it != list.end();) {
97
if(encoded < i.encoded) {
102
encoded -= i.encoded;
104
it = list.remove(it);
109
//----------------------------------------------------------------------------
111
//----------------------------------------------------------------------------
112
class SecureLayer : public QObject
116
enum { TLS, SASL, TLSH };
121
#ifdef USE_TLSHANDLER
122
XMPP::TLSHandler *tlsHandler;
129
SecureLayer(QCA::TLS *t)
134
connect(p.tls, SIGNAL(handshaken()), SLOT(tls_handshaken()));
135
connect(p.tls, SIGNAL(readyRead()), SLOT(tls_readyRead()));
136
connect(p.tls, SIGNAL(readyReadOutgoing(int)), SLOT(tls_readyReadOutgoing(int)));
137
connect(p.tls, SIGNAL(closed()), SLOT(tls_closed()));
138
connect(p.tls, SIGNAL(error(int)), SLOT(tls_error(int)));
141
SecureLayer(QCA::SASL *s)
146
connect(p.sasl, SIGNAL(readyRead()), SLOT(sasl_readyRead()));
147
connect(p.sasl, SIGNAL(readyReadOutgoing(int)), SLOT(sasl_readyReadOutgoing(int)));
148
connect(p.sasl, SIGNAL(error(int)), SLOT(sasl_error(int)));
151
#ifdef USE_TLSHANDLER
152
SecureLayer(XMPP::TLSHandler *t)
157
connect(p.tlsHandler, SIGNAL(success()), SLOT(tlsHandler_success()));
158
connect(p.tlsHandler, SIGNAL(fail()), SLOT(tlsHandler_fail()));
159
connect(p.tlsHandler, SIGNAL(closed()), SLOT(tlsHandler_closed()));
160
connect(p.tlsHandler, SIGNAL(readyRead(const QByteArray &)), SLOT(tlsHandler_readyRead(const QByteArray &)));
161
connect(p.tlsHandler, SIGNAL(readyReadOutgoing(const QByteArray &, int)), SLOT(tlsHandler_readyReadOutgoing(const QByteArray &, int)));
171
void write(const QByteArray &a)
173
layer.addPlain(a.size());
175
case TLS: { p.tls->write(a); break; }
176
case SASL: { p.sasl->write(a); break; }
177
#ifdef USE_TLSHANDLER
178
case TLSH: { p.tlsHandler->write(a); break; }
183
void writeIncoming(const QByteArray &a)
186
case TLS: { p.tls->writeIncoming(a); break; }
187
case SASL: { p.sasl->writeIncoming(a); break; }
188
#ifdef USE_TLSHANDLER
189
case TLSH: { p.tlsHandler->writeIncoming(a); break; }
194
int finished(int plain)
198
// deal with prebytes (bytes sent prior to this security layer)
200
if(prebytes >= plain) {
212
// put remainder into the layer tracker
213
if(type == SASL || tls_done)
214
written += layer.finished(plain);
220
void tlsHandshaken();
221
void tlsClosed(const QByteArray &);
222
void readyRead(const QByteArray &);
223
void needWrite(const QByteArray &);
227
void tls_handshaken()
235
QByteArray a = p.tls->read();
239
void tls_readyReadOutgoing(int plainBytes)
241
QByteArray a = p.tls->readOutgoing();
243
layer.specifyEncoded(a.size(), plainBytes);
249
QByteArray a = p.tls->readUnprocessed();
253
void tls_error(int x)
258
void sasl_readyRead()
260
QByteArray a = p.sasl->read();
264
void sasl_readyReadOutgoing(int plainBytes)
266
QByteArray a = p.sasl->readOutgoing();
267
layer.specifyEncoded(a.size(), plainBytes);
271
void sasl_error(int x)
276
#ifdef USE_TLSHANDLER
277
void tlsHandler_success()
283
void tlsHandler_fail()
288
void tlsHandler_closed()
290
tlsClosed(QByteArray());
293
void tlsHandler_readyRead(const QByteArray &a)
298
void tlsHandler_readyReadOutgoing(const QByteArray &a, int plainBytes)
301
layer.specifyEncoded(a.size(), plainBytes);
307
#include"securestream.moc"
309
class SecureStream::Private
313
QPtrList<SecureLayer> layers;
321
QPtrListIterator<SecureLayer> it(layers);
322
for(SecureLayer *s; (s = it.current()); ++it) {
323
if(s->type == SecureLayer::TLS
324
#ifdef USE_TLSHANDLER
325
|| s->type == SecureLayer::TLSH
334
bool haveSASL() const
336
QPtrListIterator<SecureLayer> it(layers);
337
for(SecureLayer *s; (s = it.current()); ++it) {
338
if(s->type == SecureLayer::SASL)
345
SecureStream::SecureStream(ByteStream *s)
351
connect(d->bs, SIGNAL(readyRead()), SLOT(bs_readyRead()));
352
connect(d->bs, SIGNAL(bytesWritten(int)), SLOT(bs_bytesWritten(int)));
354
d->layers.setAutoDelete(true);
357
d->topInProgress = false;
360
SecureStream::~SecureStream()
365
void SecureStream::linkLayer(QObject *s)
367
connect(s, SIGNAL(tlsHandshaken()), SLOT(layer_tlsHandshaken()));
368
connect(s, SIGNAL(tlsClosed(const QByteArray &)), SLOT(layer_tlsClosed(const QByteArray &)));
369
connect(s, SIGNAL(readyRead(const QByteArray &)), SLOT(layer_readyRead(const QByteArray &)));
370
connect(s, SIGNAL(needWrite(const QByteArray &)), SLOT(layer_needWrite(const QByteArray &)));
371
connect(s, SIGNAL(error(int)), SLOT(layer_error(int)));
374
int SecureStream::calcPrebytes() const
377
QPtrListIterator<SecureLayer> it(d->layers);
378
for(SecureLayer *s; (s = it.current()); ++it)
380
return (d->pending - x);
383
void SecureStream::startTLSClient(QCA::TLS *t, const QByteArray &spare)
385
if(!d->active || d->topInProgress || d->haveTLS())
388
SecureLayer *s = new SecureLayer(t);
389
s->prebytes = calcPrebytes();
392
d->topInProgress = true;
397
void SecureStream::startTLSServer(QCA::TLS *t, const QByteArray &spare)
399
if(!d->active || d->topInProgress || d->haveTLS())
402
SecureLayer *s = new SecureLayer(t);
403
s->prebytes = calcPrebytes();
406
d->topInProgress = true;
411
void SecureStream::setLayerSASL(QCA::SASL *sasl, const QByteArray &spare)
413
if(!d->active || d->topInProgress || d->haveSASL())
416
SecureLayer *s = new SecureLayer(sasl);
417
s->prebytes = calcPrebytes();
424
#ifdef USE_TLSHANDLER
425
void SecureStream::startTLSClient(XMPP::TLSHandler *t, const QString &server, const QByteArray &spare)
427
if(!d->active || d->topInProgress || d->haveTLS())
430
SecureLayer *s = new SecureLayer(t);
431
s->prebytes = calcPrebytes();
434
d->topInProgress = true;
436
// unlike QCA::TLS, XMPP::TLSHandler has no return value
437
s->p.tlsHandler->startClient(server);
443
void SecureStream::closeTLS()
445
SecureLayer *s = d->layers.getLast();
447
if(s->type == SecureLayer::TLS)
452
int SecureStream::errorCode() const
457
bool SecureStream::isOpen() const
462
void SecureStream::write(const QByteArray &a)
467
d->pending += a.size();
469
// send to the last layer
470
SecureLayer *s = d->layers.getLast();
477
int SecureStream::bytesToWrite() const
482
void SecureStream::bs_readyRead()
484
QByteArray a = d->bs->read();
486
// send to the first layer
487
SecureLayer *s = d->layers.getFirst();
494
void SecureStream::bs_bytesWritten(int bytes)
496
QPtrListIterator<SecureLayer> it(d->layers);
497
for(SecureLayer *s; (s = it.current()); ++it)
498
bytes = s->finished(bytes);
506
void SecureStream::layer_tlsHandshaken()
508
d->topInProgress = false;
512
void SecureStream::layer_tlsClosed(const QByteArray &)
519
void SecureStream::layer_readyRead(const QByteArray &a)
521
SecureLayer *s = (SecureLayer *)sender();
522
QPtrListIterator<SecureLayer> it(d->layers);
523
while(it.current() != s)
535
void SecureStream::layer_needWrite(const QByteArray &a)
537
SecureLayer *s = (SecureLayer *)sender();
538
QPtrListIterator<SecureLayer> it(d->layers);
539
while(it.current() != s)
551
void SecureStream::layer_error(int x)
553
SecureLayer *s = (SecureLayer *)sender();
558
if(type == SecureLayer::TLS)
560
else if(type == SecureLayer::SASL)
562
#ifdef USE_TLSHANDLER
563
else if(type == SecureLayer::TLSH)
568
void SecureStream::insertData(const QByteArray &a)
571
SecureLayer *s = d->layers.getLast();
579
void SecureStream::writeRawData(const QByteArray &a)
584
void SecureStream::incomingData(const QByteArray &a)