File indexing completed on 2024-12-01 07:27:47

0001 /*
0002  * Copyright (C) 2003-2007  Justin Karneges <justin@affinix.com>
0003  * Copyright (C) 2004,2005  Brad Hards <bradh@frogmouth.net>
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  * version 2.1 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Lesser General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Lesser General Public
0016  * License along with this library; if not, write to the Free Software
0017  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0018  * 02110-1301  USA
0019  *
0020  */
0021 
0022 #include "qca_securelayer.h"
0023 
0024 #include "qca_safeobj.h"
0025 #include "qca_safetimer.h"
0026 #include "qcaprovider.h"
0027 
0028 #include <QMetaMethod>
0029 #include <QPointer>
0030 
0031 namespace QCA {
0032 
0033 Provider::Context *getContext(const QString &type, const QString &provider);
0034 
0035 enum ResetMode
0036 {
0037     ResetSession        = 0,
0038     ResetSessionAndData = 1,
0039     ResetAll            = 2
0040 };
0041 
0042 //----------------------------------------------------------------------------
0043 // LayerTracker
0044 //----------------------------------------------------------------------------
0045 class LayerTracker
0046 {
0047 private:
0048     struct Item
0049     {
0050         int    plain;
0051         qint64 encoded;
0052     };
0053 
0054     int         p;
0055     QList<Item> list;
0056 
0057 public:
0058     LayerTracker()
0059     {
0060         p = 0;
0061     }
0062 
0063     void reset()
0064     {
0065         p = 0;
0066         list.clear();
0067     }
0068 
0069     void addPlain(int plain)
0070     {
0071         p += plain;
0072     }
0073 
0074     void specifyEncoded(int encoded, int plain)
0075     {
0076         // can't specify more bytes than we have
0077         if (plain > p)
0078             plain = p;
0079         p -= plain;
0080         Item i;
0081         i.plain   = plain;
0082         i.encoded = encoded;
0083         list += i;
0084     }
0085 
0086     int finished(qint64 encoded)
0087     {
0088         int plain = 0;
0089         for (QList<Item>::Iterator it = list.begin(); it != list.end();) {
0090             Item &i = *it;
0091 
0092             // not enough?
0093             if (encoded < i.encoded) {
0094                 i.encoded -= encoded;
0095                 break;
0096             }
0097 
0098             encoded -= i.encoded;
0099             plain += i.plain;
0100             it = list.erase(it);
0101         }
0102         return plain;
0103     }
0104 };
0105 
0106 //----------------------------------------------------------------------------
0107 // SecureLayer
0108 //----------------------------------------------------------------------------
0109 SecureLayer::SecureLayer(QObject *parent)
0110     : QObject(parent)
0111 {
0112 }
0113 
0114 bool SecureLayer::isClosable() const
0115 {
0116     return false;
0117 }
0118 
0119 void SecureLayer::close()
0120 {
0121 }
0122 
0123 QByteArray SecureLayer::readUnprocessed()
0124 {
0125     return QByteArray();
0126 }
0127 
0128 //----------------------------------------------------------------------------
0129 // TLSSession
0130 //----------------------------------------------------------------------------
0131 TLSSession::TLSSession()
0132 {
0133 }
0134 
0135 TLSSession::TLSSession(const TLSSession &from)
0136     : Algorithm(from)
0137 {
0138 }
0139 
0140 TLSSession::~TLSSession()
0141 {
0142 }
0143 
0144 TLSSession &TLSSession::operator=(const TLSSession &from)
0145 {
0146     Algorithm::operator=(from);
0147     return *this;
0148 }
0149 
0150 bool TLSSession::isNull() const
0151 {
0152     return (!context() ? true : false);
0153 }
0154 
0155 //----------------------------------------------------------------------------
0156 // TLS
0157 //----------------------------------------------------------------------------
0158 class TLS::Private : public QObject
0159 {
0160     Q_OBJECT
0161 public:
0162     enum
0163     {
0164         OpStart,
0165         OpUpdate
0166     };
0167 
0168     enum State
0169     {
0170         Inactive,
0171         Initializing,
0172         Handshaking,
0173         Connected,
0174         Closing
0175     };
0176 
0177     class Action
0178     {
0179     public:
0180         enum Type
0181         {
0182             ReadyRead,
0183             ReadyReadOutgoing,
0184             Handshaken,
0185             Close,
0186             CheckPeerCertificate,
0187             CertificateRequested,
0188             HostNameReceived
0189         };
0190 
0191         int type;
0192 
0193         Action(int _type)
0194             : type(_type)
0195         {
0196         }
0197     };
0198 
0199     TLS        *q;
0200     TLSContext *c;
0201     TLS::Mode   mode;
0202 
0203     // signal connected flags
0204     bool connect_hostNameReceived;
0205     bool connect_certificateRequested;
0206     bool connect_peerCertificateAvailable;
0207     bool connect_handshaken;
0208 
0209     // persistent settings (survives ResetSessionAndData)
0210     CertificateChain              localCert;
0211     PrivateKey                    localKey;
0212     CertificateCollection         trusted;
0213     bool                          con_ssfMode;
0214     int                           con_minSSF, con_maxSSF;
0215     QStringList                   con_cipherSuites;
0216     bool                          tryCompress;
0217     int                           packet_mtu;
0218     QList<CertificateInfoOrdered> issuerList;
0219     TLSSession                    session;
0220 
0221     // session
0222     State                   state;
0223     bool                    blocked;
0224     bool                    server;
0225     QString                 host;
0226     TLSContext::SessionInfo sessionInfo;
0227     SafeTimer               actionTrigger;
0228     int                     op;
0229     QList<Action>           actionQueue;
0230     bool                    need_update;
0231     bool                    maybe_input;
0232     bool                    emitted_hostNameReceived;
0233     bool                    emitted_certificateRequested;
0234     bool                    emitted_peerCertificateAvailable;
0235 
0236     // data (survives ResetSession)
0237     CertificateChain peerCert;
0238     Validity         peerValidity;
0239     bool             hostMismatch;
0240     Error            errorCode;
0241 
0242     // stream i/o
0243     QByteArray   in, out;
0244     QByteArray   to_net, from_net;
0245     QByteArray   unprocessed;
0246     int          out_pending;
0247     int          to_net_encoded;
0248     LayerTracker layer;
0249 
0250     // datagram i/o
0251     QList<QByteArray> packet_in, packet_out;
0252     QList<QByteArray> packet_to_net, packet_from_net;
0253     int               packet_out_pending; // packet count
0254     QList<int>        packet_to_net_encoded;
0255 
0256     Private(TLS *_q, TLS::Mode _mode)
0257         : QObject(_q)
0258         , q(_q)
0259         , mode(_mode)
0260         , actionTrigger(this)
0261     {
0262         // c is 0 during initial reset, so we don't redundantly reset it
0263         c                                = nullptr;
0264         connect_hostNameReceived         = false;
0265         connect_certificateRequested     = false;
0266         connect_peerCertificateAvailable = false;
0267         connect_handshaken               = false;
0268         server                           = false;
0269 
0270         connect(&actionTrigger, &SafeTimer::timeout, this, &Private::doNextAction);
0271         actionTrigger.setSingleShot(true);
0272 
0273         reset(ResetAll);
0274 
0275         c = static_cast<TLSContext *>(q->context());
0276 
0277         // parent the context to us, so that moveToThread works
0278         c->setParent(this);
0279 
0280         connect(c, &TLSContext::resultsReady, this, &Private::tls_resultsReady);
0281         connect(c, &TLSContext::dtlsTimeout, this, &Private::tls_dtlsTimeout);
0282     }
0283 
0284     ~Private() override
0285     {
0286         // context is owned by Algorithm, unparent so we don't double-delete
0287         c->setParent(nullptr);
0288     }
0289 
0290     void reset(ResetMode mode)
0291     {
0292         if (c)
0293             c->reset();
0294 
0295         // if we reset while in client mode, then clear this list
0296         //   (it should only persist when used for server mode)
0297         if (!server)
0298             issuerList.clear();
0299 
0300         state       = Inactive;
0301         blocked     = false;
0302         server      = false;
0303         host        = QString();
0304         sessionInfo = TLSContext::SessionInfo();
0305         actionTrigger.stop();
0306         op = -1;
0307         actionQueue.clear();
0308         need_update                      = false;
0309         maybe_input                      = false;
0310         emitted_hostNameReceived         = false;
0311         emitted_certificateRequested     = false;
0312         emitted_peerCertificateAvailable = false;
0313 
0314         out.clear();
0315         out_pending = 0;
0316         packet_out.clear();
0317         packet_out_pending = 0;
0318 
0319         if (mode >= ResetSessionAndData) {
0320             peerCert     = CertificateChain();
0321             peerValidity = ErrorValidityUnknown;
0322             hostMismatch = false;
0323             errorCode    = (TLS::Error)-1;
0324 
0325             in.clear();
0326             to_net.clear();
0327             from_net.clear();
0328             unprocessed.clear();
0329             to_net_encoded = 0;
0330             layer.reset();
0331 
0332             packet_in.clear();
0333             packet_to_net.clear();
0334             packet_from_net.clear();
0335             packet_to_net_encoded.clear();
0336         }
0337 
0338         if (mode >= ResetAll) {
0339             localCert        = CertificateChain();
0340             localKey         = PrivateKey();
0341             trusted          = CertificateCollection();
0342             con_ssfMode      = true;
0343             con_minSSF       = 128;
0344             con_maxSSF       = -1;
0345             con_cipherSuites = QStringList();
0346             tryCompress      = false;
0347             packet_mtu       = -1;
0348             issuerList.clear();
0349             session = TLSSession();
0350         }
0351     }
0352 
0353     void start(bool serverMode)
0354     {
0355         state  = Initializing;
0356         server = serverMode;
0357 
0358         c->setup(serverMode, host, tryCompress);
0359 
0360         if (con_ssfMode)
0361             c->setConstraints(con_minSSF, con_maxSSF);
0362         else
0363             c->setConstraints(con_cipherSuites);
0364 
0365         c->setCertificate(localCert, localKey);
0366         c->setTrustedCertificates(trusted);
0367         if (serverMode)
0368             c->setIssuerList(issuerList);
0369         if (!session.isNull()) {
0370             TLSSessionContext *sc = static_cast<TLSSessionContext *>(session.context());
0371             c->setSessionId(*sc);
0372         }
0373         c->setMTU(packet_mtu);
0374 
0375         QCA_logTextMessage(QStringLiteral("tls[%1]: c->start()").arg(q->objectName()), Logger::Information);
0376         op = OpStart;
0377         c->start();
0378     }
0379 
0380     void close()
0381     {
0382         QCA_logTextMessage(QStringLiteral("tls[%1]: close").arg(q->objectName()), Logger::Information);
0383 
0384         if (state != Connected)
0385             return;
0386 
0387         state = Closing;
0388         c->shutdown();
0389     }
0390 
0391     void continueAfterStep()
0392     {
0393         QCA_logTextMessage(QStringLiteral("tls[%1]: continueAfterStep").arg(q->objectName()), Logger::Information);
0394 
0395         if (!blocked)
0396             return;
0397 
0398         blocked = false;
0399         update();
0400     }
0401 
0402     void processNextAction()
0403     {
0404         if (actionQueue.isEmpty()) {
0405             if (need_update) {
0406                 QCA_logTextMessage(QStringLiteral("tls[%1]: need_update").arg(q->objectName()), Logger::Information);
0407                 update();
0408             }
0409             return;
0410         }
0411 
0412         const Action a = actionQueue.takeFirst();
0413 
0414         // set up for the next one, if necessary
0415         if (!actionQueue.isEmpty() || need_update) {
0416             if (!actionTrigger.isActive())
0417                 actionTrigger.start();
0418         }
0419 
0420         if (a.type == Action::ReadyRead) {
0421             emit q->readyRead();
0422         } else if (a.type == Action::ReadyReadOutgoing) {
0423             emit q->readyReadOutgoing();
0424         } else if (a.type == Action::Handshaken) {
0425             state = Connected;
0426 
0427             // write any app data waiting during handshake
0428             if (!out.isEmpty()) {
0429                 need_update = true;
0430                 if (!actionTrigger.isActive())
0431                     actionTrigger.start();
0432             }
0433 
0434             QCA_logTextMessage(QStringLiteral("tls[%1]: handshaken").arg(q->objectName()), Logger::Information);
0435 
0436             if (connect_handshaken) {
0437                 blocked = true;
0438                 emit q->handshaken();
0439             }
0440         } else if (a.type == Action::Close) {
0441             unprocessed = c->unprocessed();
0442             reset(ResetSession);
0443             emit q->closed();
0444         } else if (a.type == Action::CheckPeerCertificate) {
0445             peerCert = c->peerCertificateChain();
0446             if (!peerCert.isEmpty()) {
0447                 peerValidity = c->peerCertificateValidity();
0448                 if (peerValidity == ValidityGood && !host.isEmpty() && !peerCert.primary().matchesHostName(host))
0449                     hostMismatch = true;
0450             }
0451 
0452             if (connect_peerCertificateAvailable) {
0453                 blocked                          = true;
0454                 emitted_peerCertificateAvailable = true;
0455                 emit q->peerCertificateAvailable();
0456             }
0457         } else if (a.type == Action::CertificateRequested) {
0458             issuerList = c->issuerList();
0459             if (connect_certificateRequested) {
0460                 blocked                      = true;
0461                 emitted_certificateRequested = true;
0462                 emit q->certificateRequested();
0463             }
0464         } else if (a.type == Action::HostNameReceived) {
0465             if (connect_hostNameReceived) {
0466                 blocked                  = true;
0467                 emitted_hostNameReceived = true;
0468                 emit q->hostNameReceived();
0469             }
0470         }
0471     }
0472 
0473     void update()
0474     {
0475         QCA_logTextMessage(QStringLiteral("tls[%1]: update").arg(q->objectName()), Logger::Information);
0476 
0477         if (blocked) {
0478             QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while blocked").arg(q->objectName()),
0479                                Logger::Information);
0480             return;
0481         }
0482 
0483         if (!actionQueue.isEmpty()) {
0484             QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while processing actions").arg(q->objectName()),
0485                                Logger::Information);
0486             need_update = true;
0487             return;
0488         }
0489 
0490         // only allow one operation at a time
0491         if (op != -1) {
0492             QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while operation active").arg(q->objectName()),
0493                                Logger::Information);
0494             need_update = true;
0495             return;
0496         }
0497 
0498         need_update = false;
0499 
0500         QByteArray arg_from_net, arg_from_app;
0501 
0502         if (state == Handshaking) {
0503             // during handshake, only send from_net (no app data)
0504 
0505             if (mode == TLS::Stream) {
0506                 arg_from_net = from_net;
0507                 from_net.clear();
0508             } else {
0509                 // note: there may not be a packet
0510                 if (!packet_from_net.isEmpty())
0511                     arg_from_net = packet_from_net.takeFirst();
0512             }
0513         } else {
0514             if (mode == TLS::Stream) {
0515                 if (!from_net.isEmpty()) {
0516                     arg_from_net = from_net;
0517                     from_net.clear();
0518                 }
0519 
0520                 if (!out.isEmpty()) {
0521                     out_pending += out.size();
0522                     arg_from_app = out;
0523                     out.clear();
0524                 }
0525             } else {
0526                 if (!packet_from_net.isEmpty())
0527                     arg_from_net = packet_from_net.takeFirst();
0528 
0529                 if (!packet_out.isEmpty()) {
0530                     arg_from_app = packet_out.takeFirst();
0531                     ++packet_out_pending;
0532                 }
0533             }
0534         }
0535 
0536         if (arg_from_net.isEmpty() && arg_from_app.isEmpty() && !maybe_input) {
0537             QCA_logTextMessage(
0538                 QStringLiteral("tls[%1]: ignoring update: no output and no expected input").arg(q->objectName()),
0539                 Logger::Information);
0540             return;
0541         }
0542 
0543         // clear this flag
0544         maybe_input = false;
0545 
0546         QCA_logTextMessage(QStringLiteral("tls[%1]: c->update").arg(q->objectName()), Logger::Information);
0547         op = OpUpdate;
0548         c->update(arg_from_net, arg_from_app);
0549     }
0550 
0551     void start_finished()
0552     {
0553         const bool ok = c->result() == TLSContext::Success;
0554         if (!ok) {
0555             reset(ResetSession);
0556             errorCode = TLS::ErrorInit;
0557             emit q->error();
0558             return;
0559         }
0560 
0561         state = Handshaking;
0562 
0563         // immediately update so we can get the first packet to send
0564         maybe_input = true;
0565         update();
0566     }
0567 
0568     void update_finished()
0569     {
0570         const TLSContext::Result r = c->result();
0571         if (r == TLSContext::Error) {
0572             if (state == Handshaking || state == Closing) {
0573                 reset(ResetSession);
0574                 errorCode = ErrorHandshake;
0575             } else {
0576                 reset(ResetSession);
0577                 errorCode = ErrorCrypt;
0578             }
0579 
0580             emit q->error();
0581             return;
0582         }
0583 
0584         const QByteArray c_to_net = c->to_net();
0585         if (!c_to_net.isEmpty()) {
0586             QCA_logTextMessage(
0587                 QStringLiteral("tls[%1]: to_net %2").arg(q->objectName(), QString::number(c_to_net.size())),
0588                 Logger::Information);
0589         }
0590 
0591         if (state == Closing) {
0592             if (mode == TLS::Stream)
0593                 to_net += c_to_net;
0594             else
0595                 packet_to_net += c_to_net;
0596 
0597             if (!c_to_net.isEmpty())
0598                 actionQueue += Action(Action::ReadyReadOutgoing);
0599 
0600             if (r == TLSContext::Success)
0601                 actionQueue += Action(Action::Close);
0602 
0603             processNextAction();
0604             return;
0605         } else if (state == Handshaking) {
0606             if (mode == TLS::Stream)
0607                 to_net += c_to_net;
0608             else
0609                 packet_to_net += c_to_net;
0610 
0611             if (!c_to_net.isEmpty())
0612                 actionQueue += Action(Action::ReadyReadOutgoing);
0613 
0614             bool clientHello = false;
0615             bool serverHello = false;
0616             if (server)
0617                 clientHello = c->clientHelloReceived();
0618             else
0619                 serverHello = c->serverHelloReceived();
0620 
0621             // client specifies a host?
0622             if (!emitted_hostNameReceived && clientHello) {
0623                 host = c->hostName();
0624                 if (!host.isEmpty())
0625                     actionQueue += Action(Action::HostNameReceived);
0626             }
0627 
0628             // successful handshake or server hello means there might be a peer cert
0629             if (!emitted_peerCertificateAvailable && (r == TLSContext::Success || (!server && serverHello)))
0630                 actionQueue += Action(Action::CheckPeerCertificate);
0631 
0632             // server requests a cert from us?
0633             if (!emitted_certificateRequested && (serverHello && c->certificateRequested()))
0634                 actionQueue += Action(Action::CertificateRequested);
0635 
0636             if (r == TLSContext::Success) {
0637                 sessionInfo = c->sessionInfo();
0638                 if (sessionInfo.id) {
0639                     TLSSessionContext *sc = static_cast<TLSSessionContext *>(sessionInfo.id->clone());
0640                     session.change(sc);
0641                 }
0642 
0643                 actionQueue += Action(Action::Handshaken);
0644             }
0645 
0646             processNextAction();
0647             return;
0648         } else // Connected
0649         {
0650             const QByteArray c_to_app = c->to_app();
0651             if (!c_to_app.isEmpty()) {
0652                 QCA_logTextMessage(
0653                     QStringLiteral("tls[%1]: to_app %2").arg(q->objectName(), QString::number(c_to_app.size())),
0654                     Logger::Information);
0655             }
0656 
0657             const bool eof = c->eof();
0658             int        enc = -1;
0659             if (!c_to_net.isEmpty())
0660                 enc = c->encoded();
0661 
0662             bool io_pending = false;
0663             if (mode == TLS::Stream) {
0664                 if (!c_to_net.isEmpty())
0665                     out_pending -= enc;
0666 
0667                 if (out_pending > 0) {
0668                     maybe_input = true;
0669                     io_pending  = true;
0670                 }
0671 
0672                 if (!out.isEmpty())
0673                     io_pending = true;
0674             } else {
0675                 if (!c_to_net.isEmpty())
0676                     --packet_out_pending;
0677 
0678                 if (packet_out_pending > 0) {
0679                     maybe_input = true;
0680                     io_pending  = true;
0681                 }
0682 
0683                 if (!packet_out.isEmpty())
0684                     io_pending = true;
0685             }
0686 
0687             if (mode == TLS::Stream) {
0688                 to_net += c_to_net;
0689                 in += c_to_app;
0690                 to_net_encoded += enc;
0691             } else {
0692                 packet_to_net += c_to_net;
0693                 packet_in += c_to_app;
0694             }
0695 
0696             if (!c_to_net.isEmpty())
0697                 actionQueue += Action(Action::ReadyReadOutgoing);
0698 
0699             if (!c_to_app.isEmpty())
0700                 actionQueue += Action(Action::ReadyRead);
0701 
0702             if (eof) {
0703                 close();
0704                 maybe_input = true;
0705             }
0706 
0707             if (eof || io_pending) {
0708                 QCA_logTextMessage(QStringLiteral("tls[%1]: eof || io_pending").arg(q->objectName()),
0709                                    Logger::Information);
0710                 update();
0711             }
0712 
0713             processNextAction();
0714             return;
0715         }
0716     }
0717 
0718 private Q_SLOTS:
0719     void tls_resultsReady()
0720     {
0721         QCA_logTextMessage(QStringLiteral("tls[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information);
0722 
0723         Q_ASSERT(op != -1);
0724 
0725         int last_op = op;
0726         op          = -1;
0727 
0728         if (last_op == OpStart)
0729             start_finished();
0730         else // OpUpdate
0731             update_finished();
0732     }
0733 
0734     void tls_dtlsTimeout()
0735     {
0736         QCA_logTextMessage(QStringLiteral("tls[%1]: c->dtlsTimeout()").arg(q->objectName()), Logger::Information);
0737 
0738         maybe_input = true;
0739         update();
0740     }
0741 
0742     void doNextAction()
0743     {
0744         processNextAction();
0745     }
0746 };
0747 
0748 TLS::TLS(QObject *parent, const QString &provider)
0749     : SecureLayer(parent)
0750     , Algorithm(QStringLiteral("tls"), provider)
0751 {
0752     d = new Private(this, TLS::Stream);
0753 }
0754 
0755 TLS::TLS(Mode mode, QObject *parent, const QString &provider)
0756     : SecureLayer(parent)
0757     , Algorithm(mode == Stream ? QStringLiteral("tls") : QStringLiteral("dtls"), provider)
0758 {
0759     d = new Private(this, mode);
0760 }
0761 
0762 TLS::~TLS()
0763 {
0764     delete d;
0765 }
0766 
0767 void TLS::reset()
0768 {
0769     d->reset(ResetAll);
0770 }
0771 
0772 QStringList TLS::supportedCipherSuites(
0773     const Version &version) const // clazy:exclude=function-args-by-value TODO make it remove the & when we break ABI
0774 {
0775     return d->c->supportedCipherSuites(version);
0776 }
0777 
0778 void TLS::setCertificate(const CertificateChain &cert, const PrivateKey &key)
0779 {
0780     d->localCert = cert;
0781     d->localKey  = key;
0782     if (d->state != TLS::Private::Inactive)
0783         d->c->setCertificate(cert, key);
0784 }
0785 
0786 void TLS::setCertificate(const KeyBundle &kb)
0787 {
0788     setCertificate(kb.certificateChain(), kb.privateKey());
0789 }
0790 
0791 CertificateCollection TLS::trustedCertificates() const
0792 {
0793     return d->trusted;
0794 }
0795 
0796 void TLS::setTrustedCertificates(const CertificateCollection &trusted)
0797 {
0798     d->trusted = trusted;
0799     if (d->state != TLS::Private::Inactive)
0800         d->c->setTrustedCertificates(trusted);
0801 }
0802 
0803 void TLS::setConstraints(SecurityLevel s)
0804 {
0805     int min = 128;
0806     switch (s) {
0807     case SL_None:
0808         min = 0;
0809         break;
0810     case SL_Integrity:
0811         min = 1;
0812         break;
0813     case SL_Export:
0814         min = 40;
0815         break;
0816     case SL_Baseline:
0817         min = 128;
0818         break;
0819     case SL_High:
0820         min = 129;
0821         break;
0822     case SL_Highest:
0823         min = qMax(129, d->c->maxSSF());
0824         break;
0825     }
0826 
0827     d->con_ssfMode = true;
0828     d->con_minSSF  = min;
0829     d->con_maxSSF  = -1;
0830 
0831     if (d->state != TLS::Private::Inactive)
0832         d->c->setConstraints(d->con_minSSF, d->con_maxSSF);
0833 }
0834 
0835 void TLS::setConstraints(int minSSF, int maxSSF)
0836 {
0837     d->con_ssfMode = true;
0838     d->con_minSSF  = minSSF;
0839     d->con_maxSSF  = maxSSF;
0840 
0841     if (d->state != TLS::Private::Inactive)
0842         d->c->setConstraints(d->con_minSSF, d->con_maxSSF);
0843 }
0844 
0845 void TLS::setConstraints(const QStringList &cipherSuiteList)
0846 {
0847     d->con_ssfMode      = false;
0848     d->con_cipherSuites = cipherSuiteList;
0849 
0850     if (d->state != TLS::Private::Inactive)
0851         d->c->setConstraints(d->con_cipherSuites);
0852 }
0853 
0854 QList<CertificateInfoOrdered> TLS::issuerList() const
0855 {
0856     return d->issuerList;
0857 }
0858 
0859 void TLS::setIssuerList(const QList<CertificateInfoOrdered> &issuers)
0860 {
0861     d->issuerList = issuers;
0862     if (d->state != TLS::Private::Inactive)
0863         d->c->setIssuerList(issuers);
0864 }
0865 
0866 void TLS::setSession(const TLSSession &session)
0867 {
0868     d->session = session;
0869 }
0870 
0871 bool TLS::canCompress() const
0872 {
0873     return d->c->canCompress();
0874 }
0875 
0876 bool TLS::canSetHostName() const
0877 {
0878     return d->c->canSetHostName();
0879 }
0880 
0881 bool TLS::compressionEnabled() const
0882 {
0883     return d->tryCompress;
0884 }
0885 
0886 void TLS::setCompressionEnabled(bool b)
0887 {
0888     d->tryCompress = b;
0889 }
0890 
0891 void TLS::startClient(const QString &host)
0892 {
0893     d->reset(ResetSessionAndData);
0894     d->host = host;
0895     d->issuerList.clear();
0896 
0897     // client mode
0898     d->start(false);
0899 }
0900 
0901 void TLS::startServer()
0902 {
0903     d->reset(ResetSessionAndData);
0904 
0905     // server mode
0906     d->start(true);
0907 }
0908 
0909 void TLS::continueAfterStep()
0910 {
0911     d->continueAfterStep();
0912 }
0913 
0914 bool TLS::isHandshaken() const
0915 {
0916     if (d->state == TLS::Private::Connected || d->state == TLS::Private::Closing)
0917         return true;
0918     else
0919         return false;
0920 }
0921 
0922 bool TLS::isCompressed() const
0923 {
0924     return d->sessionInfo.isCompressed;
0925 }
0926 
0927 TLS::Version TLS::version() const
0928 {
0929     return d->sessionInfo.version;
0930 }
0931 
0932 QString TLS::cipherSuite() const
0933 {
0934     return d->sessionInfo.cipherSuite;
0935 }
0936 
0937 int TLS::cipherBits() const
0938 {
0939     return d->sessionInfo.cipherBits;
0940 }
0941 
0942 int TLS::cipherMaxBits() const
0943 {
0944     return d->sessionInfo.cipherMaxBits;
0945 }
0946 
0947 TLSSession TLS::session() const
0948 {
0949     return d->session;
0950 }
0951 
0952 TLS::Error TLS::errorCode() const
0953 {
0954     return d->errorCode;
0955 }
0956 
0957 TLS::IdentityResult TLS::peerIdentityResult() const
0958 {
0959     if (d->peerCert.isEmpty())
0960         return NoCertificate;
0961 
0962     if (d->peerValidity != ValidityGood)
0963         return InvalidCertificate;
0964 
0965     if (d->hostMismatch)
0966         return HostMismatch;
0967 
0968     return Valid;
0969 }
0970 
0971 Validity TLS::peerCertificateValidity() const
0972 {
0973     return d->peerValidity;
0974 }
0975 
0976 CertificateChain TLS::localCertificateChain() const
0977 {
0978     return d->localCert;
0979 }
0980 
0981 PrivateKey TLS::localPrivateKey() const
0982 {
0983     return d->localKey;
0984 }
0985 
0986 CertificateChain TLS::peerCertificateChain() const
0987 {
0988     return d->peerCert;
0989 }
0990 
0991 bool TLS::isClosable() const
0992 {
0993     return true;
0994 }
0995 
0996 int TLS::bytesAvailable() const
0997 {
0998     if (d->mode == Stream)
0999         return d->in.size();
1000     else
1001         return 0;
1002 }
1003 
1004 int TLS::bytesOutgoingAvailable() const
1005 {
1006     if (d->mode == Stream)
1007         return d->to_net.size();
1008     else
1009         return 0;
1010 }
1011 
1012 void TLS::close()
1013 {
1014     d->close();
1015     d->update();
1016 }
1017 
1018 void TLS::write(const QByteArray &a)
1019 {
1020     if (d->mode == Stream) {
1021         d->out.append(a);
1022         d->layer.addPlain(a.size());
1023     } else
1024         d->packet_out.append(a);
1025     QCA_logTextMessage(QStringLiteral("tls[%1]: write").arg(objectName()), Logger::Information);
1026     d->update();
1027 }
1028 
1029 QByteArray TLS::read()
1030 {
1031     if (d->mode == Stream) {
1032         const QByteArray a = d->in;
1033         d->in.clear();
1034         return a;
1035     } else {
1036         if (!d->packet_in.isEmpty())
1037             return d->packet_in.takeFirst();
1038         else
1039             return QByteArray();
1040     }
1041 }
1042 
1043 void TLS::writeIncoming(const QByteArray &a)
1044 {
1045     if (d->mode == Stream)
1046         d->from_net.append(a);
1047     else
1048         d->packet_from_net.append(a);
1049     QCA_logTextMessage(QStringLiteral("tls[%1]: writeIncoming %2").arg(objectName(), QString::number(a.size())),
1050                        Logger::Information);
1051     d->update();
1052 }
1053 
1054 QByteArray TLS::readOutgoing(int *plainBytes)
1055 {
1056     if (d->mode == Stream) {
1057         const QByteArray a = d->to_net;
1058         d->to_net.clear();
1059         if (plainBytes)
1060             *plainBytes = d->to_net_encoded;
1061         d->layer.specifyEncoded(a.size(), d->to_net_encoded);
1062         d->to_net_encoded = 0;
1063         return a;
1064     } else {
1065         if (!d->packet_to_net.isEmpty()) {
1066             const QByteArray a = d->packet_to_net.takeFirst();
1067             const int        x = d->packet_to_net_encoded.takeFirst();
1068             if (plainBytes)
1069                 *plainBytes = x;
1070             return a;
1071         } else {
1072             if (plainBytes)
1073                 *plainBytes = 0;
1074             return QByteArray();
1075         }
1076     }
1077 }
1078 
1079 QByteArray TLS::readUnprocessed()
1080 {
1081     if (d->mode == Stream) {
1082         const QByteArray a = d->unprocessed;
1083         d->unprocessed.clear();
1084         return a;
1085     } else
1086         return QByteArray();
1087 }
1088 
1089 int TLS::convertBytesWritten(qint64 bytes)
1090 {
1091     return d->layer.finished(bytes);
1092 }
1093 
1094 int TLS::packetsAvailable() const
1095 {
1096     return d->packet_in.count();
1097 }
1098 
1099 int TLS::packetsOutgoingAvailable() const
1100 {
1101     return d->packet_to_net.count();
1102 }
1103 
1104 int TLS::packetMTU() const
1105 {
1106     return d->packet_mtu;
1107 }
1108 
1109 void TLS::setPacketMTU(int size) const
1110 {
1111     d->packet_mtu = size;
1112     if (d->state != TLS::Private::Inactive)
1113         d->c->setMTU(size);
1114 }
1115 
1116 void TLS::connectNotify(const QMetaMethod &signal)
1117 {
1118     if (signal == QMetaMethod::fromSignal(&TLS::hostNameReceived))
1119         d->connect_hostNameReceived = true;
1120     else if (signal == QMetaMethod::fromSignal(&TLS::certificateRequested))
1121         d->connect_certificateRequested = true;
1122     else if (signal == QMetaMethod::fromSignal(&TLS::peerCertificateAvailable))
1123         d->connect_peerCertificateAvailable = true;
1124     else if (signal == QMetaMethod::fromSignal(&TLS::handshaken))
1125         d->connect_handshaken = true;
1126 }
1127 
1128 void TLS::disconnectNotify(const QMetaMethod &signal)
1129 {
1130     if (signal == QMetaMethod::fromSignal(&TLS::hostNameReceived))
1131         d->connect_hostNameReceived = false;
1132     else if (signal == QMetaMethod::fromSignal(&TLS::certificateRequested))
1133         d->connect_certificateRequested = false;
1134     else if (signal == QMetaMethod::fromSignal(&TLS::peerCertificateAvailable))
1135         d->connect_peerCertificateAvailable = false;
1136     else if (signal == QMetaMethod::fromSignal(&TLS::handshaken))
1137         d->connect_handshaken = false;
1138 }
1139 
1140 //----------------------------------------------------------------------------
1141 // SASL::Params
1142 //----------------------------------------------------------------------------
1143 class SASL::Params::Private
1144 {
1145 public:
1146     bool needUsername, canSendAuthzid, needPassword, canSendRealm;
1147 };
1148 
1149 SASL::Params::Params()
1150     : d(new Private)
1151 {
1152 }
1153 
1154 SASL::Params::Params(bool user, bool authzid, bool pass, bool realm)
1155     : d(new Private)
1156 {
1157     d->needUsername   = user;
1158     d->canSendAuthzid = authzid;
1159     d->needPassword   = pass;
1160     d->canSendRealm   = realm;
1161 }
1162 
1163 SASL::Params::Params(const SASL::Params &from)
1164     : d(new Private(*from.d))
1165 {
1166 }
1167 
1168 SASL::Params::~Params()
1169 {
1170     delete d;
1171 }
1172 
1173 SASL::Params &SASL::Params::operator=(const SASL::Params &from)
1174 {
1175     *d = *from.d;
1176     return *this;
1177 }
1178 
1179 bool SASL::Params::needUsername() const
1180 {
1181     return d->needUsername;
1182 }
1183 
1184 bool SASL::Params::canSendAuthzid() const
1185 {
1186     return d->canSendAuthzid;
1187 }
1188 
1189 bool SASL::Params::needPassword() const
1190 {
1191     return d->needPassword;
1192 }
1193 
1194 bool SASL::Params::canSendRealm() const
1195 {
1196     return d->canSendRealm;
1197 }
1198 
1199 //----------------------------------------------------------------------------
1200 // SASL
1201 //----------------------------------------------------------------------------
1202 /*
1203   These don't map, but I don't think it matters much..
1204     SASL_TRYAGAIN  (-8)  transient failure (e.g., weak key)
1205     SASL_BADMAC    (-9)  integrity check failed
1206       -- client only codes --
1207     SASL_WRONGMECH (-11) mechanism doesn't support requested feature
1208     SASL_NEWSECRET (-12) new secret needed
1209       -- server only codes --
1210     SASL_TRANS     (-17) One time use of a plaintext password will
1211                          enable requested mechanism for user
1212     SASL_PWLOCK    (-21) password locked
1213     SASL_NOCHANGE  (-22) requested change was not needed
1214 */
1215 
1216 class SASL::Private : public QObject
1217 {
1218     Q_OBJECT
1219 public:
1220     enum
1221     {
1222         OpStart,
1223         OpServerFirstStep,
1224         OpNextStep,
1225         OpTryAgain,
1226         OpUpdate
1227     };
1228 
1229     class Action
1230     {
1231     public:
1232         enum Type
1233         {
1234             ClientStarted,
1235             NextStep,
1236             Authenticated,
1237             ReadyRead,
1238             ReadyReadOutgoing
1239         };
1240 
1241         int        type;
1242         QByteArray stepData;
1243         bool       haveInit;
1244 
1245         Action(int _type)
1246             : type(_type)
1247         {
1248         }
1249 
1250         Action(int _type, const QByteArray &_stepData)
1251             : type(_type)
1252             , stepData(_stepData)
1253         {
1254         }
1255 
1256         Action(int _type, bool _haveInit, const QByteArray &_stepData)
1257             : type(_type)
1258             , stepData(_stepData)
1259             , haveInit(_haveInit)
1260         {
1261         }
1262     };
1263 
1264     SASL        *q;
1265     SASLContext *c;
1266 
1267     // persistent settings (survives ResetSessionAndData)
1268     AuthFlags             auth_flags;
1269     int                   ssfmin, ssfmax;
1270     QString               ext_authid;
1271     int                   ext_ssf;
1272     bool                  localSet, remoteSet;
1273     SASLContext::HostPort local, remote;
1274     bool                  set_username, set_authzid, set_password, set_realm;
1275     QString               username, authzid, realm;
1276     SecureArray           password;
1277 
1278     // session
1279     bool          server;
1280     QStringList   mechlist;
1281     QString       server_realm;
1282     bool          allowClientSendFirst;
1283     bool          disableServerSendLast;
1284     SafeTimer     actionTrigger;
1285     int           op;
1286     QList<Action> actionQueue;
1287     bool          need_update;
1288     bool          first;
1289     bool          authed;
1290 
1291     // data (survives ResetSession)
1292     QString mech; // selected mech
1293     Error   errorCode;
1294 
1295     // stream i/o
1296     QByteArray   in, out;
1297     QByteArray   to_net, from_net;
1298     int          out_pending;
1299     int          to_net_encoded;
1300     LayerTracker layer;
1301 
1302     Private(SASL *_q)
1303         : QObject(_q)
1304         , q(_q)
1305         , actionTrigger(this)
1306     {
1307         c            = nullptr;
1308         set_username = false;
1309         set_authzid  = false;
1310         set_password = false;
1311         set_realm    = false;
1312 
1313         connect(&actionTrigger, &SafeTimer::timeout, this, &Private::doNextAction);
1314         actionTrigger.setSingleShot(true);
1315 
1316         reset(ResetAll);
1317 
1318         c = static_cast<SASLContext *>(q->context());
1319 
1320         // parent the context to us, so that moveToThread works
1321         c->setParent(this);
1322 
1323         connect(c, &SASLContext::resultsReady, this, &Private::sasl_resultsReady);
1324     }
1325 
1326     ~Private() override
1327     {
1328         // context is owned by Algorithm, unparent so we don't double-delete
1329         c->setParent(nullptr);
1330     }
1331 
1332     void reset(ResetMode mode)
1333     {
1334         if (c)
1335             c->reset();
1336 
1337         server = false;
1338         mechlist.clear();
1339         server_realm          = QString();
1340         allowClientSendFirst  = false;
1341         disableServerSendLast = true;
1342         actionTrigger.stop();
1343         op = -1;
1344         actionQueue.clear();
1345         need_update = false;
1346         first       = false;
1347         authed      = false;
1348 
1349         out.clear();
1350         out_pending = 0;
1351 
1352         if (mode >= ResetSessionAndData) {
1353             mech      = QString();
1354             errorCode = (SASL::Error)-1;
1355 
1356             in.clear();
1357             to_net.clear();
1358             from_net.clear();
1359             to_net_encoded = 0;
1360             layer.reset();
1361         }
1362 
1363         if (mode >= ResetAll) {
1364             auth_flags = SASL::AuthFlagsNone;
1365             ssfmin     = 0;
1366             ssfmax     = 0;
1367             ext_authid = QString();
1368             ext_ssf    = 0;
1369             localSet   = false;
1370             remoteSet  = false;
1371             local      = SASLContext::HostPort();
1372             remote     = SASLContext::HostPort();
1373 
1374             set_username = false;
1375             username     = QString();
1376             set_authzid  = false;
1377             authzid      = QString();
1378             set_password = false;
1379             password     = SecureArray();
1380             set_realm    = false;
1381             realm        = QString();
1382         }
1383     }
1384 
1385     void setup(const QString &service, const QString &host)
1386     {
1387         c->setup(service, host, localSet ? &local : nullptr, remoteSet ? &remote : nullptr, ext_authid, ext_ssf);
1388         c->setConstraints(auth_flags, ssfmin, ssfmax);
1389 
1390         QString     *p_username = nullptr;
1391         QString     *p_authzid  = nullptr;
1392         SecureArray *p_password = nullptr;
1393         QString     *p_realm    = nullptr;
1394 
1395         if (set_username)
1396             p_username = &username;
1397         if (set_authzid)
1398             p_authzid = &authzid;
1399         if (set_password)
1400             p_password = &password;
1401         if (set_realm)
1402             p_realm = &realm;
1403 
1404         c->setClientParams(p_username, p_authzid, p_password, p_realm);
1405     }
1406 
1407     void start()
1408     {
1409         op    = OpStart;
1410         first = true;
1411 
1412         if (server) {
1413             QCA_logTextMessage(QStringLiteral("sasl[%1]: c->startServer()").arg(q->objectName()), Logger::Information);
1414             c->startServer(server_realm, disableServerSendLast);
1415         } else {
1416             QCA_logTextMessage(QStringLiteral("sasl[%1]: c->startClient()").arg(q->objectName()), Logger::Information);
1417             c->startClient(mechlist, allowClientSendFirst);
1418         }
1419     }
1420 
1421     void putServerFirstStep(const QString &mech, const QByteArray *clientInit)
1422     {
1423         if (op != -1)
1424             return;
1425 
1426         QCA_logTextMessage(QStringLiteral("sasl[%1]: c->serverFirstStep()").arg(q->objectName()), Logger::Information);
1427         op = OpServerFirstStep;
1428         c->serverFirstStep(mech, clientInit);
1429     }
1430 
1431     void putStep(const QByteArray &stepData)
1432     {
1433         if (op != -1)
1434             return;
1435 
1436         QCA_logTextMessage(QStringLiteral("sasl[%1]: c->nextStep()").arg(q->objectName()), Logger::Information);
1437         op = OpNextStep;
1438         c->nextStep(stepData);
1439     }
1440 
1441     void tryAgain()
1442     {
1443         if (op != -1)
1444             return;
1445 
1446         QCA_logTextMessage(QStringLiteral("sasl[%1]: c->tryAgain()").arg(q->objectName()), Logger::Information);
1447         op = OpTryAgain;
1448         c->tryAgain();
1449     }
1450 
1451     void processNextAction()
1452     {
1453         if (actionQueue.isEmpty()) {
1454             if (need_update)
1455                 update();
1456             return;
1457         }
1458 
1459         const Action a = actionQueue.takeFirst();
1460 
1461         // set up for the next one, if necessary
1462         if (!actionQueue.isEmpty() || need_update) {
1463             if (!actionTrigger.isActive())
1464                 actionTrigger.start();
1465         }
1466 
1467         if (a.type == Action::ClientStarted) {
1468             emit q->clientStarted(a.haveInit, a.stepData);
1469         } else if (a.type == Action::NextStep) {
1470             emit q->nextStep(a.stepData);
1471         } else if (a.type == Action::Authenticated) {
1472             authed = true;
1473 
1474             // write any app data waiting during authentication
1475             if (!out.isEmpty()) {
1476                 need_update = true;
1477                 if (!actionTrigger.isActive())
1478                     actionTrigger.start();
1479             }
1480 
1481             QCA_logTextMessage(QStringLiteral("sasl[%1]: authenticated").arg(q->objectName()), Logger::Information);
1482             emit q->authenticated();
1483         } else if (a.type == Action::ReadyRead) {
1484             emit q->readyRead();
1485         } else if (a.type == Action::ReadyReadOutgoing) {
1486             emit q->readyReadOutgoing();
1487         }
1488     }
1489 
1490     void update()
1491     {
1492         // defer writes while authenticating
1493         if (!authed) {
1494             QCA_logTextMessage(
1495                 QStringLiteral("sasl[%1]: ignoring update while not yet authenticated").arg(q->objectName()),
1496                 Logger::Information);
1497             return;
1498         }
1499 
1500         if (!actionQueue.isEmpty()) {
1501             QCA_logTextMessage(
1502                 QStringLiteral("sasl[%1]: ignoring update while processing actions").arg(q->objectName()),
1503                 Logger::Information);
1504             need_update = true;
1505             return;
1506         }
1507 
1508         // only allow one operation at a time
1509         if (op != -1) {
1510             QCA_logTextMessage(QStringLiteral("sasl[%1]: ignoring update while operation active").arg(q->objectName()),
1511                                Logger::Information);
1512             need_update = true;
1513             return;
1514         }
1515 
1516         need_update = false;
1517 
1518         QCA_logTextMessage(QStringLiteral("sasl[%1]: c->update()").arg(q->objectName()), Logger::Information);
1519         op = OpUpdate;
1520         out_pending += out.size();
1521         c->update(from_net, out);
1522         from_net.clear();
1523         out.clear();
1524     }
1525 
1526 private Q_SLOTS:
1527     void sasl_resultsReady()
1528     {
1529         QCA_logTextMessage(QStringLiteral("sasl[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information);
1530 
1531         int last_op = op;
1532         op          = -1;
1533 
1534         const SASLContext::Result r = c->result();
1535 
1536         if (last_op == OpStart) {
1537             if (server) {
1538                 if (r != SASLContext::Success) {
1539                     errorCode = SASL::ErrorInit;
1540                     emit q->error();
1541                     return;
1542                 }
1543 
1544                 emit q->serverStarted();
1545                 return;
1546             } else // client
1547             {
1548                 mech = c->mech();
1549 
1550                 // fall into this logic
1551                 last_op = OpTryAgain;
1552             }
1553         } else if (last_op == OpServerFirstStep) {
1554             // fall into this logic
1555             last_op = OpTryAgain;
1556         } else if (last_op == OpNextStep) {
1557             // fall into this logic
1558             last_op = OpTryAgain;
1559         }
1560 
1561         if (last_op == OpTryAgain) {
1562             if (server) {
1563                 if (r == SASLContext::Continue) {
1564                     emit q->nextStep(c->stepData());
1565                     return;
1566                 } else if (r == SASLContext::AuthCheck) {
1567                     emit q->authCheck(c->username(), c->authzid());
1568                     return;
1569                 } else if (r == SASLContext::Success) {
1570                     if (!disableServerSendLast)
1571                         actionQueue += Action(Action::NextStep, c->stepData());
1572 
1573                     actionQueue += Action(Action::Authenticated);
1574 
1575                     processNextAction();
1576                     return;
1577                 } else // error
1578                 {
1579                     errorCode = SASL::ErrorHandshake;
1580                     emit q->error();
1581                     return;
1582                 }
1583             } else // client
1584             {
1585                 if (first) {
1586                     if (r == SASLContext::Error) {
1587                         if (first)
1588                             errorCode = SASL::ErrorInit;
1589                         else
1590                             errorCode = SASL::ErrorHandshake;
1591                         emit q->error();
1592                         return;
1593                     } else if (r == SASLContext::Params) {
1594                         const Params np = c->clientParams();
1595                         emit         q->needParams(np);
1596                         return;
1597                     }
1598 
1599                     first = false;
1600                     actionQueue += Action(Action::ClientStarted, c->haveClientInit(), c->stepData());
1601                     if (r == SASLContext::Success)
1602                         actionQueue += Action(Action::Authenticated);
1603 
1604                     processNextAction();
1605                     return;
1606                 } else {
1607                     if (r == SASLContext::Error) {
1608                         errorCode = ErrorHandshake;
1609                         emit q->error();
1610                         return;
1611                     } else if (r == SASLContext::Params) {
1612                         const Params np = c->clientParams();
1613                         emit         q->needParams(np);
1614                         return;
1615                     } else if (r == SASLContext::Continue) {
1616                         emit q->nextStep(c->stepData());
1617                         return;
1618                     } else if (r == SASLContext::Success) {
1619                         actionQueue += Action(Action::NextStep, c->stepData());
1620                         actionQueue += Action(Action::Authenticated);
1621 
1622                         processNextAction();
1623                         return;
1624                     }
1625                 }
1626             }
1627         } else if (last_op == OpUpdate) {
1628             if (r != SASLContext::Success) {
1629                 errorCode = ErrorCrypt;
1630                 emit q->error();
1631                 return;
1632             }
1633 
1634             const QByteArray c_to_net = c->to_net();
1635             const QByteArray c_to_app = c->to_app();
1636             int              enc      = -1;
1637             if (!c_to_net.isEmpty())
1638                 enc = c->encoded();
1639 
1640             bool io_pending = false;
1641             if (!c_to_net.isEmpty())
1642                 out_pending -= enc;
1643 
1644             if (out_pending > 0)
1645                 io_pending = true;
1646 
1647             if (!out.isEmpty())
1648                 io_pending = true;
1649 
1650             to_net += c_to_net;
1651             in += c_to_app;
1652             to_net_encoded += enc;
1653 
1654             if (!c_to_net.isEmpty())
1655                 actionQueue += Action(Action::ReadyReadOutgoing);
1656 
1657             if (!c_to_app.isEmpty())
1658                 actionQueue += Action(Action::ReadyRead);
1659 
1660             if (io_pending)
1661                 update();
1662 
1663             processNextAction();
1664             return;
1665         }
1666     }
1667 
1668     void doNextAction()
1669     {
1670         processNextAction();
1671     }
1672 };
1673 
1674 SASL::SASL(QObject *parent, const QString &provider)
1675     : SecureLayer(parent)
1676     , Algorithm(QStringLiteral("sasl"), provider)
1677 {
1678     d = new Private(this);
1679 }
1680 
1681 SASL::~SASL()
1682 {
1683     delete d;
1684 }
1685 
1686 void SASL::reset()
1687 {
1688     d->reset(ResetAll);
1689 }
1690 
1691 SASL::Error SASL::errorCode() const
1692 {
1693     return d->errorCode;
1694 }
1695 
1696 SASL::AuthCondition SASL::authCondition() const
1697 {
1698     return d->c->authCondition();
1699 }
1700 
1701 void SASL::setConstraints(AuthFlags f, SecurityLevel s)
1702 {
1703     int min = 0;
1704     if (s == SL_Integrity)
1705         min = 1;
1706     else if (s == SL_Export)
1707         min = 56;
1708     else if (s == SL_Baseline)
1709         min = 128;
1710     else if (s == SL_High)
1711         min = 192;
1712     else if (s == SL_Highest)
1713         min = 256;
1714 
1715     setConstraints(f, min, 256);
1716 }
1717 
1718 void SASL::setConstraints(AuthFlags f, int minSSF, int maxSSF)
1719 {
1720     d->auth_flags = f;
1721 
1722     d->ssfmin = minSSF;
1723     d->ssfmax = maxSSF;
1724 }
1725 
1726 void SASL::setExternalAuthId(const QString &authid)
1727 {
1728     d->ext_authid = authid;
1729 }
1730 
1731 void SASL::setExternalSSF(int strength)
1732 {
1733     d->ext_ssf = strength;
1734 }
1735 
1736 void SASL::setLocalAddress(const QString &addr, quint16 port)
1737 {
1738     d->localSet   = true;
1739     d->local.addr = addr;
1740     d->local.port = port;
1741 }
1742 
1743 void SASL::setRemoteAddress(const QString &addr, quint16 port)
1744 {
1745     d->remoteSet   = true;
1746     d->remote.addr = addr;
1747     d->remote.port = port;
1748 }
1749 
1750 void SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, ClientSendMode mode)
1751 {
1752     d->reset(ResetSessionAndData);
1753     d->setup(service, host);
1754     d->server               = false;
1755     d->mechlist             = mechlist;
1756     d->allowClientSendFirst = (mode == AllowClientSendFirst);
1757     d->start();
1758 }
1759 
1760 void SASL::startServer(const QString &service, const QString &host, const QString &realm, ServerSendMode mode)
1761 {
1762     d->reset(ResetSessionAndData);
1763     d->setup(service, host);
1764     d->server                = true;
1765     d->server_realm          = realm;
1766     d->disableServerSendLast = (mode == DisableServerSendLast);
1767     d->start();
1768 }
1769 
1770 void SASL::putServerFirstStep(const QString &mech)
1771 {
1772     d->putServerFirstStep(mech, nullptr);
1773 }
1774 
1775 void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
1776 {
1777     d->putServerFirstStep(mech, &clientInit);
1778 }
1779 
1780 void SASL::putStep(const QByteArray &stepData)
1781 {
1782     d->putStep(stepData);
1783 }
1784 
1785 void SASL::setUsername(const QString &user)
1786 {
1787     d->set_username = true;
1788     d->username     = user;
1789     d->c->setClientParams(&user, nullptr, nullptr, nullptr);
1790 }
1791 
1792 void SASL::setAuthzid(const QString &authzid)
1793 {
1794     d->set_authzid = true;
1795     d->authzid     = authzid;
1796     d->c->setClientParams(nullptr, &authzid, nullptr, nullptr);
1797 }
1798 
1799 void SASL::setPassword(const SecureArray &pass)
1800 {
1801     d->set_password = true;
1802     d->password     = pass;
1803     d->c->setClientParams(nullptr, nullptr, &pass, nullptr);
1804 }
1805 
1806 void SASL::setRealm(const QString &realm)
1807 {
1808     d->set_realm = true;
1809     d->realm     = realm;
1810     d->c->setClientParams(nullptr, nullptr, nullptr, &realm);
1811 }
1812 
1813 void SASL::continueAfterParams()
1814 {
1815     d->tryAgain();
1816 }
1817 
1818 void SASL::continueAfterAuthCheck()
1819 {
1820     d->tryAgain();
1821 }
1822 
1823 QString SASL::mechanism() const
1824 {
1825     return d->mech;
1826 }
1827 
1828 QStringList SASL::mechanismList() const
1829 {
1830     return d->c->mechlist();
1831 }
1832 
1833 QStringList SASL::realmList() const
1834 {
1835     return d->c->realmlist();
1836 }
1837 
1838 int SASL::ssf() const
1839 {
1840     return d->c->ssf();
1841 }
1842 
1843 int SASL::bytesAvailable() const
1844 {
1845     return d->in.size();
1846 }
1847 
1848 int SASL::bytesOutgoingAvailable() const
1849 {
1850     return d->to_net.size();
1851 }
1852 
1853 void SASL::write(const QByteArray &a)
1854 {
1855     d->out.append(a);
1856     d->layer.addPlain(a.size());
1857     d->update();
1858 }
1859 
1860 QByteArray SASL::read()
1861 {
1862     const QByteArray a = d->in;
1863     d->in.clear();
1864     return a;
1865 }
1866 
1867 void SASL::writeIncoming(const QByteArray &a)
1868 {
1869     d->from_net.append(a);
1870     d->update();
1871 }
1872 
1873 QByteArray SASL::readOutgoing(int *plainBytes)
1874 {
1875     const QByteArray a = d->to_net;
1876     d->to_net.clear();
1877     if (plainBytes)
1878         *plainBytes = d->to_net_encoded;
1879     d->layer.specifyEncoded(a.size(), d->to_net_encoded);
1880     d->to_net_encoded = 0;
1881     return a;
1882 }
1883 
1884 int SASL::convertBytesWritten(qint64 bytes)
1885 {
1886     return d->layer.finished(bytes);
1887 }
1888 
1889 }
1890 
1891 #include "qca_securelayer.moc"