/* securestream.h - Kopete Groupwise Protocol Combines a ByteStream with TLS and SASL Copyright (c) 2004 SUSE Linux AG http://www.suse.com Based on Iris, Copyright (C) 2003 Justin Karneges Kopete (c) 2002-2004 by the Kopete developers ************************************************************************* * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License, or (at your option) any later version. * * * ************************************************************************* */ /* Note: SecureStream depends on the underlying security layers to signal plain-to-encrypted results immediately (as opposed to waiting for the event loop) so that the user cannot add/remove security layers during this conversion moment. TQCA::TLS and TQCA::SASL behave as expected, but future layers might not. */ #include #include #include #include "securestream.h" //---------------------------------------------------------------------------- // LayerTracker //---------------------------------------------------------------------------- LayerTracker::LayerTracker() { p = 0; } void LayerTracker::reset() {USE_TLSHANDLER p = 0; list.clear(); } void LayerTracker::addPlain(int plain) { p += plain; } void LayerTracker::specifyEncoded(int encoded, int plain) { // can't specify more bytes than we have if(plain > p) plain = p; p -= plain; Item i; i.plain = plain; i.encoded = encoded; list += i; } int LayerTracker::finished(int encoded) { int plain = 0; for(TQValueList::Iterator it = list.begin(); it != list.end();) { Item &i = *it; // not enough? if(encoded < i.encoded) { i.encoded -= encoded; break; } encoded -= i.encoded; plain += i.plain; it = list.remove(it); } return plain; } //---------------------------------------------------------------------------- // SecureStream //---------------------------------------------------------------------------- SecureLayer::SecureLayer(TQCA::TLS *t) { type = TLS; p.tls = t; init(); connect(p.tls, TQT_SIGNAL(handshaken()), TQT_SLOT(tls_handshaken())); connect(p.tls, TQT_SIGNAL(readyRead()), TQT_SLOT(tls_readyRead())); connect(p.tls, TQT_SIGNAL(readyReadOutgoing(int)), TQT_SLOT(tls_readyReadOutgoing(int))); connect(p.tls, TQT_SIGNAL(closed()), TQT_SLOT(tls_closed())); connect(p.tls, TQT_SIGNAL(error(int)), TQT_SLOT(tls_error(int))); } SecureLayer::SecureLayer(TQCA::SASL *s) { type = SASL; p.sasl = s; init(); connect(p.sasl, TQT_SIGNAL(readyRead()), TQT_SLOT(sasl_readyRead())); connect(p.sasl, TQT_SIGNAL(readyReadOutgoing(int)), TQT_SLOT(sasl_readyReadOutgoing(int))); connect(p.sasl, TQT_SIGNAL(error(int)), TQT_SLOT(sasl_error(int))); } #ifdef USE_TLSHANDLER SecureLayer::SecureLayer(TLSHandler *t) { type = TLSH; p.tlsHandler = t; init(); connect(p.tlsHandler, TQT_SIGNAL(success()), TQT_SLOT(tlsHandler_success())); connect(p.tlsHandler, TQT_SIGNAL(fail()), TQT_SLOT(tlsHandler_fail())); connect(p.tlsHandler, TQT_SIGNAL(closed()), TQT_SLOT(tlsHandler_closed())); connect(p.tlsHandler, TQT_SIGNAL(readyRead(const TQByteArray &)), TQT_SLOT(tlsHandler_readyRead(const TQByteArray &))); connect(p.tlsHandler, TQT_SIGNAL(readyReadOutgoing(const TQByteArray &, int)), TQT_SLOT(tlsHandler_readyReadOutgoing(const TQByteArray &, int))); } #endif void SecureLayer::init() { tls_done = false; prebytes = 0; } void SecureLayer::write(const TQByteArray &a) { layer.addPlain(a.size()); switch(type) { case TLS: { p.tls->write(a); break; } case SASL: { p.sasl->write(a); break; } #ifdef USE_TLSHANDLER case TLSH: { p.tlsHandler->write(a); break; } #endif } } void SecureLayer::writeIncoming(const TQByteArray &a) { switch(type) { case TLS: { p.tls->writeIncoming(a); break; } case SASL: { p.sasl->writeIncoming(a); break; } #ifdef USE_TLSHANDLER case TLSH: { p.tlsHandler->writeIncoming(a); break; } #endif } } int SecureLayer::finished(int plain) { int written = 0; // deal with prebytes (bytes sent prior to this security layer) if(prebytes > 0) { if(prebytes >= plain) { written += plain; prebytes -= plain; plain = 0; } else { written += prebytes; plain -= prebytes; prebytes = 0; } } // put remainder into the layer tracker if(type == SASL || tls_done) written += layer.finished(plain); return written; } void SecureLayer::tls_handshaken() { tls_done = true; tlsHandshaken(); } void SecureLayer::tls_readyRead() { TQByteArray a = p.tls->read(); readyRead(a); } void SecureLayer::tls_readyReadOutgoing(int plainBytes) { TQByteArray a = p.tls->readOutgoing(); if(tls_done) layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } void SecureLayer::tls_closed() { TQByteArray a = p.tls->readUnprocessed(); tlsClosed(a); } void SecureLayer::tls_error(int x) { error(x); } void SecureLayer::sasl_readyRead() { TQByteArray a = p.sasl->read(); readyRead(a); } void SecureLayer::sasl_readyReadOutgoing(int plainBytes) { TQByteArray a = p.sasl->readOutgoing(); layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } void SecureLayer::sasl_error(int x) { error(x); } #ifdef USE_TLSHANDLER void SecureLayer::tlsHandler_success() { tls_done = true; tlsHandshaken(); } void SecureLayer::tlsHandler_fail() { error(0); } void SecureLayer::tlsHandler_closed() { tlsClosed(TQByteArray()); } void SecureLayer::tlsHandler_readyRead(const TQByteArray &a) { readyRead(a); } void SecureLayer::tlsHandler_readyReadOutgoing(const TQByteArray &a, int plainBytes) { if(tls_done) layer.specifyEncoded(a.size(), plainBytes); needWrite(a); } #endif class SecureStream::Private { public: ByteStream *bs; TQPtrList layers; int pending; int errorCode; bool active; bool topInProgress; bool haveTLS() const { TQPtrListIterator it(layers); for(SecureLayer *s; (s = it.current()); ++it) { if(s->type == SecureLayer::TLS #ifdef USE_TLSHANDLER || s->type == SecureLayer::TLSH #endif ) { return true; } } return false; } bool haveSASL() const { TQPtrListIterator it(layers); for(SecureLayer *s; (s = it.current()); ++it) { if(s->type == SecureLayer::SASL) return true; } return false; } }; SecureStream::SecureStream(ByteStream *s) :ByteStream(0) { d = new Private; d->bs = s; connect(d->bs, TQT_SIGNAL(readyRead()), TQT_SLOT(bs_readyRead())); connect(d->bs, TQT_SIGNAL(bytesWritten(int)), TQT_SLOT(bs_bytesWritten(int))); d->layers.setAutoDelete(true); d->pending = 0; d->active = true; d->topInProgress = false; } SecureStream::~SecureStream() { delete d; } void SecureStream::linkLayer(TQObject *s) { connect(s, TQT_SIGNAL(tlsHandshaken()), TQT_SLOT(layer_tlsHandshaken())); connect(s, TQT_SIGNAL(tlsClosed(const TQByteArray &)), TQT_SLOT(layer_tlsClosed(const TQByteArray &))); connect(s, TQT_SIGNAL(readyRead(const TQByteArray &)), TQT_SLOT(layer_readyRead(const TQByteArray &))); connect(s, TQT_SIGNAL(needWrite(const TQByteArray &)), TQT_SLOT(layer_needWrite(const TQByteArray &))); connect(s, TQT_SIGNAL(error(int)), TQT_SLOT(layer_error(int))); } int SecureStream::calcPrebytes() const { int x = 0; TQPtrListIterator it(d->layers); for(SecureLayer *s; (s = it.current()); ++it) x += s->prebytes; return (d->pending - x); } void SecureStream::startTLSClient(TQCA::TLS *t, const TQByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; insertData(spare); } void SecureStream::startTLSServer(TQCA::TLS *t, const TQByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; insertData(spare); } void SecureStream::setLayerSASL(TQCA::SASL *sasl, const TQByteArray &spare) { if(!d->active || d->topInProgress || d->haveSASL()) return; SecureLayer *s = new SecureLayer(sasl); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); insertData(spare); } #ifdef USE_TLSHANDLER void SecureStream::startTLSClient(TLSHandler *t, const TQString &server, const TQByteArray &spare) { if(!d->active || d->topInProgress || d->haveTLS()) return; SecureLayer *s = new SecureLayer(t); s->prebytes = calcPrebytes(); linkLayer(s); d->layers.append(s); d->topInProgress = true; // unlike TQCA::TLS, TLSHandler has no return value s->p.tlsHandler->startClient(server); insertData(spare); } #endif void SecureStream::closeTLS() { SecureLayer *s = d->layers.getLast(); if(s) { if(s->type == SecureLayer::TLS) s->p.tls->close(); } } int SecureStream::errorCode() const { return d->errorCode; } bool SecureStream::isOpen() const { return d->active; } void SecureStream::write(const TQByteArray &a) { if(!isOpen()) return; d->pending += a.size(); // send to the last layer SecureLayer *s = d->layers.getLast(); if(s) s->write(a); else writeRawData(a); } int SecureStream::bytesToWrite() const { return d->pending; } void SecureStream::bs_readyRead() { TQByteArray a = d->bs->read(); // send to the first layer SecureLayer *s = d->layers.getFirst(); if(s) s->writeIncoming(a); else incomingData(a); } void SecureStream::bs_bytesWritten(int bytes) { TQPtrListIterator it(d->layers); for(SecureLayer *s; (s = it.current()); ++it) bytes = s->finished(bytes); if(bytes > 0) { d->pending -= bytes; bytesWritten(bytes); } } void SecureStream::layer_tlsHandshaken() { d->topInProgress = false; tlsHandshaken(); } void SecureStream::layer_tlsClosed(const TQByteArray &) { d->active = false; d->layers.clear(); tlsClosed(); } void SecureStream::layer_readyRead(const TQByteArray &a) { SecureLayer *s = (SecureLayer *)sender(); TQPtrListIterator it(d->layers); while(it.current() != s) ++it; // pass upwards ++it; s = it.current(); if(s) s->writeIncoming(a); else incomingData(a); } void SecureStream::layer_needWrite(const TQByteArray &a) { SecureLayer *s = (SecureLayer *)sender(); TQPtrListIterator it(d->layers); while(it.current() != s) ++it; // pass downwards --it; s = it.current(); if(s) s->write(a); else writeRawData(a); } void SecureStream::layer_error(int x) { SecureLayer *s = (SecureLayer *)sender(); int type = s->type; d->errorCode = x; d->active = false; d->layers.clear(); if(type == SecureLayer::TLS) error(ErrTLS); else if(type == SecureLayer::SASL) error(ErrSASL); #ifdef USE_TLSHANDLER else if(type == SecureLayer::TLSH) error(ErrTLS); #endif } void SecureStream::insertData(const TQByteArray &a) { if(!a.isEmpty()) { SecureLayer *s = d->layers.getLast(); if(s) s->writeIncoming(a); else incomingData(a); } } void SecureStream::writeRawData(const TQByteArray &a) { d->bs->write(a); } void SecureStream::incomingData(const TQByteArray &a) { appendRead(a); //tqDebug( "SecureStream::incomingData() got %i bytes ", a.size() ); if(bytesAvailable()) readyRead(); } #include "securestream.moc"