File indexing completed on 2024-06-02 04:07:03
0001 /* 0002 * securestream.cpp - combines a ByteStream with TLS and SASL 0003 * Copyright (C) 2004 Justin Karneges 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * either version 2 0009 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0019 * 0020 */ 0021 0022 /* 0023 Note: SecureStream depends on the underlying security layers to signal 0024 plain-to-encrypted results immediately (as opposed to waiting for the 0025 event loop) so that the user cannot add/remove security layers during 0026 this conversion moment. QCA::TLS and QCA::SASL behave as expected, 0027 but future layers might not. 0028 */ 0029 0030 #include "securestream.h" 0031 0032 #include <QPointer> 0033 #include <QList> 0034 #include <QTimer> 0035 0036 #ifdef USE_TLSHANDLER 0037 #include "xmpp.h" 0038 #endif 0039 #include "compressionhandler.h" 0040 0041 //---------------------------------------------------------------------------- 0042 // LayerTracker 0043 //---------------------------------------------------------------------------- 0044 class LayerTracker 0045 { 0046 public: 0047 struct Item 0048 { 0049 int plain; 0050 int encoded; 0051 }; 0052 0053 LayerTracker(); 0054 0055 void reset(); 0056 void addPlain(int plain); 0057 void specifyEncoded(int encoded, int plain); 0058 int finished(int encoded); 0059 0060 int p; 0061 QList<Item> list; 0062 }; 0063 0064 LayerTracker::LayerTracker() 0065 { 0066 p = 0; 0067 } 0068 0069 void LayerTracker::reset() 0070 { 0071 p = 0; 0072 list.clear(); 0073 } 0074 0075 void LayerTracker::addPlain(int plain) 0076 { 0077 p += plain; 0078 } 0079 0080 void LayerTracker::specifyEncoded(int encoded, int plain) 0081 { 0082 // can't specify more bytes than we have 0083 if(plain > p) 0084 plain = p; 0085 p -= plain; 0086 Item i; 0087 i.plain = plain; 0088 i.encoded = encoded; 0089 list += i; 0090 } 0091 0092 int LayerTracker::finished(int encoded) 0093 { 0094 int plain = 0; 0095 for(QList<Item>::Iterator it = list.begin(); it != list.end();) { 0096 Item &i = *it; 0097 0098 // not enough? 0099 if(encoded < i.encoded) { 0100 i.encoded -= encoded; 0101 break; 0102 } 0103 0104 encoded -= i.encoded; 0105 plain += i.plain; 0106 it = list.erase(it); 0107 } 0108 return plain; 0109 } 0110 0111 //---------------------------------------------------------------------------- 0112 // SecureStream 0113 //---------------------------------------------------------------------------- 0114 class SecureLayer : public QObject 0115 { 0116 Q_OBJECT 0117 public: 0118 enum { TLS, SASL, TLSH, Compression }; 0119 int type; 0120 union { 0121 QCA::TLS *tls; 0122 QCA::SASL *sasl; 0123 #ifdef USE_TLSHANDLER 0124 XMPP::TLSHandler *tlsHandler; 0125 #endif 0126 CompressionHandler *compressionHandler; 0127 } p; 0128 LayerTracker layer; 0129 bool tls_done; 0130 int prebytes; 0131 0132 SecureLayer(QCA::TLS *t) 0133 { 0134 type = TLS; 0135 p.tls = t; 0136 init(); 0137 connect(p.tls, &QCA::TLS::handshaken, this, &SecureLayer::tls_handshaken); 0138 connect(p.tls, &QCA::SecureLayer::readyRead, this, &SecureLayer::tls_readyRead); 0139 connect(p.tls, SIGNAL(readyReadOutgoing(int)), SLOT(tls_readyReadOutgoing(int))); 0140 connect(p.tls, &QCA::SecureLayer::closed, this, &SecureLayer::tls_closed); 0141 connect(p.tls, SIGNAL(error(int)), SLOT(tls_error(int))); 0142 } 0143 0144 SecureLayer(QCA::SASL *s) 0145 { 0146 type = SASL; 0147 p.sasl = s; 0148 init(); 0149 connect(p.sasl, &QCA::SecureLayer::readyRead, this, &SecureLayer::sasl_readyRead); 0150 connect(p.sasl, &QCA::SecureLayer::readyReadOutgoing, this, &SecureLayer::sasl_readyReadOutgoing); 0151 connect(p.sasl, &QCA::SecureLayer::error, this, &SecureLayer::sasl_error); 0152 } 0153 0154 SecureLayer(CompressionHandler *t) 0155 { 0156 t->setParent(this); // automatically clean up CompressionHandler when SecureLayer is destroyed 0157 type = Compression; 0158 p.compressionHandler = t; 0159 init(); 0160 connect(p.compressionHandler, &CompressionHandler::readyRead, this, &SecureLayer::compressionHandler_readyRead); 0161 connect(p.compressionHandler, &CompressionHandler::readyReadOutgoing, this, &SecureLayer::compressionHandler_readyReadOutgoing); 0162 connect(p.compressionHandler, &CompressionHandler::error, this, &SecureLayer::compressionHandler_error); 0163 } 0164 0165 #ifdef USE_TLSHANDLER 0166 SecureLayer(XMPP::TLSHandler *t) 0167 { 0168 type = TLSH; 0169 p.tlsHandler = t; 0170 init(); 0171 connect(p.tlsHandler, &XMPP::TLSHandler::success, this, &SecureLayer::tlsHandler_success); 0172 connect(p.tlsHandler, &XMPP::TLSHandler::fail, this, &SecureLayer::tlsHandler_fail); 0173 connect(p.tlsHandler, &XMPP::TLSHandler::closed, this, &SecureLayer::tlsHandler_closed); 0174 connect(p.tlsHandler, &XMPP::TLSHandler::readyRead, this, &SecureLayer::tlsHandler_readyRead); 0175 connect(p.tlsHandler, &XMPP::TLSHandler::readyReadOutgoing, this, &SecureLayer::tlsHandler_readyReadOutgoing); 0176 } 0177 #endif 0178 0179 void init() 0180 { 0181 tls_done = false; 0182 prebytes = 0; 0183 } 0184 0185 void write(const QByteArray &a) 0186 { 0187 layer.addPlain(a.size()); 0188 switch(type) { 0189 case TLS: { p.tls->write(a); break; } 0190 case SASL: { p.sasl->write(a); break; } 0191 #ifdef USE_TLSHANDLER 0192 case TLSH: { p.tlsHandler->write(a); break; } 0193 #endif 0194 case Compression: { p.compressionHandler->write(a); break; } 0195 } 0196 } 0197 0198 void writeIncoming(const QByteArray &a) 0199 { 0200 switch(type) { 0201 case TLS: { p.tls->writeIncoming(a); break; } 0202 case SASL: { p.sasl->writeIncoming(a); break; } 0203 #ifdef USE_TLSHANDLER 0204 case TLSH: { p.tlsHandler->writeIncoming(a); break; } 0205 #endif 0206 case Compression: { p.compressionHandler->writeIncoming(a); break; } 0207 } 0208 } 0209 0210 int finished(int plain) 0211 { 0212 int written = 0; 0213 0214 // deal with prebytes (bytes sent prior to this security layer) 0215 if(prebytes > 0) { 0216 if(prebytes >= plain) { 0217 written += plain; 0218 prebytes -= plain; 0219 plain = 0; 0220 } 0221 else { 0222 written += prebytes; 0223 plain -= prebytes; 0224 prebytes = 0; 0225 } 0226 } 0227 0228 // put remainder into the layer tracker 0229 if(type == SASL || tls_done) 0230 written += layer.finished(plain); 0231 0232 return written; 0233 } 0234 0235 signals: 0236 void tlsHandshaken(); 0237 void tlsClosed(const QByteArray &); 0238 void readyRead(const QByteArray &); 0239 void needWrite(const QByteArray &); 0240 void error(int); 0241 0242 private slots: 0243 void tls_handshaken() 0244 { 0245 tls_done = true; 0246 tlsHandshaken(); 0247 } 0248 0249 void tls_readyRead() 0250 { 0251 QByteArray a = p.tls->read(); 0252 readyRead(a); 0253 } 0254 0255 void tls_readyReadOutgoing(int plainBytes) 0256 { 0257 QByteArray a = p.tls->readOutgoing(); 0258 if(tls_done) 0259 layer.specifyEncoded(a.size(), plainBytes); 0260 needWrite(a); 0261 } 0262 0263 void tls_closed() 0264 { 0265 QByteArray a = p.tls->readUnprocessed(); 0266 tlsClosed(a); 0267 } 0268 0269 void tls_error(int x) 0270 { 0271 error(x); 0272 } 0273 0274 void sasl_readyRead() 0275 { 0276 QByteArray a = p.sasl->read(); 0277 readyRead(a); 0278 } 0279 0280 void sasl_readyReadOutgoing() 0281 { 0282 int plainBytes; 0283 QByteArray a = p.sasl->readOutgoing(&plainBytes); 0284 layer.specifyEncoded(a.size(), plainBytes); 0285 needWrite(a); 0286 } 0287 0288 void sasl_error() 0289 { 0290 error(p.sasl->errorCode()); 0291 } 0292 0293 void compressionHandler_readyRead() 0294 { 0295 QByteArray a = p.compressionHandler->read(); 0296 readyRead(a); 0297 } 0298 0299 void compressionHandler_readyReadOutgoing() 0300 { 0301 int plainBytes; 0302 QByteArray a = p.compressionHandler->readOutgoing(&plainBytes); 0303 layer.specifyEncoded(a.size(), plainBytes); 0304 needWrite(a); 0305 } 0306 0307 void compressionHandler_error() 0308 { 0309 error(p.compressionHandler->errorCode()); 0310 } 0311 0312 #ifdef USE_TLSHANDLER 0313 void tlsHandler_success() 0314 { 0315 tls_done = true; 0316 tlsHandshaken(); 0317 } 0318 0319 void tlsHandler_fail() 0320 { 0321 error(0); 0322 } 0323 0324 void tlsHandler_closed() 0325 { 0326 tlsClosed(QByteArray()); 0327 } 0328 0329 void tlsHandler_readyRead(const QByteArray &a) 0330 { 0331 readyRead(a); 0332 } 0333 0334 void tlsHandler_readyReadOutgoing(const QByteArray &a, int plainBytes) 0335 { 0336 if(tls_done) 0337 layer.specifyEncoded(a.size(), plainBytes); 0338 needWrite(a); 0339 } 0340 #endif 0341 }; 0342 0343 #include "securestream.moc" 0344 0345 class SecureStream::Private 0346 { 0347 public: 0348 ByteStream *bs; 0349 QList<SecureLayer*> layers; 0350 int pending; 0351 int errorCode; 0352 bool active; 0353 bool topInProgress; 0354 0355 bool haveTLS() const 0356 { 0357 foreach(SecureLayer *s, layers) { 0358 if(s->type == SecureLayer::TLS 0359 #ifdef USE_TLSHANDLER 0360 || s->type == SecureLayer::TLSH 0361 #endif 0362 ) { 0363 return true; 0364 } 0365 } 0366 return false; 0367 } 0368 0369 bool haveSASL() const 0370 { 0371 foreach(SecureLayer *s, layers) { 0372 if(s->type == SecureLayer::SASL) 0373 return true; 0374 } 0375 return false; 0376 } 0377 0378 bool haveCompress() const 0379 { 0380 foreach(SecureLayer *s, layers) { 0381 if(s->type == SecureLayer::Compression) 0382 return true; 0383 } 0384 return false; 0385 } 0386 }; 0387 0388 SecureStream::SecureStream(ByteStream *s) 0389 :ByteStream(0) 0390 { 0391 d = new Private; 0392 0393 d->bs = s; 0394 connect(d->bs, &ByteStream::readyRead, this, &SecureStream::bs_readyRead); 0395 connect(d->bs, &ByteStream::bytesWritten, this, &SecureStream::bs_bytesWritten); 0396 0397 d->pending = 0; 0398 d->active = true; 0399 d->topInProgress = false; 0400 } 0401 0402 SecureStream::~SecureStream() 0403 { 0404 delete d; 0405 } 0406 0407 void SecureStream::linkLayer(QObject *s) 0408 { 0409 connect(s, SIGNAL(tlsHandshaken()), SLOT(layer_tlsHandshaken())); 0410 connect(s, SIGNAL(tlsClosed(QByteArray)), SLOT(layer_tlsClosed(QByteArray))); 0411 connect(s, SIGNAL(readyRead(QByteArray)), SLOT(layer_readyRead(QByteArray))); 0412 connect(s, SIGNAL(needWrite(QByteArray)), SLOT(layer_needWrite(QByteArray))); 0413 connect(s, SIGNAL(error(int)), SLOT(layer_error(int))); 0414 } 0415 0416 int SecureStream::calcPrebytes() const 0417 { 0418 int x = 0; 0419 foreach(SecureLayer *s, d->layers) { 0420 x += s->prebytes; 0421 } 0422 return (d->pending - x); 0423 } 0424 0425 void SecureStream::startTLSClient(QCA::TLS *t, const QByteArray &spare) 0426 { 0427 if(!d->active || d->topInProgress || d->haveTLS()) 0428 return; 0429 0430 SecureLayer *s = new SecureLayer(t); 0431 s->prebytes = calcPrebytes(); 0432 linkLayer(s); 0433 d->layers.append(s); 0434 d->topInProgress = true; 0435 0436 insertData(spare); 0437 } 0438 0439 void SecureStream::startTLSServer(QCA::TLS *t, const QByteArray &spare) 0440 { 0441 if(!d->active || d->topInProgress || d->haveTLS()) 0442 return; 0443 0444 SecureLayer *s = new SecureLayer(t); 0445 s->prebytes = calcPrebytes(); 0446 linkLayer(s); 0447 d->layers.append(s); 0448 d->topInProgress = true; 0449 0450 insertData(spare); 0451 } 0452 0453 void SecureStream::setLayerCompress(const QByteArray& spare) 0454 { 0455 if(!d->active || d->topInProgress || d->haveCompress()) 0456 return; 0457 0458 SecureLayer *s = new SecureLayer(new CompressionHandler()); 0459 s->prebytes = calcPrebytes(); 0460 linkLayer(s); 0461 d->layers.append(s); 0462 0463 insertData(spare); 0464 } 0465 0466 void SecureStream::setLayerSASL(QCA::SASL *sasl, const QByteArray &spare) 0467 { 0468 if(!d->active || d->topInProgress || d->haveSASL()) 0469 return; 0470 0471 SecureLayer *s = new SecureLayer(sasl); 0472 s->prebytes = calcPrebytes(); 0473 linkLayer(s); 0474 d->layers.append(s); 0475 0476 insertData(spare); 0477 } 0478 0479 #ifdef USE_TLSHANDLER 0480 void SecureStream::startTLSClient(XMPP::TLSHandler *t, const QString &server, const QByteArray &spare) 0481 { 0482 if(!d->active || d->topInProgress || d->haveTLS()) 0483 return; 0484 0485 SecureLayer *s = new SecureLayer(t); 0486 s->prebytes = calcPrebytes(); 0487 linkLayer(s); 0488 d->layers.append(s); 0489 d->topInProgress = true; 0490 0491 // unlike QCA::TLS, XMPP::TLSHandler has no return value 0492 s->p.tlsHandler->startClient(server); 0493 0494 insertData(spare); 0495 } 0496 #endif 0497 0498 void SecureStream::closeTLS() 0499 { 0500 if (!d->layers.isEmpty()) { 0501 SecureLayer *s = d->layers.last(); 0502 if(s->type == SecureLayer::TLS) { 0503 s->p.tls->close(); 0504 } 0505 } 0506 } 0507 0508 int SecureStream::errorCode() const 0509 { 0510 return d->errorCode; 0511 } 0512 0513 bool SecureStream::isOpen() const 0514 { 0515 return d->active; 0516 } 0517 0518 void SecureStream::write(const QByteArray &a) 0519 { 0520 if(!isOpen()) 0521 return; 0522 0523 d->pending += a.size(); 0524 0525 // send to the last layer 0526 if (!d->layers.isEmpty()) { 0527 SecureLayer *s = d->layers.last(); 0528 s->write(a); 0529 } 0530 else { 0531 writeRawData(a); 0532 } 0533 } 0534 0535 int SecureStream::bytesToWrite() const 0536 { 0537 return d->pending; 0538 } 0539 0540 void SecureStream::bs_readyRead() 0541 { 0542 QByteArray a = d->bs->read(); 0543 0544 // send to the first layer 0545 if (!d->layers.isEmpty()) { 0546 SecureLayer *s = d->layers.first(); 0547 s->writeIncoming(a); 0548 } 0549 else { 0550 incomingData(a); 0551 } 0552 } 0553 0554 void SecureStream::bs_bytesWritten(int bytes) 0555 { 0556 foreach(SecureLayer *s, d->layers) { 0557 bytes = s->finished(bytes); 0558 } 0559 0560 if(bytes > 0) { 0561 d->pending -= bytes; 0562 bytesWritten(bytes); 0563 } 0564 } 0565 0566 void SecureStream::layer_tlsHandshaken() 0567 { 0568 d->topInProgress = false; 0569 tlsHandshaken(); 0570 } 0571 0572 void SecureStream::layer_tlsClosed(const QByteArray &) 0573 { 0574 d->active = false; 0575 while (!d->layers.isEmpty()) { 0576 delete d->layers.takeFirst(); 0577 } 0578 tlsClosed(); 0579 } 0580 0581 void SecureStream::layer_readyRead(const QByteArray &a) 0582 { 0583 SecureLayer *s = (SecureLayer *)sender(); 0584 QList<SecureLayer*>::Iterator it(d->layers.begin()); 0585 while((*it) != s) { 0586 Q_ASSERT(it != d->layers.end()); 0587 ++it; 0588 } 0589 Q_ASSERT(it != d->layers.end()); 0590 0591 // pass upwards 0592 ++it; 0593 if (it != d->layers.end()) { 0594 s = (*it); 0595 s->writeIncoming(a); 0596 } 0597 else { 0598 incomingData(a); 0599 } 0600 } 0601 0602 void SecureStream::layer_needWrite(const QByteArray &a) 0603 { 0604 SecureLayer *s = (SecureLayer *)sender(); 0605 QList<SecureLayer*>::Iterator it(d->layers.begin()); 0606 while((*it) != s) { 0607 Q_ASSERT(it != d->layers.end()); 0608 ++it; 0609 } 0610 Q_ASSERT(it != d->layers.end()); 0611 0612 // pass downwards 0613 if (it != d->layers.begin()) { 0614 --it; 0615 s = (*it); 0616 s->write(a); 0617 } 0618 else { 0619 writeRawData(a); 0620 } 0621 } 0622 0623 void SecureStream::layer_error(int x) 0624 { 0625 SecureLayer *s = (SecureLayer *)sender(); 0626 int type = s->type; 0627 d->errorCode = x; 0628 d->active = false; 0629 while (!d->layers.isEmpty()) { 0630 delete d->layers.takeFirst(); 0631 } 0632 if(type == SecureLayer::TLS) 0633 error(ErrTLS); 0634 else if(type == SecureLayer::SASL) 0635 error(ErrSASL); 0636 #ifdef USE_TLSHANDLER 0637 else if(type == SecureLayer::TLSH) 0638 error(ErrTLS); 0639 #endif 0640 } 0641 0642 void SecureStream::insertData(const QByteArray &a) 0643 { 0644 if(!a.isEmpty()) { 0645 if (!d->layers.isEmpty()) { 0646 SecureLayer *s = d->layers.last(); 0647 s->writeIncoming(a); 0648 } 0649 else { 0650 incomingData(a); 0651 } 0652 } 0653 } 0654 0655 void SecureStream::writeRawData(const QByteArray &a) 0656 { 0657 d->bs->write(a); 0658 } 0659 0660 void SecureStream::incomingData(const QByteArray &a) 0661 { 0662 appendRead(a); 0663 if(bytesAvailable()) 0664 readyRead(); 0665 }