1/*
2 * Copyright (C) 2003-2007 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net>
4 *
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.
9 *
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.
14 *
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., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA
19 *
20 */
21
22#include "qca_securelayer.h"
23
24#include "qca_safeobj.h"
25#include "qca_safetimer.h"
26#include "qcaprovider.h"
27
28#include <QMetaMethod>
29#include <QPointer>
30
31namespace QCA {
32
33Provider::Context *getContext(const QString &type, const QString &provider);
34
35enum ResetMode
36{
37 ResetSession = 0,
38 ResetSessionAndData = 1,
39 ResetAll = 2
40};
41
42//----------------------------------------------------------------------------
43// LayerTracker
44//----------------------------------------------------------------------------
45class LayerTracker
46{
47private:
48 struct Item
49 {
50 int plain;
51 qint64 encoded;
52 };
53
54 int p;
55 QList<Item> list;
56
57public:
58 LayerTracker()
59 {
60 p = 0;
61 }
62
63 void reset()
64 {
65 p = 0;
66 list.clear();
67 }
68
69 void addPlain(int plain)
70 {
71 p += plain;
72 }
73
74 void specifyEncoded(int encoded, int plain)
75 {
76 // can't specify more bytes than we have
77 if (plain > p)
78 plain = p;
79 p -= plain;
80 Item i;
81 i.plain = plain;
82 i.encoded = encoded;
83 list += i;
84 }
85
86 int finished(qint64 encoded)
87 {
88 int plain = 0;
89 for (QList<Item>::Iterator it = list.begin(); it != list.end();) {
90 Item &i = *it;
91
92 // not enough?
93 if (encoded < i.encoded) {
94 i.encoded -= encoded;
95 break;
96 }
97
98 encoded -= i.encoded;
99 plain += i.plain;
100 it = list.erase(pos: it);
101 }
102 return plain;
103 }
104};
105
106//----------------------------------------------------------------------------
107// SecureLayer
108//----------------------------------------------------------------------------
109SecureLayer::SecureLayer(QObject *parent)
110 : QObject(parent)
111{
112}
113
114bool SecureLayer::isClosable() const
115{
116 return false;
117}
118
119void SecureLayer::close()
120{
121}
122
123QByteArray SecureLayer::readUnprocessed()
124{
125 return QByteArray();
126}
127
128//----------------------------------------------------------------------------
129// TLSSession
130//----------------------------------------------------------------------------
131TLSSession::TLSSession()
132{
133}
134
135TLSSession::TLSSession(const TLSSession &from)
136 : Algorithm(from)
137{
138}
139
140TLSSession::~TLSSession()
141{
142}
143
144TLSSession &TLSSession::operator=(const TLSSession &from)
145{
146 Algorithm::operator=(from);
147 return *this;
148}
149
150bool TLSSession::isNull() const
151{
152 return (!context() ? true : false);
153}
154
155//----------------------------------------------------------------------------
156// TLS
157//----------------------------------------------------------------------------
158class TLS::Private : public QObject
159{
160 Q_OBJECT
161public:
162 enum
163 {
164 OpStart,
165 OpUpdate
166 };
167
168 enum State
169 {
170 Inactive,
171 Initializing,
172 Handshaking,
173 Connected,
174 Closing
175 };
176
177 class Action
178 {
179 public:
180 enum Type
181 {
182 ReadyRead,
183 ReadyReadOutgoing,
184 Handshaken,
185 Close,
186 CheckPeerCertificate,
187 CertificateRequested,
188 HostNameReceived
189 };
190
191 int type;
192
193 Action(int _type)
194 : type(_type)
195 {
196 }
197 };
198
199 TLS *q;
200 TLSContext *c;
201 TLS::Mode mode;
202
203 // signal connected flags
204 bool connect_hostNameReceived;
205 bool connect_certificateRequested;
206 bool connect_peerCertificateAvailable;
207 bool connect_handshaken;
208
209 // persistent settings (survives ResetSessionAndData)
210 CertificateChain localCert;
211 PrivateKey localKey;
212 CertificateCollection trusted;
213 bool con_ssfMode;
214 int con_minSSF, con_maxSSF;
215 QStringList con_cipherSuites;
216 bool tryCompress;
217 int packet_mtu;
218 QList<CertificateInfoOrdered> issuerList;
219 TLSSession session;
220
221 // session
222 State state;
223 bool blocked;
224 bool server;
225 QString host;
226 TLSContext::SessionInfo sessionInfo;
227 SafeTimer actionTrigger;
228 int op;
229 QList<Action> actionQueue;
230 bool need_update;
231 bool maybe_input;
232 bool emitted_hostNameReceived;
233 bool emitted_certificateRequested;
234 bool emitted_peerCertificateAvailable;
235
236 // data (survives ResetSession)
237 CertificateChain peerCert;
238 Validity peerValidity;
239 bool hostMismatch;
240 Error errorCode;
241
242 // stream i/o
243 QByteArray in, out;
244 QByteArray to_net, from_net;
245 QByteArray unprocessed;
246 int out_pending;
247 int to_net_encoded;
248 LayerTracker layer;
249
250 // datagram i/o
251 QList<QByteArray> packet_in, packet_out;
252 QList<QByteArray> packet_to_net, packet_from_net;
253 int packet_out_pending; // packet count
254 QList<int> packet_to_net_encoded;
255
256 Private(TLS *_q, TLS::Mode _mode)
257 : QObject(_q)
258 , q(_q)
259 , mode(_mode)
260 , actionTrigger(this)
261 {
262 // c is 0 during initial reset, so we don't redundantly reset it
263 c = nullptr;
264 connect_hostNameReceived = false;
265 connect_certificateRequested = false;
266 connect_peerCertificateAvailable = false;
267 connect_handshaken = false;
268 server = false;
269
270 connect(sender: &actionTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doNextAction);
271 actionTrigger.setSingleShot(true);
272
273 reset(mode: ResetAll);
274
275 c = static_cast<TLSContext *>(q->context());
276
277 // parent the context to us, so that moveToThread works
278 c->setParent(this);
279
280 connect(sender: c, signal: &TLSContext::resultsReady, context: this, slot: &Private::tls_resultsReady);
281 connect(sender: c, signal: &TLSContext::dtlsTimeout, context: this, slot: &Private::tls_dtlsTimeout);
282 }
283
284 ~Private() override
285 {
286 // context is owned by Algorithm, unparent so we don't double-delete
287 c->setParent(nullptr);
288 }
289
290 void reset(ResetMode mode)
291 {
292 if (c)
293 c->reset();
294
295 // if we reset while in client mode, then clear this list
296 // (it should only persist when used for server mode)
297 if (!server)
298 issuerList.clear();
299
300 state = Inactive;
301 blocked = false;
302 server = false;
303 host = QString();
304 sessionInfo = TLSContext::SessionInfo();
305 actionTrigger.stop();
306 op = -1;
307 actionQueue.clear();
308 need_update = false;
309 maybe_input = false;
310 emitted_hostNameReceived = false;
311 emitted_certificateRequested = false;
312 emitted_peerCertificateAvailable = false;
313
314 out.clear();
315 out_pending = 0;
316 packet_out.clear();
317 packet_out_pending = 0;
318
319 if (mode >= ResetSessionAndData) {
320 peerCert = CertificateChain();
321 peerValidity = ErrorValidityUnknown;
322 hostMismatch = false;
323 errorCode = (TLS::Error)-1;
324
325 in.clear();
326 to_net.clear();
327 from_net.clear();
328 unprocessed.clear();
329 to_net_encoded = 0;
330 layer.reset();
331
332 packet_in.clear();
333 packet_to_net.clear();
334 packet_from_net.clear();
335 packet_to_net_encoded.clear();
336 }
337
338 if (mode >= ResetAll) {
339 localCert = CertificateChain();
340 localKey = PrivateKey();
341 trusted = CertificateCollection();
342 con_ssfMode = true;
343 con_minSSF = 128;
344 con_maxSSF = -1;
345 con_cipherSuites = QStringList();
346 tryCompress = false;
347 packet_mtu = -1;
348 issuerList.clear();
349 session = TLSSession();
350 }
351 }
352
353 void start(bool serverMode)
354 {
355 state = Initializing;
356 server = serverMode;
357
358 c->setup(serverMode, hostName: host, compress: tryCompress);
359
360 if (con_ssfMode)
361 c->setConstraints(minSSF: con_minSSF, maxSSF: con_maxSSF);
362 else
363 c->setConstraints(con_cipherSuites);
364
365 c->setCertificate(cert: localCert, key: localKey);
366 c->setTrustedCertificates(trusted);
367 if (serverMode)
368 c->setIssuerList(issuerList);
369 if (!session.isNull()) {
370 TLSSessionContext *sc = static_cast<TLSSessionContext *>(session.context());
371 c->setSessionId(*sc);
372 }
373 c->setMTU(packet_mtu);
374
375 QCA_logTextMessage(QStringLiteral("tls[%1]: c->start()").arg(q->objectName()), Logger::Information);
376 op = OpStart;
377 c->start();
378 }
379
380 void close()
381 {
382 QCA_logTextMessage(QStringLiteral("tls[%1]: close").arg(q->objectName()), Logger::Information);
383
384 if (state != Connected)
385 return;
386
387 state = Closing;
388 c->shutdown();
389 }
390
391 void continueAfterStep()
392 {
393 QCA_logTextMessage(QStringLiteral("tls[%1]: continueAfterStep").arg(q->objectName()), Logger::Information);
394
395 if (!blocked)
396 return;
397
398 blocked = false;
399 update();
400 }
401
402 void processNextAction()
403 {
404 if (actionQueue.isEmpty()) {
405 if (need_update) {
406 QCA_logTextMessage(QStringLiteral("tls[%1]: need_update").arg(q->objectName()), Logger::Information);
407 update();
408 }
409 return;
410 }
411
412 const Action a = actionQueue.takeFirst();
413
414 // set up for the next one, if necessary
415 if (!actionQueue.isEmpty() || need_update) {
416 if (!actionTrigger.isActive())
417 actionTrigger.start();
418 }
419
420 if (a.type == Action::ReadyRead) {
421 emit q->readyRead();
422 } else if (a.type == Action::ReadyReadOutgoing) {
423 emit q->readyReadOutgoing();
424 } else if (a.type == Action::Handshaken) {
425 state = Connected;
426
427 // write any app data waiting during handshake
428 if (!out.isEmpty()) {
429 need_update = true;
430 if (!actionTrigger.isActive())
431 actionTrigger.start();
432 }
433
434 QCA_logTextMessage(QStringLiteral("tls[%1]: handshaken").arg(q->objectName()), Logger::Information);
435
436 if (connect_handshaken) {
437 blocked = true;
438 emit q->handshaken();
439 }
440 } else if (a.type == Action::Close) {
441 unprocessed = c->unprocessed();
442 reset(mode: ResetSession);
443 emit q->closed();
444 } else if (a.type == Action::CheckPeerCertificate) {
445 peerCert = c->peerCertificateChain();
446 if (!peerCert.isEmpty()) {
447 peerValidity = c->peerCertificateValidity();
448 if (peerValidity == ValidityGood && !host.isEmpty() && !peerCert.primary().matchesHostName(host))
449 hostMismatch = true;
450 }
451
452 if (connect_peerCertificateAvailable) {
453 blocked = true;
454 emitted_peerCertificateAvailable = true;
455 emit q->peerCertificateAvailable();
456 }
457 } else if (a.type == Action::CertificateRequested) {
458 issuerList = c->issuerList();
459 if (connect_certificateRequested) {
460 blocked = true;
461 emitted_certificateRequested = true;
462 emit q->certificateRequested();
463 }
464 } else if (a.type == Action::HostNameReceived) {
465 if (connect_hostNameReceived) {
466 blocked = true;
467 emitted_hostNameReceived = true;
468 emit q->hostNameReceived();
469 }
470 }
471 }
472
473 void update()
474 {
475 QCA_logTextMessage(QStringLiteral("tls[%1]: update").arg(q->objectName()), Logger::Information);
476
477 if (blocked) {
478 QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while blocked").arg(q->objectName()),
479 Logger::Information);
480 return;
481 }
482
483 if (!actionQueue.isEmpty()) {
484 QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while processing actions").arg(q->objectName()),
485 Logger::Information);
486 need_update = true;
487 return;
488 }
489
490 // only allow one operation at a time
491 if (op != -1) {
492 QCA_logTextMessage(QStringLiteral("tls[%1]: ignoring update while operation active").arg(q->objectName()),
493 Logger::Information);
494 need_update = true;
495 return;
496 }
497
498 need_update = false;
499
500 QByteArray arg_from_net, arg_from_app;
501
502 if (state == Handshaking) {
503 // during handshake, only send from_net (no app data)
504
505 if (mode == TLS::Stream) {
506 arg_from_net = from_net;
507 from_net.clear();
508 } else {
509 // note: there may not be a packet
510 if (!packet_from_net.isEmpty())
511 arg_from_net = packet_from_net.takeFirst();
512 }
513 } else {
514 if (mode == TLS::Stream) {
515 if (!from_net.isEmpty()) {
516 arg_from_net = from_net;
517 from_net.clear();
518 }
519
520 if (!out.isEmpty()) {
521 out_pending += out.size();
522 arg_from_app = out;
523 out.clear();
524 }
525 } else {
526 if (!packet_from_net.isEmpty())
527 arg_from_net = packet_from_net.takeFirst();
528
529 if (!packet_out.isEmpty()) {
530 arg_from_app = packet_out.takeFirst();
531 ++packet_out_pending;
532 }
533 }
534 }
535
536 if (arg_from_net.isEmpty() && arg_from_app.isEmpty() && !maybe_input) {
537 QCA_logTextMessage(
538 QStringLiteral("tls[%1]: ignoring update: no output and no expected input").arg(q->objectName()),
539 Logger::Information);
540 return;
541 }
542
543 // clear this flag
544 maybe_input = false;
545
546 QCA_logTextMessage(QStringLiteral("tls[%1]: c->update").arg(q->objectName()), Logger::Information);
547 op = OpUpdate;
548 c->update(from_net: arg_from_net, from_app: arg_from_app);
549 }
550
551 void start_finished()
552 {
553 const bool ok = c->result() == TLSContext::Success;
554 if (!ok) {
555 reset(mode: ResetSession);
556 errorCode = TLS::ErrorInit;
557 emit q->error();
558 return;
559 }
560
561 state = Handshaking;
562
563 // immediately update so we can get the first packet to send
564 maybe_input = true;
565 update();
566 }
567
568 void update_finished()
569 {
570 const TLSContext::Result r = c->result();
571 if (r == TLSContext::Error) {
572 if (state == Handshaking || state == Closing) {
573 reset(mode: ResetSession);
574 errorCode = ErrorHandshake;
575 } else {
576 reset(mode: ResetSession);
577 errorCode = ErrorCrypt;
578 }
579
580 emit q->error();
581 return;
582 }
583
584 const QByteArray c_to_net = c->to_net();
585 if (!c_to_net.isEmpty()) {
586 QCA_logTextMessage(
587 QStringLiteral("tls[%1]: to_net %2").arg(q->objectName(), QString::number(c_to_net.size())),
588 Logger::Information);
589 }
590
591 if (state == Closing) {
592 if (mode == TLS::Stream)
593 to_net += c_to_net;
594 else
595 packet_to_net += c_to_net;
596
597 if (!c_to_net.isEmpty())
598 actionQueue += Action(Action::ReadyReadOutgoing);
599
600 if (r == TLSContext::Success)
601 actionQueue += Action(Action::Close);
602
603 processNextAction();
604 return;
605 } else if (state == Handshaking) {
606 if (mode == TLS::Stream)
607 to_net += c_to_net;
608 else
609 packet_to_net += c_to_net;
610
611 if (!c_to_net.isEmpty())
612 actionQueue += Action(Action::ReadyReadOutgoing);
613
614 bool clientHello = false;
615 bool serverHello = false;
616 if (server)
617 clientHello = c->clientHelloReceived();
618 else
619 serverHello = c->serverHelloReceived();
620
621 // client specifies a host?
622 if (!emitted_hostNameReceived && clientHello) {
623 host = c->hostName();
624 if (!host.isEmpty())
625 actionQueue += Action(Action::HostNameReceived);
626 }
627
628 // successful handshake or server hello means there might be a peer cert
629 if (!emitted_peerCertificateAvailable && (r == TLSContext::Success || (!server && serverHello)))
630 actionQueue += Action(Action::CheckPeerCertificate);
631
632 // server requests a cert from us?
633 if (!emitted_certificateRequested && (serverHello && c->certificateRequested()))
634 actionQueue += Action(Action::CertificateRequested);
635
636 if (r == TLSContext::Success) {
637 sessionInfo = c->sessionInfo();
638 if (sessionInfo.id) {
639 TLSSessionContext *sc = static_cast<TLSSessionContext *>(sessionInfo.id->clone());
640 session.change(c: sc);
641 }
642
643 actionQueue += Action(Action::Handshaken);
644 }
645
646 processNextAction();
647 return;
648 } else // Connected
649 {
650 const QByteArray c_to_app = c->to_app();
651 if (!c_to_app.isEmpty()) {
652 QCA_logTextMessage(
653 QStringLiteral("tls[%1]: to_app %2").arg(q->objectName(), QString::number(c_to_app.size())),
654 Logger::Information);
655 }
656
657 const bool eof = c->eof();
658 int enc = -1;
659 if (!c_to_net.isEmpty())
660 enc = c->encoded();
661
662 bool io_pending = false;
663 if (mode == TLS::Stream) {
664 if (!c_to_net.isEmpty())
665 out_pending -= enc;
666
667 if (out_pending > 0) {
668 maybe_input = true;
669 io_pending = true;
670 }
671
672 if (!out.isEmpty())
673 io_pending = true;
674 } else {
675 if (!c_to_net.isEmpty())
676 --packet_out_pending;
677
678 if (packet_out_pending > 0) {
679 maybe_input = true;
680 io_pending = true;
681 }
682
683 if (!packet_out.isEmpty())
684 io_pending = true;
685 }
686
687 if (mode == TLS::Stream) {
688 to_net += c_to_net;
689 in += c_to_app;
690 to_net_encoded += enc;
691 } else {
692 packet_to_net += c_to_net;
693 packet_in += c_to_app;
694 }
695
696 if (!c_to_net.isEmpty())
697 actionQueue += Action(Action::ReadyReadOutgoing);
698
699 if (!c_to_app.isEmpty())
700 actionQueue += Action(Action::ReadyRead);
701
702 if (eof) {
703 close();
704 maybe_input = true;
705 }
706
707 if (eof || io_pending) {
708 QCA_logTextMessage(QStringLiteral("tls[%1]: eof || io_pending").arg(q->objectName()),
709 Logger::Information);
710 update();
711 }
712
713 processNextAction();
714 return;
715 }
716 }
717
718private Q_SLOTS:
719 void tls_resultsReady()
720 {
721 QCA_logTextMessage(QStringLiteral("tls[%1]: c->resultsReady()").arg(q->objectName()), Logger::Information);
722
723 Q_ASSERT(op != -1);
724
725 int last_op = op;
726 op = -1;
727
728 if (last_op == OpStart)
729 start_finished();
730 else // OpUpdate
731 update_finished();
732 }
733
734 void tls_dtlsTimeout()
735 {
736 QCA_logTextMessage(QStringLiteral("tls[%1]: c->dtlsTimeout()").arg(q->objectName()), Logger::Information);
737
738 maybe_input = true;
739 update();
740 }
741
742 void doNextAction()
743 {
744 processNextAction();
745 }
746};
747
748TLS::TLS(QObject *parent, const QString &provider)
749 : SecureLayer(parent)
750 , Algorithm(QStringLiteral("tls"), provider)
751{
752 d = new Private(this, TLS::Stream);
753}
754
755TLS::TLS(Mode mode, QObject *parent, const QString &provider)
756 : SecureLayer(parent)
757 , Algorithm(mode == Stream ? QStringLiteral("tls") : QStringLiteral("dtls"), provider)
758{
759 d = new Private(this, mode);
760}
761
762TLS::~TLS()
763{
764 delete d;
765}
766
767void TLS::reset()
768{
769 d->reset(mode: ResetAll);
770}
771
772QStringList TLS::supportedCipherSuites(
773 const Version &version) const // clazy:exclude=function-args-by-value TODO make it remove the & when we break ABI
774{
775 return d->c->supportedCipherSuites(version);
776}
777
778void TLS::setCertificate(const CertificateChain &cert, const PrivateKey &key)
779{
780 d->localCert = cert;
781 d->localKey = key;
782 if (d->state != TLS::Private::Inactive)
783 d->c->setCertificate(cert, key);
784}
785
786void TLS::setCertificate(const KeyBundle &kb)
787{
788 setCertificate(cert: kb.certificateChain(), key: kb.privateKey());
789}
790
791CertificateCollection TLS::trustedCertificates() const
792{
793 return d->trusted;
794}
795
796void TLS::setTrustedCertificates(const CertificateCollection &trusted)
797{
798 d->trusted = trusted;
799 if (d->state != TLS::Private::Inactive)
800 d->c->setTrustedCertificates(trusted);
801}
802
803void TLS::setConstraints(SecurityLevel s)
804{
805 int min = 128;
806 switch (s) {
807 case SL_None:
808 min = 0;
809 break;
810 case SL_Integrity:
811 min = 1;
812 break;
813 case SL_Export:
814 min = 40;
815 break;
816 case SL_Baseline:
817 min = 128;
818 break;
819 case SL_High:
820 min = 129;
821 break;
822 case SL_Highest:
823 min = qMax(a: 129, b: d->c->maxSSF());
824 break;
825 }
826
827 d->con_ssfMode = true;
828 d->con_minSSF = min;
829 d->con_maxSSF = -1;
830
831 if (d->state != TLS::Private::Inactive)
832 d->c->setConstraints(minSSF: d->con_minSSF, maxSSF: d->con_maxSSF);
833}
834
835void TLS::setConstraints(int minSSF, int maxSSF)
836{
837 d->con_ssfMode = true;
838 d->con_minSSF = minSSF;
839 d->con_maxSSF = maxSSF;
840
841 if (d->state != TLS::Private::Inactive)
842 d->c->setConstraints(minSSF: d->con_minSSF, maxSSF: d->con_maxSSF);
843}
844
845void TLS::setConstraints(const QStringList &cipherSuiteList)
846{
847 d->con_ssfMode = false;
848 d->con_cipherSuites = cipherSuiteList;
849
850 if (d->state != TLS::Private::Inactive)
851 d->c->setConstraints(d->con_cipherSuites);
852}
853
854QList<CertificateInfoOrdered> TLS::issuerList() const
855{
856 return d->issuerList;
857}
858
859void TLS::setIssuerList(const QList<CertificateInfoOrdered> &issuers)
860{
861 d->issuerList = issuers;
862 if (d->state != TLS::Private::Inactive)
863 d->c->setIssuerList(issuers);
864}
865
866void TLS::setSession(const TLSSession &session)
867{
868 d->session = session;
869}
870
871bool TLS::canCompress() const
872{
873 return d->c->canCompress();
874}
875
876bool TLS::canSetHostName() const
877{
878 return d->c->canSetHostName();
879}
880
881bool TLS::compressionEnabled() const
882{
883 return d->tryCompress;
884}
885
886void TLS::setCompressionEnabled(bool b)
887{
888 d->tryCompress = b;
889}
890
891void TLS::startClient(const QString &host)
892{
893 d->reset(mode: ResetSessionAndData);
894 d->host = host;
895 d->issuerList.clear();
896
897 // client mode
898 d->start(serverMode: false);
899}
900
901void TLS::startServer()
902{
903 d->reset(mode: ResetSessionAndData);
904
905 // server mode
906 d->start(serverMode: true);
907}
908
909void TLS::continueAfterStep()
910{
911 d->continueAfterStep();
912}
913
914bool TLS::isHandshaken() const
915{
916 if (d->state == TLS::Private::Connected || d->state == TLS::Private::Closing)
917 return true;
918 else
919 return false;
920}
921
922bool TLS::isCompressed() const
923{
924 return d->sessionInfo.isCompressed;
925}
926
927TLS::Version TLS::version() const
928{
929 return d->sessionInfo.version;
930}
931
932QString TLS::cipherSuite() const
933{
934 return d->sessionInfo.cipherSuite;
935}
936
937int TLS::cipherBits() const
938{
939 return d->sessionInfo.cipherBits;
940}
941
942int TLS::cipherMaxBits() const
943{
944 return d->sessionInfo.cipherMaxBits;
945}
946
947TLSSession TLS::session() const
948{
949 return d->session;
950}
951
952TLS::Error TLS::errorCode() const
953{
954 return d->errorCode;
955}
956
957TLS::IdentityResult TLS::peerIdentityResult() const
958{
959 if (d->peerCert.isEmpty())
960 return NoCertificate;
961
962 if (d->peerValidity != ValidityGood)
963 return InvalidCertificate;
964
965 if (d->hostMismatch)
966 return HostMismatch;
967
968 return Valid;
969}
970
971Validity TLS::peerCertificateValidity() const
972{
973 return d->peerValidity;
974}
975
976CertificateChain TLS::localCertificateChain() const
977{
978 return d->localCert;
979}
980
981PrivateKey TLS::localPrivateKey() const
982{
983 return d->localKey;
984}
985
986CertificateChain TLS::peerCertificateChain() const
987{
988 return d->peerCert;
989}
990
991bool TLS::isClosable() const
992{
993 return true;
994}
995
996int TLS::bytesAvailable() const
997{
998 if (d->mode == Stream)
999 return d->in.size();
1000 else
1001 return 0;
1002}
1003
1004int TLS::bytesOutgoingAvailable() const
1005{
1006 if (d->mode == Stream)
1007 return d->to_net.size();
1008 else
1009 return 0;
1010}
1011
1012void TLS::close()
1013{
1014 d->close();
1015 d->update();
1016}
1017
1018void TLS::write(const QByteArray &a)
1019{
1020 if (d->mode == Stream) {
1021 d->out.append(a);
1022 d->layer.addPlain(plain: a.size());
1023 } else
1024 d->packet_out.append(t: a);
1025 QCA_logTextMessage(QStringLiteral("tls[%1]: write").arg(objectName()), Logger::Information);
1026 d->update();
1027}
1028
1029QByteArray 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
1043void 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(t: a);
1049 QCA_logTextMessage(QStringLiteral("tls[%1]: writeIncoming %2").arg(objectName(), QString::number(a.size())),
1050 Logger::Information);
1051 d->update();
1052}
1053
1054QByteArray 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(encoded: a.size(), plain: 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
1079QByteArray 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
1089int TLS::convertBytesWritten(qint64 bytes)
1090{
1091 return d->layer.finished(encoded: bytes);
1092}
1093
1094int TLS::packetsAvailable() const
1095{
1096 return d->packet_in.count();
1097}
1098
1099int TLS::packetsOutgoingAvailable() const
1100{
1101 return d->packet_to_net.count();
1102}
1103
1104int TLS::packetMTU() const
1105{
1106 return d->packet_mtu;
1107}
1108
1109void 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
1116void TLS::connectNotify(const QMetaMethod &signal)
1117{
1118 if (signal == QMetaMethod::fromSignal(signal: &TLS::hostNameReceived))
1119 d->connect_hostNameReceived = true;
1120 else if (signal == QMetaMethod::fromSignal(signal: &TLS::certificateRequested))
1121 d->connect_certificateRequested = true;
1122 else if (signal == QMetaMethod::fromSignal(signal: &TLS::peerCertificateAvailable))
1123 d->connect_peerCertificateAvailable = true;
1124 else if (signal == QMetaMethod::fromSignal(signal: &TLS::handshaken))
1125 d->connect_handshaken = true;
1126}
1127
1128void TLS::disconnectNotify(const QMetaMethod &signal)
1129{
1130 if (signal == QMetaMethod::fromSignal(signal: &TLS::hostNameReceived))
1131 d->connect_hostNameReceived = false;
1132 else if (signal == QMetaMethod::fromSignal(signal: &TLS::certificateRequested))
1133 d->connect_certificateRequested = false;
1134 else if (signal == QMetaMethod::fromSignal(signal: &TLS::peerCertificateAvailable))
1135 d->connect_peerCertificateAvailable = false;
1136 else if (signal == QMetaMethod::fromSignal(signal: &TLS::handshaken))
1137 d->connect_handshaken = false;
1138}
1139
1140//----------------------------------------------------------------------------
1141// SASL::Params
1142//----------------------------------------------------------------------------
1143class SASL::Params::Private
1144{
1145public:
1146 bool needUsername, canSendAuthzid, needPassword, canSendRealm;
1147};
1148
1149SASL::Params::Params()
1150 : d(new Private)
1151{
1152}
1153
1154SASL::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
1163SASL::Params::Params(const SASL::Params &from)
1164 : d(new Private(*from.d))
1165{
1166}
1167
1168SASL::Params::~Params()
1169{
1170 delete d;
1171}
1172
1173SASL::Params &SASL::Params::operator=(const SASL::Params &from)
1174{
1175 *d = *from.d;
1176 return *this;
1177}
1178
1179bool SASL::Params::needUsername() const
1180{
1181 return d->needUsername;
1182}
1183
1184bool SASL::Params::canSendAuthzid() const
1185{
1186 return d->canSendAuthzid;
1187}
1188
1189bool SASL::Params::needPassword() const
1190{
1191 return d->needPassword;
1192}
1193
1194bool 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
1216class SASL::Private : public QObject
1217{
1218 Q_OBJECT
1219public:
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(sender: &actionTrigger, signal: &SafeTimer::timeout, context: this, slot: &Private::doNextAction);
1314 actionTrigger.setSingleShot(true);
1315
1316 reset(mode: 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(sender: c, signal: &SASLContext::resultsReady, context: this, slot: &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, local: localSet ? &local : nullptr, remote: remoteSet ? &remote : nullptr, ext_id: ext_authid, ext_ssf);
1388 c->setConstraints(f: auth_flags, minSSF: ssfmin, maxSSF: 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(user: p_username, authzid: p_authzid, pass: p_password, realm: 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(realm: 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(from_net: 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(clientInit: a.haveInit, clientInitData: a.stepData);
1469 } else if (a.type == Action::NextStep) {
1470 emit q->nextStep(stepData: 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, from_app: out);
1522 from_net.clear();
1523 out.clear();
1524 }
1525
1526private 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(stepData: c->stepData());
1565 return;
1566 } else if (r == SASLContext::AuthCheck) {
1567 emit q->authCheck(user: c->username(), authzid: 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(params: 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(params: np);
1614 return;
1615 } else if (r == SASLContext::Continue) {
1616 emit q->nextStep(stepData: 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
1674SASL::SASL(QObject *parent, const QString &provider)
1675 : SecureLayer(parent)
1676 , Algorithm(QStringLiteral("sasl"), provider)
1677{
1678 d = new Private(this);
1679}
1680
1681SASL::~SASL()
1682{
1683 delete d;
1684}
1685
1686void SASL::reset()
1687{
1688 d->reset(mode: ResetAll);
1689}
1690
1691SASL::Error SASL::errorCode() const
1692{
1693 return d->errorCode;
1694}
1695
1696SASL::AuthCondition SASL::authCondition() const
1697{
1698 return d->c->authCondition();
1699}
1700
1701void 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, minSSF: min, maxSSF: 256);
1716}
1717
1718void 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
1726void SASL::setExternalAuthId(const QString &authid)
1727{
1728 d->ext_authid = authid;
1729}
1730
1731void SASL::setExternalSSF(int strength)
1732{
1733 d->ext_ssf = strength;
1734}
1735
1736void SASL::setLocalAddress(const QString &addr, quint16 port)
1737{
1738 d->localSet = true;
1739 d->local.addr = addr;
1740 d->local.port = port;
1741}
1742
1743void SASL::setRemoteAddress(const QString &addr, quint16 port)
1744{
1745 d->remoteSet = true;
1746 d->remote.addr = addr;
1747 d->remote.port = port;
1748}
1749
1750void SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, ClientSendMode mode)
1751{
1752 d->reset(mode: ResetSessionAndData);
1753 d->setup(service, host);
1754 d->server = false;
1755 d->mechlist = mechlist;
1756 d->allowClientSendFirst = (mode == AllowClientSendFirst);
1757 d->start();
1758}
1759
1760void SASL::startServer(const QString &service, const QString &host, const QString &realm, ServerSendMode mode)
1761{
1762 d->reset(mode: 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
1770void SASL::putServerFirstStep(const QString &mech)
1771{
1772 d->putServerFirstStep(mech, clientInit: nullptr);
1773}
1774
1775void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
1776{
1777 d->putServerFirstStep(mech, clientInit: &clientInit);
1778}
1779
1780void SASL::putStep(const QByteArray &stepData)
1781{
1782 d->putStep(stepData);
1783}
1784
1785void SASL::setUsername(const QString &user)
1786{
1787 d->set_username = true;
1788 d->username = user;
1789 d->c->setClientParams(user: &user, authzid: nullptr, pass: nullptr, realm: nullptr);
1790}
1791
1792void SASL::setAuthzid(const QString &authzid)
1793{
1794 d->set_authzid = true;
1795 d->authzid = authzid;
1796 d->c->setClientParams(user: nullptr, authzid: &authzid, pass: nullptr, realm: nullptr);
1797}
1798
1799void SASL::setPassword(const SecureArray &pass)
1800{
1801 d->set_password = true;
1802 d->password = pass;
1803 d->c->setClientParams(user: nullptr, authzid: nullptr, pass: &pass, realm: nullptr);
1804}
1805
1806void SASL::setRealm(const QString &realm)
1807{
1808 d->set_realm = true;
1809 d->realm = realm;
1810 d->c->setClientParams(user: nullptr, authzid: nullptr, pass: nullptr, realm: &realm);
1811}
1812
1813void SASL::continueAfterParams()
1814{
1815 d->tryAgain();
1816}
1817
1818void SASL::continueAfterAuthCheck()
1819{
1820 d->tryAgain();
1821}
1822
1823QString SASL::mechanism() const
1824{
1825 return d->mech;
1826}
1827
1828QStringList SASL::mechanismList() const
1829{
1830 return d->c->mechlist();
1831}
1832
1833QStringList SASL::realmList() const
1834{
1835 return d->c->realmlist();
1836}
1837
1838int SASL::ssf() const
1839{
1840 return d->c->ssf();
1841}
1842
1843int SASL::bytesAvailable() const
1844{
1845 return d->in.size();
1846}
1847
1848int SASL::bytesOutgoingAvailable() const
1849{
1850 return d->to_net.size();
1851}
1852
1853void SASL::write(const QByteArray &a)
1854{
1855 d->out.append(a);
1856 d->layer.addPlain(plain: a.size());
1857 d->update();
1858}
1859
1860QByteArray SASL::read()
1861{
1862 const QByteArray a = d->in;
1863 d->in.clear();
1864 return a;
1865}
1866
1867void SASL::writeIncoming(const QByteArray &a)
1868{
1869 d->from_net.append(a);
1870 d->update();
1871}
1872
1873QByteArray 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(encoded: a.size(), plain: d->to_net_encoded);
1880 d->to_net_encoded = 0;
1881 return a;
1882}
1883
1884int SASL::convertBytesWritten(qint64 bytes)
1885{
1886 return d->layer.finished(encoded: bytes);
1887}
1888
1889}
1890
1891#include "qca_securelayer.moc"
1892

source code of qca/src/qca_securelayer.cpp