source: qca/trunk/src/qca.cpp@ 150

Last change on this file since 150 was 71, checked in by dmik, 19 years ago

QCA: Applied somebody's patch (from psi-im.org's Wiki) to fix MSVC 7 build.

  • Property svn:keywords set to Id
File size: 27.8 KB
Line 
1/*
2 * qca.cpp - Qt Cryptographic Architecture
3 * Copyright (C) 2003 Justin Karneges
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include"qca.h"
22
23#include<qptrlist.h>
24#include<qdir.h>
25#include<qfileinfo.h>
26#include<qstringlist.h>
27#include<qlibrary.h>
28#include<qtimer.h>
29#include<qhostaddress.h>
30#include<qapplication.h>
31#include<qguardedptr.h>
32#include<stdlib.h>
33#include"qcaprovider.h"
34
35#if defined(Q_OS_WIN32) || defined(Q_OS_OS2)
36#define PLUGIN_EXT "dll"
37#elif defined(Q_OS_MAC)
38#define PLUGIN_EXT "dylib"
39#else
40#define PLUGIN_EXT "so"
41#endif
42
43using namespace QCA;
44
45class ProviderItem
46{
47public:
48 QCAProvider *p;
49 QString fname;
50
51 static ProviderItem *load(const QString &fname)
52 {
53 QLibrary *lib = new QLibrary(fname);
54 if(!lib->load()) {
55 delete lib;
56 return 0;
57 }
58 void *s = lib->resolve("createProvider");
59 if(!s) {
60 delete lib;
61 return 0;
62 }
63 QCAProvider *(*createProvider)() = (QCAProvider *(*)())s;
64 QCAProvider *p = createProvider();
65 if(!p) {
66 delete lib;
67 return 0;
68 }
69 ProviderItem *i = new ProviderItem(lib, p);
70 i->fname = fname;
71 return i;
72 }
73
74 static ProviderItem *fromClass(QCAProvider *p)
75 {
76 ProviderItem *i = new ProviderItem(0, p);
77 return i;
78 }
79
80 ~ProviderItem()
81 {
82 delete p;
83 delete lib;
84 }
85
86 void ensureInit()
87 {
88 if(init_done)
89 return;
90 init_done = true;
91 p->init();
92 }
93
94private:
95 QLibrary *lib;
96 bool init_done;
97
98 ProviderItem(QLibrary *_lib, QCAProvider *_p)
99 {
100 lib = _lib;
101 p = _p;
102 init_done = false;
103 }
104};
105
106static QPtrList<ProviderItem> providerList;
107static bool qca_init = false;
108
109static bool plugin_have(const QString &fname)
110{
111 QPtrListIterator<ProviderItem> it(providerList);
112 for(ProviderItem *i; (i = it.current()); ++it) {
113 if(i->fname == fname)
114 return true;
115 }
116 return false;
117}
118
119static void plugin_scan()
120{
121 QStringList dirs = QApplication::libraryPaths();
122 for(QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
123 QDir libpath(*it);
124 QDir dir(libpath.filePath("crypto"));
125 if(!dir.exists())
126 continue;
127
128 QStringList list = dir.entryList();
129 for(QStringList::ConstIterator it = list.begin(); it != list.end(); ++it) {
130 QFileInfo fi(dir.filePath(*it));
131 if(fi.isDir())
132 continue;
133 if(fi.extension() != PLUGIN_EXT)
134 continue;
135 QString fname = fi.filePath();
136
137 // don't load the same plugin again!
138 if(plugin_have(fname))
139 continue;
140 //printf("f=[%s]\n", fname.latin1());
141
142 ProviderItem *i = ProviderItem::load(fname);
143 if(!i)
144 continue;
145 if(i->p->qcaVersion() != QCA_PLUGIN_VERSION) {
146 delete i;
147 continue;
148 }
149
150 providerList.append(i);
151 }
152 }
153}
154
155static void plugin_addClass(QCAProvider *p)
156{
157 ProviderItem *i = ProviderItem::fromClass(p);
158 providerList.prepend(i);
159}
160
161static void plugin_unloadall()
162{
163 providerList.clear();
164}
165
166static int plugin_caps()
167{
168 int caps = 0;
169 QPtrListIterator<ProviderItem> it(providerList);
170 for(ProviderItem *i; (i = it.current()); ++it)
171 caps |= i->p->capabilities();
172 return caps;
173}
174
175QString QCA::arrayToHex(const QByteArray &a)
176{
177 QString out;
178 for(int n = 0; n < (int)a.size(); ++n) {
179 QString str;
180 str.sprintf("%02x", (uchar)a[n]);
181 out.append(str);
182 }
183 return out;
184}
185
186QByteArray QCA::hexToArray(const QString &str)
187{
188 QByteArray out(str.length() / 2);
189 int at = 0;
190 for(int n = 0; n + 1 < (int)str.length(); n += 2) {
191 uchar a = str[n];
192 uchar b = str[n+1];
193 uchar c = ((a & 0x0f) << 4) + (b & 0x0f);
194 out[at++] = c;
195 }
196 return out;
197}
198
199void QCA::init()
200{
201 if(qca_init)
202 return;
203 qca_init = true;
204 providerList.setAutoDelete(true);
205}
206
207bool QCA::isSupported(int capabilities)
208{
209 init();
210
211 int caps = plugin_caps();
212 if(caps & capabilities)
213 return true;
214
215 // ok, try scanning for new stuff
216 plugin_scan();
217 caps = plugin_caps();
218 if(caps & capabilities)
219 return true;
220
221 return false;
222}
223
224void QCA::insertProvider(QCAProvider *p)
225{
226 plugin_addClass(p);
227}
228
229void QCA::unloadAllPlugins()
230{
231 plugin_unloadall();
232}
233
234static void *getContext(int cap)
235{
236 init();
237
238 // this call will also trip a scan for new plugins if needed
239 if(!QCA::isSupported(cap))
240 return 0;
241
242 QPtrListIterator<ProviderItem> it(providerList);
243 for(ProviderItem *i; (i = it.current()); ++it) {
244 if(i->p->capabilities() & cap) {
245 i->ensureInit();
246 return i->p->context(cap);
247 }
248 }
249 return 0;
250}
251
252
253//----------------------------------------------------------------------------
254// Hash
255//----------------------------------------------------------------------------
256class Hash::Private
257{
258public:
259 Private()
260 {
261 c = 0;
262 }
263
264 ~Private()
265 {
266 delete c;
267 }
268
269 void reset()
270 {
271 c->reset();
272 }
273
274 QCA_HashContext *c;
275};
276
277Hash::Hash(QCA_HashContext *c)
278{
279 d = new Private;
280 d->c = c;
281}
282
283Hash::Hash(const Hash &from)
284{
285 d = new Private;
286 *this = from;
287}
288
289Hash & Hash::operator=(const Hash &from)
290{
291 delete d->c;
292 d->c = from.d->c->clone();
293 return *this;
294}
295
296Hash::~Hash()
297{
298 delete d;
299}
300
301void Hash::clear()
302{
303 d->reset();
304}
305
306void Hash::update(const QByteArray &a)
307{
308 d->c->update(a.data(), a.size());
309}
310
311QByteArray Hash::final()
312{
313 QByteArray buf;
314 d->c->final(&buf);
315 return buf;
316}
317
318
319//----------------------------------------------------------------------------
320// Cipher
321//----------------------------------------------------------------------------
322class Cipher::Private
323{
324public:
325 Private()
326 {
327 c = 0;
328 }
329
330 ~Private()
331 {
332 delete c;
333 }
334
335 void reset()
336 {
337 dir = Encrypt;
338 key.resize(0);
339 iv.resize(0);
340 err = false;
341 }
342
343 QCA_CipherContext *c;
344 int dir;
345 int mode;
346 QByteArray key, iv;
347 bool err;
348};
349
350Cipher::Cipher(QCA_CipherContext *c, int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
351{
352 d = new Private;
353 d->c = c;
354 reset(dir, mode, key, iv, pad);
355}
356
357Cipher::Cipher(const Cipher &from)
358{
359 d = new Private;
360 *this = from;
361}
362
363Cipher & Cipher::operator=(const Cipher &from)
364{
365 delete d->c;
366 d->c = from.d->c->clone();
367 d->dir = from.d->dir;
368 d->mode = from.d->mode;
369 d->key = from.d->key.copy();
370 d->iv = from.d->iv.copy();
371 d->err = from.d->err;
372 return *this;
373}
374
375Cipher::~Cipher()
376{
377 delete d;
378}
379
380QByteArray Cipher::dyn_generateKey(int size) const
381{
382 QByteArray buf;
383 if(size != -1)
384 buf.resize(size);
385 else
386 buf.resize(d->c->keySize());
387 if(!d->c->generateKey(buf.data(), size))
388 return QByteArray();
389 return buf;
390}
391
392QByteArray Cipher::dyn_generateIV() const
393{
394 QByteArray buf(d->c->blockSize());
395 if(!d->c->generateIV(buf.data()))
396 return QByteArray();
397 return buf;
398}
399
400void Cipher::reset(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
401{
402 d->reset();
403
404 d->dir = dir;
405 d->mode = mode;
406 d->key = key.copy();
407 d->iv = iv.copy();
408 if(!d->c->setup(d->dir, d->mode, d->key.isEmpty() ? 0: d->key.data(), d->key.size(), d->iv.isEmpty() ? 0 : d->iv.data(), pad)) {
409 d->err = true;
410 return;
411 }
412}
413
414bool Cipher::update(const QByteArray &a)
415{
416 if(d->err)
417 return false;
418
419 if(!a.isEmpty()) {
420 if(!d->c->update(a.data(), a.size())) {
421 d->err = true;
422 return false;
423 }
424 }
425 return true;
426}
427
428QByteArray Cipher::final(bool *ok)
429{
430 if(ok)
431 *ok = false;
432 if(d->err)
433 return QByteArray();
434
435 QByteArray out;
436 if(!d->c->final(&out)) {
437 d->err = true;
438 return QByteArray();
439 }
440 if(ok)
441 *ok = true;
442 return out;
443}
444
445
446//----------------------------------------------------------------------------
447// SHA1
448//----------------------------------------------------------------------------
449SHA1::SHA1()
450:Hash((QCA_HashContext *)getContext(CAP_SHA1))
451{
452}
453
454
455//----------------------------------------------------------------------------
456// SHA256
457//----------------------------------------------------------------------------
458#if !defined(MSC_NET_HOTFIX)
459SHA256::SHA256()
460:Hash((QCA_HashContext *)getContext(CAP_SHA256))
461{
462}
463#endif
464
465
466//----------------------------------------------------------------------------
467// MD5
468//----------------------------------------------------------------------------
469MD5::MD5()
470:Hash((QCA_HashContext *)getContext(CAP_MD5))
471{
472}
473
474
475//----------------------------------------------------------------------------
476// BlowFish
477//----------------------------------------------------------------------------
478BlowFish::BlowFish(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
479:Cipher((QCA_CipherContext *)getContext(CAP_BlowFish), dir, mode, key, iv, pad)
480{
481}
482
483
484//----------------------------------------------------------------------------
485// TripleDES
486//----------------------------------------------------------------------------
487TripleDES::TripleDES(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
488:Cipher((QCA_CipherContext *)getContext(CAP_TripleDES), dir, mode, key, iv, pad)
489{
490}
491
492
493//----------------------------------------------------------------------------
494// AES128
495//----------------------------------------------------------------------------
496AES128::AES128(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
497:Cipher((QCA_CipherContext *)getContext(CAP_AES128), dir, mode, key, iv, pad)
498{
499}
500
501
502//----------------------------------------------------------------------------
503// AES256
504//----------------------------------------------------------------------------
505AES256::AES256(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
506:Cipher((QCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad)
507{
508}
509
510
511//----------------------------------------------------------------------------
512// RSAKey
513//----------------------------------------------------------------------------
514class RSAKey::Private
515{
516public:
517 Private()
518 {
519 c = 0;
520 }
521
522 ~Private()
523 {
524 delete c;
525 }
526
527 QCA_RSAKeyContext *c;
528};
529
530RSAKey::RSAKey()
531{
532 d = new Private;
533 d->c = (QCA_RSAKeyContext *)getContext(CAP_RSA);
534}
535
536RSAKey::RSAKey(const RSAKey &from)
537{
538 d = new Private;
539 *this = from;
540}
541
542RSAKey & RSAKey::operator=(const RSAKey &from)
543{
544 delete d->c;
545 d->c = from.d->c->clone();
546 return *this;
547}
548
549RSAKey::~RSAKey()
550{
551 delete d;
552}
553
554bool RSAKey::isNull() const
555{
556 return d->c->isNull();
557}
558
559bool RSAKey::havePublic() const
560{
561 return d->c->havePublic();
562}
563
564bool RSAKey::havePrivate() const
565{
566 return d->c->havePrivate();
567}
568
569QByteArray RSAKey::toDER(bool publicOnly) const
570{
571 QByteArray out;
572 if(!d->c->toDER(&out, publicOnly))
573 return QByteArray();
574 return out;
575}
576
577bool RSAKey::fromDER(const QByteArray &a)
578{
579 return d->c->createFromDER(a.data(), a.size());
580}
581
582QString RSAKey::toPEM(bool publicOnly) const
583{
584 QByteArray out;
585 if(!d->c->toPEM(&out, publicOnly))
586 return QByteArray();
587
588 QCString cs;
589 cs.resize(out.size()+1);
590 memcpy(cs.data(), out.data(), out.size());
591 return QString::fromLatin1(cs);
592}
593
594bool RSAKey::fromPEM(const QString &str)
595{
596 QCString cs = str.latin1();
597 QByteArray a(cs.length());
598 memcpy(a.data(), cs.data(), a.size());
599 return d->c->createFromPEM(a.data(), a.size());
600}
601
602bool RSAKey::fromNative(void *p)
603{
604 return d->c->createFromNative(p);
605}
606
607bool RSAKey::encrypt(const QByteArray &a, QByteArray *b, bool oaep) const
608{
609 QByteArray out;
610 if(!d->c->encrypt(a, &out, oaep))
611 return false;
612 *b = out;
613 return true;
614}
615
616bool RSAKey::decrypt(const QByteArray &a, QByteArray *b, bool oaep) const
617{
618 QByteArray out;
619 if(!d->c->decrypt(a, &out, oaep))
620 return false;
621 *b = out;
622 return true;
623}
624
625bool RSAKey::generate(unsigned int bits)
626{
627 return d->c->generate(bits);
628}
629
630
631//----------------------------------------------------------------------------
632// RSA
633//----------------------------------------------------------------------------
634RSA::RSA()
635{
636}
637
638RSA::~RSA()
639{
640}
641
642RSAKey RSA::key() const
643{
644 return v_key;
645}
646
647void RSA::setKey(const RSAKey &k)
648{
649 v_key = k;
650}
651
652bool RSA::encrypt(const QByteArray &a, QByteArray *b, bool oaep) const
653{
654 if(v_key.isNull())
655 return false;
656 return v_key.encrypt(a, b, oaep);
657}
658
659bool RSA::decrypt(const QByteArray &a, QByteArray *b, bool oaep) const
660{
661 if(v_key.isNull())
662 return false;
663 return v_key.decrypt(a, b, oaep);
664}
665
666RSAKey RSA::generateKey(unsigned int bits)
667{
668 RSAKey k;
669 k.generate(bits);
670 return k;
671}
672
673
674//----------------------------------------------------------------------------
675// Cert
676//----------------------------------------------------------------------------
677class Cert::Private
678{
679public:
680 Private()
681 {
682 c = 0;
683 }
684
685 ~Private()
686 {
687 delete c;
688 }
689
690 QCA_CertContext *c;
691};
692
693Cert::Cert()
694{
695 d = new Private;
696 d->c = (QCA_CertContext *)getContext(CAP_X509);
697}
698
699Cert::Cert(const Cert &from)
700{
701 d = new Private;
702 *this = from;
703}
704
705Cert & Cert::operator=(const Cert &from)
706{
707 delete d->c;
708 d->c = from.d->c->clone();
709 return *this;
710}
711
712Cert::~Cert()
713{
714 delete d;
715}
716
717void Cert::fromContext(QCA_CertContext *ctx)
718{
719 delete d->c;
720 d->c = ctx;
721}
722
723bool Cert::isNull() const
724{
725 return d->c->isNull();
726}
727
728QString Cert::commonName() const
729{
730 CertProperties props = subject();
731 return props["CN"];
732}
733
734QString Cert::serialNumber() const
735{
736 return d->c->serialNumber();
737}
738
739QString Cert::subjectString() const
740{
741 return d->c->subjectString();
742}
743
744QString Cert::issuerString() const
745{
746 return d->c->issuerString();
747}
748
749CertProperties Cert::subject() const
750{
751 QValueList<QCA_CertProperty> list = d->c->subject();
752 CertProperties props;
753 for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
754 props[(*it).var] = (*it).val;
755 return props;
756}
757
758CertProperties Cert::issuer() const
759{
760 QValueList<QCA_CertProperty> list = d->c->issuer();
761 CertProperties props;
762 for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
763 props[(*it).var] = (*it).val;
764 return props;
765}
766
767QDateTime Cert::notBefore() const
768{
769 return d->c->notBefore();
770}
771
772QDateTime Cert::notAfter() const
773{
774 return d->c->notAfter();
775}
776
777QByteArray Cert::toDER() const
778{
779 QByteArray out;
780 if(!d->c->toDER(&out))
781 return QByteArray();
782 return out;
783}
784
785bool Cert::fromDER(const QByteArray &a)
786{
787 return d->c->createFromDER(a.data(), a.size());
788}
789
790QString Cert::toPEM() const
791{
792 QByteArray out;
793 if(!d->c->toPEM(&out))
794 return QByteArray();
795
796 QCString cs;
797 cs.resize(out.size()+1);
798 memcpy(cs.data(), out.data(), out.size());
799 return QString::fromLatin1(cs);
800}
801
802bool Cert::fromPEM(const QString &str)
803{
804 QCString cs = str.latin1();
805 QByteArray a(cs.length());
806 memcpy(a.data(), cs.data(), a.size());
807 return d->c->createFromPEM(a.data(), a.size());
808}
809
810
811//----------------------------------------------------------------------------
812// TLS
813//----------------------------------------------------------------------------
814class TLS::Private
815{
816public:
817 Private()
818 {
819 c = (QCA_TLSContext *)getContext(CAP_TLS);
820 }
821
822 ~Private()
823 {
824 delete c;
825 }
826
827 void reset()
828 {
829 handshaken = false;
830 closing = false;
831 in.resize(0);
832 out.resize(0);
833 from_net.resize(0);
834 to_net.resize(0);
835 host = "";
836 hostMismatch = false;
837 cert = Cert();
838 bytesEncoded = 0;
839 tryMore = false;
840 }
841
842 void appendArray(QByteArray *a, const QByteArray &b)
843 {
844 int oldsize = a->size();
845 a->resize(oldsize + b.size());
846 memcpy(a->data() + oldsize, b.data(), b.size());
847 }
848
849 Cert cert;
850 QCA_TLSContext *c;
851 QByteArray in, out, to_net, from_net;
852 int bytesEncoded;
853 bool tryMore;
854 bool handshaken;
855 QString host;
856 bool hostMismatch;
857 bool closing;
858
859 Cert ourCert;
860 RSAKey ourKey;
861 QPtrList<QCA_CertContext> store;
862};
863
864TLS::TLS(QObject *parent)
865:QObject(parent)
866{
867 d = new Private;
868}
869
870TLS::~TLS()
871{
872 delete d;
873}
874
875void TLS::setCertificate(const Cert &cert, const RSAKey &key)
876{
877 d->ourCert = cert;
878 d->ourKey = key;
879}
880
881void TLS::setCertificateStore(const QPtrList<Cert> &store)
882{
883 // convert the cert list into a context list
884 d->store.clear();
885 QPtrListIterator<Cert> it(store);
886 for(Cert *cert; (cert = it.current()); ++it)
887 d->store.append(cert->d->c);
888}
889
890void TLS::reset()
891{
892 d->reset();
893}
894
895bool TLS::startClient(const QString &host)
896{
897 d->reset();
898 d->host = host;
899
900 if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
901 return false;
902 QTimer::singleShot(0, this, SLOT(update()));
903 return true;
904}
905
906bool TLS::startServer()
907{
908 d->reset();
909
910 if(!d->c->startServer(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
911 return false;
912 QTimer::singleShot(0, this, SLOT(update()));
913 return true;
914}
915
916void TLS::close()
917{
918 if(!d->handshaken || d->closing)
919 return;
920
921 d->closing = true;
922 QTimer::singleShot(0, this, SLOT(update()));
923}
924
925bool TLS::isHandshaken() const
926{
927 return d->handshaken;
928}
929
930void TLS::write(const QByteArray &a)
931{
932 d->appendArray(&d->out, a);
933 update();
934}
935
936QByteArray TLS::read()
937{
938 QByteArray a = d->in.copy();
939 d->in.resize(0);
940 return a;
941}
942
943void TLS::writeIncoming(const QByteArray &a)
944{
945 d->appendArray(&d->from_net, a);
946 update();
947}
948
949QByteArray TLS::readOutgoing()
950{
951 QByteArray a = d->to_net.copy();
952 d->to_net.resize(0);
953 return a;
954}
955
956QByteArray TLS::readUnprocessed()
957{
958 QByteArray a = d->from_net.copy();
959 d->from_net.resize(0);
960 return a;
961}
962
963const Cert & TLS::peerCertificate() const
964{
965 return d->cert;
966}
967
968int TLS::certificateValidityResult() const
969{
970 if(d->hostMismatch)
971 return QCA::TLS::HostMismatch;
972 else
973 return d->c->validityResult();
974}
975
976void TLS::update()
977{
978 bool force_read = false;
979 bool eof = false;
980 bool done = false;
981 QGuardedPtr<TLS> self = this;
982
983 if(d->closing) {
984 QByteArray a;
985 int r = d->c->shutdown(d->from_net, &a);
986 d->from_net.resize(0);
987 if(r == QCA_TLSContext::Error) {
988 reset();
989 error(ErrHandshake);
990 return;
991 }
992 if(r == QCA_TLSContext::Success) {
993 d->from_net = d->c->unprocessed().copy();
994 done = true;
995 }
996 d->appendArray(&d->to_net, a);
997 }
998 else {
999 if(!d->handshaken) {
1000 QByteArray a;
1001 int r = d->c->handshake(d->from_net, &a);
1002 d->from_net.resize(0);
1003 if(r == QCA_TLSContext::Error) {
1004 reset();
1005 error(ErrHandshake);
1006 return;
1007 }
1008 d->appendArray(&d->to_net, a);
1009 if(r == QCA_TLSContext::Success) {
1010 QCA_CertContext *cc = d->c->peerCertificate();
1011 if(cc && !d->host.isEmpty() && d->c->validityResult() == QCA::TLS::Valid) {
1012 if(!cc->matchesAddress(d->host))
1013 d->hostMismatch = true;
1014 }
1015 d->cert.fromContext(cc);
1016 d->handshaken = true;
1017 handshaken();
1018 if(!self)
1019 return;
1020
1021 // there is a teeny tiny possibility that incoming data awaits. let us get it.
1022 force_read = true;
1023 }
1024 }
1025
1026 if(d->handshaken) {
1027 if(!d->out.isEmpty() || d->tryMore) {
1028 d->tryMore = false;
1029 QByteArray a;
1030 int enc;
1031 bool more = false;
1032 bool ok = d->c->encode(d->out, &a, &enc);
1033 eof = d->c->eof();
1034 if(ok && enc < (int)d->out.size())
1035 more = true;
1036 d->out.resize(0);
1037 if(!eof) {
1038 if(!ok) {
1039 reset();
1040 error(ErrCrypt);
1041 return;
1042 }
1043 d->bytesEncoded += enc;
1044 if(more)
1045 d->tryMore = true;
1046 d->appendArray(&d->to_net, a);
1047 }
1048 }
1049 if(!d->from_net.isEmpty() || force_read) {
1050 QByteArray a, b;
1051 bool ok = d->c->decode(d->from_net, &a, &b);
1052 eof = d->c->eof();
1053 d->from_net.resize(0);
1054 if(!ok) {
1055 reset();
1056 error(ErrCrypt);
1057 return;
1058 }
1059 d->appendArray(&d->in, a);
1060 d->appendArray(&d->to_net, b);
1061 }
1062
1063 if(!d->in.isEmpty()) {
1064 readyRead();
1065 if(!self)
1066 return;
1067 }
1068 }
1069 }
1070
1071 if(!d->to_net.isEmpty()) {
1072 int bytes = d->bytesEncoded;
1073 d->bytesEncoded = 0;
1074 readyReadOutgoing(bytes);
1075 if(!self)
1076 return;
1077 }
1078
1079 if(eof) {
1080 close();
1081 if(!self)
1082 return;
1083 return;
1084 }
1085
1086 if(d->closing && done) {
1087 reset();
1088 closed();
1089 }
1090}
1091
1092
1093//----------------------------------------------------------------------------
1094// SASL
1095//----------------------------------------------------------------------------
1096QString saslappname = "qca";
1097class SASL::Private
1098{
1099public:
1100 Private()
1101 {
1102 c = (QCA_SASLContext *)getContext(CAP_SASL);
1103 }
1104
1105 ~Private()
1106 {
1107 delete c;
1108 }
1109
1110 void setSecurityProps()
1111 {
1112 c->setSecurityProps(noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual, ssfmin, ssfmax, ext_authid, ext_ssf);
1113 }
1114
1115 // security opts
1116 bool noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual;
1117 int ssfmin, ssfmax;
1118 QString ext_authid;
1119 int ext_ssf;
1120
1121 bool tried;
1122 QCA_SASLContext *c;
1123 QHostAddress localAddr, remoteAddr;
1124 int localPort, remotePort;
1125 QByteArray stepData;
1126 bool allowCSF;
1127 bool first, server;
1128
1129 QByteArray inbuf, outbuf;
1130};
1131
1132SASL::SASL(QObject *parent)
1133:QObject(parent)
1134{
1135 d = new Private;
1136 reset();
1137}
1138
1139SASL::~SASL()
1140{
1141 delete d;
1142}
1143
1144void SASL::setAppName(const QString &name)
1145{
1146 saslappname = name;
1147}
1148
1149void SASL::reset()
1150{
1151 d->localPort = -1;
1152 d->remotePort = -1;
1153
1154 d->noPlain = false;
1155 d->noActive = false;
1156 d->noDict = false;
1157 d->noAnon = false;
1158 d->reqForward = false;
1159 d->reqCreds = false;
1160 d->reqMutual = false;
1161 d->ssfmin = 0;
1162 d->ssfmax = 0;
1163 d->ext_authid = "";
1164 d->ext_ssf = 0;
1165
1166 d->inbuf.resize(0);
1167 d->outbuf.resize(0);
1168
1169 d->c->reset();
1170}
1171
1172int SASL::errorCondition() const
1173{
1174 return d->c->errorCond();
1175}
1176
1177void SASL::setAllowPlain(bool b)
1178{
1179 d->noPlain = !b;
1180}
1181
1182void SASL::setAllowAnonymous(bool b)
1183{
1184 d->noAnon = !b;
1185}
1186
1187void SASL::setAllowActiveVulnerable(bool b)
1188{
1189 d->noActive = !b;
1190}
1191
1192void SASL::setAllowDictionaryVulnerable(bool b)
1193{
1194 d->noDict = !b;
1195}
1196
1197void SASL::setRequireForwardSecrecy(bool b)
1198{
1199 d->reqForward = b;
1200}
1201
1202void SASL::setRequirePassCredentials(bool b)
1203{
1204 d->reqCreds = b;
1205}
1206
1207void SASL::setRequireMutualAuth(bool b)
1208{
1209 d->reqMutual = b;
1210}
1211
1212void SASL::setMinimumSSF(int x)
1213{
1214 d->ssfmin = x;
1215}
1216
1217void SASL::setMaximumSSF(int x)
1218{
1219 d->ssfmax = x;
1220}
1221
1222void SASL::setExternalAuthID(const QString &authid)
1223{
1224 d->ext_authid = authid;
1225}
1226
1227void SASL::setExternalSSF(int x)
1228{
1229 d->ext_ssf = x;
1230}
1231
1232void SASL::setLocalAddr(const QHostAddress &addr, Q_UINT16 port)
1233{
1234 d->localAddr = addr;
1235 d->localPort = port;
1236}
1237
1238void SASL::setRemoteAddr(const QHostAddress &addr, Q_UINT16 port)
1239{
1240 d->remoteAddr = addr;
1241 d->remotePort = port;
1242}
1243
1244bool SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, bool allowClientSendFirst)
1245{
1246 QCA_SASLHostPort la, ra;
1247 if(d->localPort != -1) {
1248 la.addr = d->localAddr;
1249 la.port = d->localPort;
1250 }
1251 if(d->remotePort != -1) {
1252 ra.addr = d->remoteAddr;
1253 ra.port = d->remotePort;
1254 }
1255
1256 d->allowCSF = allowClientSendFirst;
1257 d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
1258 d->setSecurityProps();
1259
1260 if(!d->c->clientStart(mechlist))
1261 return false;
1262 d->first = true;
1263 d->server = false;
1264 d->tried = false;
1265 QTimer::singleShot(0, this, SLOT(tryAgain()));
1266 return true;
1267}
1268
1269bool SASL::startServer(const QString &service, const QString &host, const QString &realm, QStringList *mechlist)
1270{
1271 QCA_SASLHostPort la, ra;
1272 if(d->localPort != -1) {
1273 la.addr = d->localAddr;
1274 la.port = d->localPort;
1275 }
1276 if(d->remotePort != -1) {
1277 ra.addr = d->remoteAddr;
1278 ra.port = d->remotePort;
1279 }
1280
1281 d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
1282 d->setSecurityProps();
1283
1284 if(!d->c->serverStart(realm, mechlist, saslappname))
1285 return false;
1286 d->first = true;
1287 d->server = true;
1288 d->tried = false;
1289 return true;
1290}
1291
1292void SASL::putServerFirstStep(const QString &mech)
1293{
1294 int r = d->c->serverFirstStep(mech, 0);
1295 handleServerFirstStep(r);
1296}
1297
1298void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
1299{
1300 int r = d->c->serverFirstStep(mech, &clientInit);
1301 handleServerFirstStep(r);
1302}
1303
1304void SASL::handleServerFirstStep(int r)
1305{
1306 if(r == QCA_SASLContext::Success)
1307 authenticated();
1308 else if(r == QCA_SASLContext::Continue)
1309 nextStep(d->c->result());
1310 else if(r == QCA_SASLContext::AuthCheck)
1311 tryAgain();
1312 else
1313 error(ErrAuth);
1314}
1315
1316void SASL::putStep(const QByteArray &stepData)
1317{
1318 d->stepData = stepData.copy();
1319 tryAgain();
1320}
1321
1322void SASL::setUsername(const QString &user)
1323{
1324 d->c->setClientParams(&user, 0, 0, 0);
1325}
1326
1327void SASL::setAuthzid(const QString &authzid)
1328{
1329 d->c->setClientParams(0, &authzid, 0, 0);
1330}
1331
1332void SASL::setPassword(const QString &pass)
1333{
1334 d->c->setClientParams(0, 0, &pass, 0);
1335}
1336
1337void SASL::setRealm(const QString &realm)
1338{
1339 d->c->setClientParams(0, 0, 0, &realm);
1340}
1341
1342void SASL::continueAfterParams()
1343{
1344 tryAgain();
1345}
1346
1347void SASL::continueAfterAuthCheck()
1348{
1349 tryAgain();
1350}
1351
1352void SASL::tryAgain()
1353{
1354 int r;
1355
1356 if(d->server) {
1357 if(!d->tried) {
1358 r = d->c->nextStep(d->stepData);
1359 d->tried = true;
1360 }
1361 else {
1362 r = d->c->tryAgain();
1363 }
1364
1365 if(r == QCA_SASLContext::Error) {
1366 error(ErrAuth);
1367 return;
1368 }
1369 else if(r == QCA_SASLContext::Continue) {
1370 d->tried = false;
1371 nextStep(d->c->result());
1372 return;
1373 }
1374 else if(r == QCA_SASLContext::AuthCheck) {
1375 authCheck(d->c->username(), d->c->authzid());
1376 return;
1377 }
1378 }
1379 else {
1380 if(d->first) {
1381 if(!d->tried) {
1382 r = d->c->clientFirstStep(d->allowCSF);
1383 d->tried = true;
1384 }
1385 else
1386 r = d->c->tryAgain();
1387
1388 if(r == QCA_SASLContext::Error) {
1389 error(ErrAuth);
1390 return;
1391 }
1392 else if(r == QCA_SASLContext::NeedParams) {
1393 //d->tried = false;
1394 QCA_SASLNeedParams np = d->c->clientParamsNeeded();
1395 needParams(np.user, np.authzid, np.pass, np.realm);
1396 return;
1397 }
1398
1399 QString mech = d->c->mech();
1400 const QByteArray *clientInit = d->c->clientInit();
1401
1402 d->first = false;
1403 d->tried = false;
1404 clientFirstStep(mech, clientInit);
1405 }
1406 else {
1407 if(!d->tried) {
1408 r = d->c->nextStep(d->stepData);
1409 d->tried = true;
1410 }
1411 else
1412 r = d->c->tryAgain();
1413
1414 if(r == QCA_SASLContext::Error) {
1415 error(ErrAuth);
1416 return;
1417 }
1418 else if(r == QCA_SASLContext::NeedParams) {
1419 //d->tried = false;
1420 QCA_SASLNeedParams np = d->c->clientParamsNeeded();
1421 needParams(np.user, np.authzid, np.pass, np.realm);
1422 return;
1423 }
1424 d->tried = false;
1425 //else if(r == QCA_SASLContext::Continue) {
1426 nextStep(d->c->result());
1427 // return;
1428 //}
1429 }
1430 }
1431
1432 if(r == QCA_SASLContext::Success)
1433 authenticated();
1434 else if(r == QCA_SASLContext::Error)
1435 error(ErrAuth);
1436}
1437
1438int SASL::ssf() const
1439{
1440 return d->c->security();
1441}
1442
1443void SASL::write(const QByteArray &a)
1444{
1445 QByteArray b;
1446 if(!d->c->encode(a, &b)) {
1447 error(ErrCrypt);
1448 return;
1449 }
1450 int oldsize = d->outbuf.size();
1451 d->outbuf.resize(oldsize + b.size());
1452 memcpy(d->outbuf.data() + oldsize, b.data(), b.size());
1453 readyReadOutgoing(a.size());
1454}
1455
1456QByteArray SASL::read()
1457{
1458 QByteArray a = d->inbuf.copy();
1459 d->inbuf.resize(0);
1460 return a;
1461}
1462
1463void SASL::writeIncoming(const QByteArray &a)
1464{
1465 QByteArray b;
1466 if(!d->c->decode(a, &b)) {
1467 error(ErrCrypt);
1468 return;
1469 }
1470 int oldsize = d->inbuf.size();
1471 d->inbuf.resize(oldsize + b.size());
1472 memcpy(d->inbuf.data() + oldsize, b.data(), b.size());
1473 readyRead();
1474}
1475
1476QByteArray SASL::readOutgoing()
1477{
1478 QByteArray a = d->outbuf.copy();
1479 d->outbuf.resize(0);
1480 return a;
1481}
Note: See TracBrowser for help on using the repository browser.