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

Last change on this file since 63 was 27, checked in by dmik, 19 years ago

QCA: General: Added OS/2-related defines to make it compile.

  • Property svn:keywords set to Id
File size: 26.3 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//----------------------------------------------------------------------------
458SHA256::SHA256()
459:Hash((QCA_HashContext *)getContext(CAP_SHA256))
460{
461}
462
463
464//----------------------------------------------------------------------------
465// MD5
466//----------------------------------------------------------------------------
467MD5::MD5()
468:Hash((QCA_HashContext *)getContext(CAP_MD5))
469{
470}
471
472
473//----------------------------------------------------------------------------
474// BlowFish
475//----------------------------------------------------------------------------
476BlowFish::BlowFish(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
477:Cipher((QCA_CipherContext *)getContext(CAP_BlowFish), dir, mode, key, iv, pad)
478{
479}
480
481
482//----------------------------------------------------------------------------
483// TripleDES
484//----------------------------------------------------------------------------
485TripleDES::TripleDES(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
486:Cipher((QCA_CipherContext *)getContext(CAP_TripleDES), dir, mode, key, iv, pad)
487{
488}
489
490
491//----------------------------------------------------------------------------
492// AES128
493//----------------------------------------------------------------------------
494AES128::AES128(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
495:Cipher((QCA_CipherContext *)getContext(CAP_AES128), dir, mode, key, iv, pad)
496{
497}
498
499
500//----------------------------------------------------------------------------
501// AES256
502//----------------------------------------------------------------------------
503AES256::AES256(int dir, int mode, const QByteArray &key, const QByteArray &iv, bool pad)
504:Cipher((QCA_CipherContext *)getContext(CAP_AES256), dir, mode, key, iv, pad)
505{
506}
507
508
509//----------------------------------------------------------------------------
510// RSAKey
511//----------------------------------------------------------------------------
512class RSAKey::Private
513{
514public:
515 Private()
516 {
517 c = 0;
518 }
519
520 ~Private()
521 {
522 delete c;
523 }
524
525 QCA_RSAKeyContext *c;
526};
527
528RSAKey::RSAKey()
529{
530 d = new Private;
531 d->c = (QCA_RSAKeyContext *)getContext(CAP_RSA);
532}
533
534RSAKey::RSAKey(const RSAKey &from)
535{
536 d = new Private;
537 *this = from;
538}
539
540RSAKey & RSAKey::operator=(const RSAKey &from)
541{
542 delete d->c;
543 d->c = from.d->c->clone();
544 return *this;
545}
546
547RSAKey::~RSAKey()
548{
549 delete d;
550}
551
552bool RSAKey::isNull() const
553{
554 return d->c->isNull();
555}
556
557bool RSAKey::havePublic() const
558{
559 return d->c->havePublic();
560}
561
562bool RSAKey::havePrivate() const
563{
564 return d->c->havePrivate();
565}
566
567QByteArray RSAKey::toDER(bool publicOnly) const
568{
569 QByteArray out;
570 if(!d->c->toDER(&out, publicOnly))
571 return QByteArray();
572 return out;
573}
574
575bool RSAKey::fromDER(const QByteArray &a)
576{
577 return d->c->createFromDER(a.data(), a.size());
578}
579
580QString RSAKey::toPEM(bool publicOnly) const
581{
582 QByteArray out;
583 if(!d->c->toPEM(&out, publicOnly))
584 return QByteArray();
585
586 QCString cs;
587 cs.resize(out.size()+1);
588 memcpy(cs.data(), out.data(), out.size());
589 return QString::fromLatin1(cs);
590}
591
592bool RSAKey::fromPEM(const QString &str)
593{
594 QCString cs = str.latin1();
595 QByteArray a(cs.length());
596 memcpy(a.data(), cs.data(), a.size());
597 return d->c->createFromPEM(a.data(), a.size());
598}
599
600bool RSAKey::fromNative(void *p)
601{
602 return d->c->createFromNative(p);
603}
604
605bool RSAKey::encrypt(const QByteArray &a, QByteArray *b, bool oaep) const
606{
607 QByteArray out;
608 if(!d->c->encrypt(a, &out, oaep))
609 return false;
610 *b = out;
611 return true;
612}
613
614bool RSAKey::decrypt(const QByteArray &a, QByteArray *b, bool oaep) const
615{
616 QByteArray out;
617 if(!d->c->decrypt(a, &out, oaep))
618 return false;
619 *b = out;
620 return true;
621}
622
623bool RSAKey::generate(unsigned int bits)
624{
625 return d->c->generate(bits);
626}
627
628
629//----------------------------------------------------------------------------
630// RSA
631//----------------------------------------------------------------------------
632RSA::RSA()
633{
634}
635
636RSA::~RSA()
637{
638}
639
640RSAKey RSA::key() const
641{
642 return v_key;
643}
644
645void RSA::setKey(const RSAKey &k)
646{
647 v_key = k;
648}
649
650bool RSA::encrypt(const QByteArray &a, QByteArray *b, bool oaep) const
651{
652 if(v_key.isNull())
653 return false;
654 return v_key.encrypt(a, b, oaep);
655}
656
657bool RSA::decrypt(const QByteArray &a, QByteArray *b, bool oaep) const
658{
659 if(v_key.isNull())
660 return false;
661 return v_key.decrypt(a, b, oaep);
662}
663
664RSAKey RSA::generateKey(unsigned int bits)
665{
666 RSAKey k;
667 k.generate(bits);
668 return k;
669}
670
671
672//----------------------------------------------------------------------------
673// Cert
674//----------------------------------------------------------------------------
675class Cert::Private
676{
677public:
678 Private()
679 {
680 c = 0;
681 }
682
683 ~Private()
684 {
685 delete c;
686 }
687
688 QCA_CertContext *c;
689};
690
691Cert::Cert()
692{
693 d = new Private;
694 d->c = (QCA_CertContext *)getContext(CAP_X509);
695}
696
697Cert::Cert(const Cert &from)
698{
699 d = new Private;
700 *this = from;
701}
702
703Cert & Cert::operator=(const Cert &from)
704{
705 delete d->c;
706 d->c = from.d->c->clone();
707 return *this;
708}
709
710Cert::~Cert()
711{
712 delete d;
713}
714
715void Cert::fromContext(QCA_CertContext *ctx)
716{
717 delete d->c;
718 d->c = ctx;
719}
720
721bool Cert::isNull() const
722{
723 return d->c->isNull();
724}
725
726QString Cert::commonName() const
727{
728 CertProperties props = subject();
729 return props["CN"];
730}
731
732QString Cert::serialNumber() const
733{
734 return d->c->serialNumber();
735}
736
737QString Cert::subjectString() const
738{
739 return d->c->subjectString();
740}
741
742QString Cert::issuerString() const
743{
744 return d->c->issuerString();
745}
746
747CertProperties Cert::subject() const
748{
749 QValueList<QCA_CertProperty> list = d->c->subject();
750 CertProperties props;
751 for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
752 props[(*it).var] = (*it).val;
753 return props;
754}
755
756CertProperties Cert::issuer() const
757{
758 QValueList<QCA_CertProperty> list = d->c->issuer();
759 CertProperties props;
760 for(QValueList<QCA_CertProperty>::ConstIterator it = list.begin(); it != list.end(); ++it)
761 props[(*it).var] = (*it).val;
762 return props;
763}
764
765QDateTime Cert::notBefore() const
766{
767 return d->c->notBefore();
768}
769
770QDateTime Cert::notAfter() const
771{
772 return d->c->notAfter();
773}
774
775QByteArray Cert::toDER() const
776{
777 QByteArray out;
778 if(!d->c->toDER(&out))
779 return QByteArray();
780 return out;
781}
782
783bool Cert::fromDER(const QByteArray &a)
784{
785 return d->c->createFromDER(a.data(), a.size());
786}
787
788QString Cert::toPEM() const
789{
790 QByteArray out;
791 if(!d->c->toPEM(&out))
792 return QByteArray();
793
794 QCString cs;
795 cs.resize(out.size()+1);
796 memcpy(cs.data(), out.data(), out.size());
797 return QString::fromLatin1(cs);
798}
799
800bool Cert::fromPEM(const QString &str)
801{
802 QCString cs = str.latin1();
803 QByteArray a(cs.length());
804 memcpy(a.data(), cs.data(), a.size());
805 return d->c->createFromPEM(a.data(), a.size());
806}
807
808
809//----------------------------------------------------------------------------
810// TLS
811//----------------------------------------------------------------------------
812class TLS::Private
813{
814public:
815 Private()
816 {
817 c = (QCA_TLSContext *)getContext(CAP_TLS);
818 }
819
820 ~Private()
821 {
822 delete c;
823 }
824
825 void reset()
826 {
827 handshaken = false;
828 closing = false;
829 in.resize(0);
830 out.resize(0);
831 from_net.resize(0);
832 to_net.resize(0);
833 host = "";
834 hostMismatch = false;
835 cert = Cert();
836 bytesEncoded = 0;
837 tryMore = false;
838 }
839
840 void appendArray(QByteArray *a, const QByteArray &b)
841 {
842 int oldsize = a->size();
843 a->resize(oldsize + b.size());
844 memcpy(a->data() + oldsize, b.data(), b.size());
845 }
846
847 Cert cert;
848 QCA_TLSContext *c;
849 QByteArray in, out, to_net, from_net;
850 int bytesEncoded;
851 bool tryMore;
852 bool handshaken;
853 QString host;
854 bool hostMismatch;
855 bool closing;
856
857 Cert ourCert;
858 RSAKey ourKey;
859 QPtrList<QCA_CertContext> store;
860};
861
862TLS::TLS(QObject *parent)
863:QObject(parent)
864{
865 d = new Private;
866}
867
868TLS::~TLS()
869{
870 delete d;
871}
872
873void TLS::setCertificate(const Cert &cert, const RSAKey &key)
874{
875 d->ourCert = cert;
876 d->ourKey = key;
877}
878
879void TLS::setCertificateStore(const QPtrList<Cert> &store)
880{
881 // convert the cert list into a context list
882 d->store.clear();
883 QPtrListIterator<Cert> it(store);
884 for(Cert *cert; (cert = it.current()); ++it)
885 d->store.append(cert->d->c);
886}
887
888void TLS::reset()
889{
890 d->reset();
891}
892
893bool TLS::startClient(const QString &host)
894{
895 d->reset();
896 d->host = host;
897
898 if(!d->c->startClient(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
899 return false;
900 QTimer::singleShot(0, this, SLOT(update()));
901 return true;
902}
903
904bool TLS::startServer()
905{
906 d->reset();
907
908 if(!d->c->startServer(d->store, *d->ourCert.d->c, *d->ourKey.d->c))
909 return false;
910 QTimer::singleShot(0, this, SLOT(update()));
911 return true;
912}
913
914void TLS::close()
915{
916 if(!d->handshaken || d->closing)
917 return;
918
919 d->closing = true;
920 QTimer::singleShot(0, this, SLOT(update()));
921}
922
923bool TLS::isHandshaken() const
924{
925 return d->handshaken;
926}
927
928void TLS::write(const QByteArray &a)
929{
930 d->appendArray(&d->out, a);
931 update();
932}
933
934QByteArray TLS::read()
935{
936 QByteArray a = d->in.copy();
937 d->in.resize(0);
938 return a;
939}
940
941void TLS::writeIncoming(const QByteArray &a)
942{
943 d->appendArray(&d->from_net, a);
944 update();
945}
946
947QByteArray TLS::readOutgoing()
948{
949 QByteArray a = d->to_net.copy();
950 d->to_net.resize(0);
951 return a;
952}
953
954QByteArray TLS::readUnprocessed()
955{
956 QByteArray a = d->from_net.copy();
957 d->from_net.resize(0);
958 return a;
959}
960
961const Cert & TLS::peerCertificate() const
962{
963 return d->cert;
964}
965
966int TLS::certificateValidityResult() const
967{
968 if(d->hostMismatch)
969 return QCA::TLS::HostMismatch;
970 else
971 return d->c->validityResult();
972}
973
974void TLS::update()
975{
976 bool force_read = false;
977 bool eof = false;
978 bool done = false;
979 QGuardedPtr<TLS> self = this;
980
981 if(d->closing) {
982 QByteArray a;
983 int r = d->c->shutdown(d->from_net, &a);
984 d->from_net.resize(0);
985 if(r == QCA_TLSContext::Error) {
986 reset();
987 error(ErrHandshake);
988 return;
989 }
990 if(r == QCA_TLSContext::Success) {
991 d->from_net = d->c->unprocessed().copy();
992 done = true;
993 }
994 d->appendArray(&d->to_net, a);
995 }
996 else {
997 if(!d->handshaken) {
998 QByteArray a;
999 int r = d->c->handshake(d->from_net, &a);
1000 d->from_net.resize(0);
1001 if(r == QCA_TLSContext::Error) {
1002 reset();
1003 error(ErrHandshake);
1004 return;
1005 }
1006 d->appendArray(&d->to_net, a);
1007 if(r == QCA_TLSContext::Success) {
1008 QCA_CertContext *cc = d->c->peerCertificate();
1009 if(cc && !d->host.isEmpty() && d->c->validityResult() == QCA::TLS::Valid) {
1010 if(!cc->matchesAddress(d->host))
1011 d->hostMismatch = true;
1012 }
1013 d->cert.fromContext(cc);
1014 d->handshaken = true;
1015 handshaken();
1016 if(!self)
1017 return;
1018
1019 // there is a teeny tiny possibility that incoming data awaits. let us get it.
1020 force_read = true;
1021 }
1022 }
1023
1024 if(d->handshaken) {
1025 if(!d->out.isEmpty() || d->tryMore) {
1026 d->tryMore = false;
1027 QByteArray a;
1028 int enc;
1029 bool more = false;
1030 bool ok = d->c->encode(d->out, &a, &enc);
1031 eof = d->c->eof();
1032 if(ok && enc < (int)d->out.size())
1033 more = true;
1034 d->out.resize(0);
1035 if(!eof) {
1036 if(!ok) {
1037 reset();
1038 error(ErrCrypt);
1039 return;
1040 }
1041 d->bytesEncoded += enc;
1042 if(more)
1043 d->tryMore = true;
1044 d->appendArray(&d->to_net, a);
1045 }
1046 }
1047 if(!d->from_net.isEmpty() || force_read) {
1048 QByteArray a, b;
1049 bool ok = d->c->decode(d->from_net, &a, &b);
1050 eof = d->c->eof();
1051 d->from_net.resize(0);
1052 if(!ok) {
1053 reset();
1054 error(ErrCrypt);
1055 return;
1056 }
1057 d->appendArray(&d->in, a);
1058 d->appendArray(&d->to_net, b);
1059 }
1060
1061 if(!d->in.isEmpty()) {
1062 readyRead();
1063 if(!self)
1064 return;
1065 }
1066 }
1067 }
1068
1069 if(!d->to_net.isEmpty()) {
1070 int bytes = d->bytesEncoded;
1071 d->bytesEncoded = 0;
1072 readyReadOutgoing(bytes);
1073 if(!self)
1074 return;
1075 }
1076
1077 if(eof) {
1078 close();
1079 if(!self)
1080 return;
1081 return;
1082 }
1083
1084 if(d->closing && done) {
1085 reset();
1086 closed();
1087 }
1088}
1089
1090
1091//----------------------------------------------------------------------------
1092// SASL
1093//----------------------------------------------------------------------------
1094QString saslappname = "qca";
1095class SASL::Private
1096{
1097public:
1098 Private()
1099 {
1100 c = (QCA_SASLContext *)getContext(CAP_SASL);
1101 }
1102
1103 ~Private()
1104 {
1105 delete c;
1106 }
1107
1108 void setSecurityProps()
1109 {
1110 c->setSecurityProps(noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual, ssfmin, ssfmax, ext_authid, ext_ssf);
1111 }
1112
1113 // security opts
1114 bool noPlain, noActive, noDict, noAnon, reqForward, reqCreds, reqMutual;
1115 int ssfmin, ssfmax;
1116 QString ext_authid;
1117 int ext_ssf;
1118
1119 bool tried;
1120 QCA_SASLContext *c;
1121 QHostAddress localAddr, remoteAddr;
1122 int localPort, remotePort;
1123 QByteArray stepData;
1124 bool allowCSF;
1125 bool first, server;
1126
1127 QByteArray inbuf, outbuf;
1128};
1129
1130SASL::SASL(QObject *parent)
1131:QObject(parent)
1132{
1133 d = new Private;
1134 reset();
1135}
1136
1137SASL::~SASL()
1138{
1139 delete d;
1140}
1141
1142void SASL::setAppName(const QString &name)
1143{
1144 saslappname = name;
1145}
1146
1147void SASL::reset()
1148{
1149 d->localPort = -1;
1150 d->remotePort = -1;
1151
1152 d->noPlain = false;
1153 d->noActive = false;
1154 d->noDict = false;
1155 d->noAnon = false;
1156 d->reqForward = false;
1157 d->reqCreds = false;
1158 d->reqMutual = false;
1159 d->ssfmin = 0;
1160 d->ssfmax = 0;
1161 d->ext_authid = "";
1162 d->ext_ssf = 0;
1163
1164 d->inbuf.resize(0);
1165 d->outbuf.resize(0);
1166
1167 d->c->reset();
1168}
1169
1170int SASL::errorCondition() const
1171{
1172 return d->c->errorCond();
1173}
1174
1175void SASL::setAllowPlain(bool b)
1176{
1177 d->noPlain = !b;
1178}
1179
1180void SASL::setAllowAnonymous(bool b)
1181{
1182 d->noAnon = !b;
1183}
1184
1185void SASL::setAllowActiveVulnerable(bool b)
1186{
1187 d->noActive = !b;
1188}
1189
1190void SASL::setAllowDictionaryVulnerable(bool b)
1191{
1192 d->noDict = !b;
1193}
1194
1195void SASL::setRequireForwardSecrecy(bool b)
1196{
1197 d->reqForward = b;
1198}
1199
1200void SASL::setRequirePassCredentials(bool b)
1201{
1202 d->reqCreds = b;
1203}
1204
1205void SASL::setRequireMutualAuth(bool b)
1206{
1207 d->reqMutual = b;
1208}
1209
1210void SASL::setMinimumSSF(int x)
1211{
1212 d->ssfmin = x;
1213}
1214
1215void SASL::setMaximumSSF(int x)
1216{
1217 d->ssfmax = x;
1218}
1219
1220void SASL::setExternalAuthID(const QString &authid)
1221{
1222 d->ext_authid = authid;
1223}
1224
1225void SASL::setExternalSSF(int x)
1226{
1227 d->ext_ssf = x;
1228}
1229
1230void SASL::setLocalAddr(const QHostAddress &addr, Q_UINT16 port)
1231{
1232 d->localAddr = addr;
1233 d->localPort = port;
1234}
1235
1236void SASL::setRemoteAddr(const QHostAddress &addr, Q_UINT16 port)
1237{
1238 d->remoteAddr = addr;
1239 d->remotePort = port;
1240}
1241
1242bool SASL::startClient(const QString &service, const QString &host, const QStringList &mechlist, bool allowClientSendFirst)
1243{
1244 QCA_SASLHostPort la, ra;
1245 if(d->localPort != -1) {
1246 la.addr = d->localAddr;
1247 la.port = d->localPort;
1248 }
1249 if(d->remotePort != -1) {
1250 ra.addr = d->remoteAddr;
1251 ra.port = d->remotePort;
1252 }
1253
1254 d->allowCSF = allowClientSendFirst;
1255 d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
1256 d->setSecurityProps();
1257
1258 if(!d->c->clientStart(mechlist))
1259 return false;
1260 d->first = true;
1261 d->server = false;
1262 d->tried = false;
1263 QTimer::singleShot(0, this, SLOT(tryAgain()));
1264 return true;
1265}
1266
1267bool SASL::startServer(const QString &service, const QString &host, const QString &realm, QStringList *mechlist)
1268{
1269 QCA_SASLHostPort la, ra;
1270 if(d->localPort != -1) {
1271 la.addr = d->localAddr;
1272 la.port = d->localPort;
1273 }
1274 if(d->remotePort != -1) {
1275 ra.addr = d->remoteAddr;
1276 ra.port = d->remotePort;
1277 }
1278
1279 d->c->setCoreProps(service, host, d->localPort != -1 ? &la : 0, d->remotePort != -1 ? &ra : 0);
1280 d->setSecurityProps();
1281
1282 if(!d->c->serverStart(realm, mechlist, saslappname))
1283 return false;
1284 d->first = true;
1285 d->server = true;
1286 d->tried = false;
1287 return true;
1288}
1289
1290void SASL::putServerFirstStep(const QString &mech)
1291{
1292 int r = d->c->serverFirstStep(mech, 0);
1293 handleServerFirstStep(r);
1294}
1295
1296void SASL::putServerFirstStep(const QString &mech, const QByteArray &clientInit)
1297{
1298 int r = d->c->serverFirstStep(mech, &clientInit);
1299 handleServerFirstStep(r);
1300}
1301
1302void SASL::handleServerFirstStep(int r)
1303{
1304 if(r == QCA_SASLContext::Success)
1305 authenticated();
1306 else if(r == QCA_SASLContext::Continue)
1307 nextStep(d->c->result());
1308 else if(r == QCA_SASLContext::AuthCheck)
1309 tryAgain();
1310 else
1311 error(ErrAuth);
1312}
1313
1314void SASL::putStep(const QByteArray &stepData)
1315{
1316 d->stepData = stepData.copy();
1317 tryAgain();
1318}
1319
1320void SASL::setUsername(const QString &user)
1321{
1322 d->c->setClientParams(&user, 0, 0, 0);
1323}
1324
1325void SASL::setAuthzid(const QString &authzid)
1326{
1327 d->c->setClientParams(0, &authzid, 0, 0);
1328}
1329
1330void SASL::setPassword(const QString &pass)
1331{
1332 d->c->setClientParams(0, 0, &pass, 0);
1333}
1334
1335void SASL::setRealm(const QString &realm)
1336{
1337 d->c->setClientParams(0, 0, 0, &realm);
1338}
1339
1340void SASL::continueAfterParams()
1341{
1342 tryAgain();
1343}
1344
1345void SASL::continueAfterAuthCheck()
1346{
1347 tryAgain();
1348}
1349
1350void SASL::tryAgain()
1351{
1352 int r;
1353
1354 if(d->server) {
1355 if(!d->tried) {
1356 r = d->c->nextStep(d->stepData);
1357 d->tried = true;
1358 }
1359 else {
1360 r = d->c->tryAgain();
1361 }
1362
1363 if(r == QCA_SASLContext::Error) {
1364 error(ErrAuth);
1365 return;
1366 }
1367 else if(r == QCA_SASLContext::Continue) {
1368 d->tried = false;
1369 nextStep(d->c->result());
1370 return;
1371 }
1372 else if(r == QCA_SASLContext::AuthCheck) {
1373 authCheck(d->c->username(), d->c->authzid());
1374 return;
1375 }
1376 }
1377 else {
1378 if(d->first) {
1379 if(!d->tried) {
1380 r = d->c->clientFirstStep(d->allowCSF);
1381 d->tried = true;
1382 }
1383 else
1384 r = d->c->tryAgain();
1385
1386 if(r == QCA_SASLContext::Error) {
1387 error(ErrAuth);
1388 return;
1389 }
1390 else if(r == QCA_SASLContext::NeedParams) {
1391 //d->tried = false;
1392 QCA_SASLNeedParams np = d->c->clientParamsNeeded();
1393 needParams(np.user, np.authzid, np.pass, np.realm);
1394 return;
1395 }
1396
1397 QString mech = d->c->mech();
1398 const QByteArray *clientInit = d->c->clientInit();
1399
1400 d->first = false;
1401 d->tried = false;
1402 clientFirstStep(mech, clientInit);
1403 }
1404 else {
1405 if(!d->tried) {
1406 r = d->c->nextStep(d->stepData);
1407 d->tried = true;
1408 }
1409 else
1410 r = d->c->tryAgain();
1411
1412 if(r == QCA_SASLContext::Error) {
1413 error(ErrAuth);
1414 return;
1415 }
1416 else if(r == QCA_SASLContext::NeedParams) {
1417 //d->tried = false;
1418 QCA_SASLNeedParams np = d->c->clientParamsNeeded();
1419 needParams(np.user, np.authzid, np.pass, np.realm);
1420 return;
1421 }
1422 d->tried = false;
1423 //else if(r == QCA_SASLContext::Continue) {
1424 nextStep(d->c->result());
1425 // return;
1426 //}
1427 }
1428 }
1429
1430 if(r == QCA_SASLContext::Success)
1431 authenticated();
1432 else if(r == QCA_SASLContext::Error)
1433 error(ErrAuth);
1434}
1435
1436int SASL::ssf() const
1437{
1438 return d->c->security();
1439}
1440
1441void SASL::write(const QByteArray &a)
1442{
1443 QByteArray b;
1444 if(!d->c->encode(a, &b)) {
1445 error(ErrCrypt);
1446 return;
1447 }
1448 int oldsize = d->outbuf.size();
1449 d->outbuf.resize(oldsize + b.size());
1450 memcpy(d->outbuf.data() + oldsize, b.data(), b.size());
1451 readyReadOutgoing(a.size());
1452}
1453
1454QByteArray SASL::read()
1455{
1456 QByteArray a = d->inbuf.copy();
1457 d->inbuf.resize(0);
1458 return a;
1459}
1460
1461void SASL::writeIncoming(const QByteArray &a)
1462{
1463 QByteArray b;
1464 if(!d->c->decode(a, &b)) {
1465 error(ErrCrypt);
1466 return;
1467 }
1468 int oldsize = d->inbuf.size();
1469 d->inbuf.resize(oldsize + b.size());
1470 memcpy(d->inbuf.data() + oldsize, b.data(), b.size());
1471 readyRead();
1472}
1473
1474QByteArray SASL::readOutgoing()
1475{
1476 QByteArray a = d->outbuf.copy();
1477 d->outbuf.resize(0);
1478 return a;
1479}
Note: See TracBrowser for help on using the repository browser.