1/*
2 * Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com>
3 * Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net>
4 * Copyright (C) 2014-2016 Ivan Romanov <drizt@land.ru>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA
20 *
21 */
22
23#include "qca_core.h"
24
25#include "qca_cert.h"
26#include "qca_keystore.h"
27#include "qca_plugin.h"
28#include "qca_textfilter.h"
29#include "qcaprovider.h"
30
31// for qAddPostRoutine
32#include <QCoreApplication>
33
34#include <QDir>
35#include <QMutex>
36#include <QSettings>
37#include <QVariantMap>
38#include <QWaitCondition>
39
40#ifdef Q_OS_UNIX
41#include <unistd.h>
42#endif
43
44int qcaVersion()
45{
46 return QCA_VERSION;
47}
48
49const char *qcaVersionStr()
50{
51 return QCA_VERSION_STR;
52}
53
54int qcaMajorVersion()
55{
56 return QCA_MAJOR_VERSION;
57}
58
59int qcaMinorVersion()
60{
61 return QCA_MINOR_VERSION;
62}
63
64int qcaPatchVersion()
65{
66 return QCA_PATCH_VERSION;
67}
68
69namespace QCA {
70
71// from qca_tools
72bool botan_init(int prealloc, bool mmap);
73void botan_deinit();
74
75// from qca_default
76Provider *create_default_provider();
77
78//----------------------------------------------------------------------------
79// Global
80//----------------------------------------------------------------------------
81class Global
82{
83public:
84 int refs;
85 bool secmem;
86 bool loaded;
87 bool first_scan;
88 QString app_name;
89 QMutex name_mutex;
90 ProviderManager *manager;
91 QMutex scan_mutex;
92 Random *rng;
93 QMutex rng_mutex;
94 Logger *logger;
95 QVariantMap properties;
96 QMutex prop_mutex;
97 QMap<QString, QVariantMap> config;
98 QMutex config_mutex;
99 QMutex logger_mutex;
100
101 Global()
102 {
103 refs = 0;
104 secmem = false;
105 loaded = false;
106 first_scan = false;
107 rng = nullptr;
108 logger = nullptr;
109 manager = new ProviderManager;
110 }
111
112 ~Global()
113 {
114 KeyStoreManager::shutdown();
115 delete rng;
116 rng = nullptr;
117 delete manager;
118 manager = nullptr;
119 delete logger;
120 logger = nullptr;
121 }
122
123 void ensure_loaded()
124 {
125 // probably we shouldn't overload scan mutex, or else rename it
126 QMutexLocker locker(&scan_mutex);
127 if (!loaded) {
128 loaded = true;
129 manager->setDefault(create_default_provider()); // manager owns it
130 }
131 }
132
133 bool ensure_first_scan()
134 {
135 scan_mutex.lock();
136 if (!first_scan) {
137 first_scan = true;
138 manager->scan();
139 scan_mutex.unlock();
140 return true;
141 }
142 scan_mutex.unlock();
143 return false;
144 }
145
146 void scan()
147 {
148 scan_mutex.lock();
149 first_scan = true;
150 manager->scan();
151 scan_mutex.unlock();
152 }
153
154 void ksm_scan()
155 {
156 KeyStoreManager::scan();
157 }
158
159 Logger *get_logger()
160 {
161 QMutexLocker locker(&logger_mutex);
162 if (!logger) {
163 logger = new Logger;
164
165 // needed so deinit may delete the logger regardless
166 // of what thread the logger was created from
167 logger->moveToThread(thread: nullptr);
168 }
169 return logger;
170 }
171
172 void unloadAllPlugins()
173 {
174 KeyStoreManager::shutdown();
175
176 // if the global_rng was owned by a plugin, then delete it
177 rng_mutex.lock();
178 if (rng && (rng->provider() != manager->find(QStringLiteral("default")))) {
179 delete rng;
180 rng = nullptr;
181 }
182 rng_mutex.unlock();
183
184 manager->unloadAll();
185 }
186};
187
188Q_GLOBAL_STATIC(QMutex, global_mutex)
189static Global *global = nullptr;
190
191static bool features_have(const QStringList &have, const QStringList &want)
192{
193 foreach (const QString &i, want) {
194 if (!have.contains(str: i))
195 return false;
196 }
197 return true;
198}
199
200void init(MemoryMode mode, int prealloc)
201{
202 QMutexLocker locker(global_mutex());
203 if (global) {
204 ++(global->refs);
205 return;
206 }
207
208 bool allow_mmap_fallback = false;
209 bool drop_root = false;
210 if (mode == Practical) {
211 allow_mmap_fallback = true;
212 drop_root = true;
213 } else if (mode == Locking)
214 drop_root = true;
215
216 bool secmem = botan_init(prealloc, mmap: allow_mmap_fallback);
217
218#if defined(Q_OS_UNIX)
219 if ((geteuid() == 0) && drop_root) {
220 setuid(getuid());
221 }
222#endif
223
224 global = new Global;
225 global->secmem = secmem;
226 ++(global->refs);
227
228 // for maximum setuid safety, qca should be initialized before qapp:
229 //
230 // int main(int argc, char **argv)
231 // {
232 // QCA::Initializer init;
233 // QCoreApplication app(argc, argv);
234 // return 0;
235 // }
236 //
237 // however, the above code has the unfortunate side-effect of causing
238 // qapp to deinit before qca, which can cause problems with any
239 // plugins that have active objects (notably KeyStore). we'll use a
240 // post routine to force qca to deinit first.
241 qAddPostRoutine(deinit);
242}
243
244void init()
245{
246 init(mode: Practical, prealloc: 64);
247}
248
249void deinit()
250{
251 QMutexLocker locker(global_mutex());
252 if (!global)
253 return;
254 --(global->refs);
255 if (global->refs == 0) {
256 // In order to maintain symmetry with the init() function, remove the
257 // post routine from QCoreApplication. This is needed in case when the
258 // QCA library is unloaded before QCoreApplication instance completes:
259 // QCoreApplication d-tor would try to execute the deinit() function,
260 // which would no longer be there.
261 // Note that this function is documented only in Qt 5.3 and later, but
262 // it has been present since ancient times with the same semantics.
263 qRemovePostRoutine(deinit);
264
265 delete global;
266 global = nullptr;
267 botan_deinit();
268 }
269}
270
271static bool global_check()
272{
273 Q_ASSERT(global);
274 if (!global)
275 return false;
276 return true;
277}
278
279static bool global_check_load()
280{
281 Q_ASSERT(global);
282 if (!global)
283 return false;
284 global->ensure_loaded();
285 return true;
286}
287
288QMutex *global_random_mutex()
289{
290 return &global->rng_mutex;
291}
292
293Random *global_random()
294{
295 if (!global->rng)
296 global->rng = new Random;
297 return global->rng;
298}
299
300bool haveSecureMemory()
301{
302 if (!global_check())
303 return false;
304
305 return global->secmem;
306}
307
308bool haveSecureRandom()
309{
310 if (!global_check_load())
311 return false;
312
313 QMutexLocker locker(global_random_mutex());
314 if (global_random()->provider()->name() != QLatin1String("default"))
315 return true;
316
317 return false;
318}
319
320bool isSupported(const QStringList &features, const QString &provider)
321{
322 if (!global_check_load())
323 return false;
324
325 // single
326 if (!provider.isEmpty()) {
327 Provider *p = global->manager->find(name: provider);
328 if (!p) {
329 // ok, try scanning for new stuff
330 global->scan();
331 p = global->manager->find(name: provider);
332 }
333
334 if (p && features_have(have: p->features(), want: features))
335 return true;
336 }
337 // all
338 else {
339 if (features_have(have: global->manager->allFeatures(), want: features))
340 return true;
341
342 global->manager->appendDiagnosticText(
343 QStringLiteral("Scanning to find features: %1\n").arg(a: features.join(QStringLiteral(" "))));
344
345 // ok, try scanning for new stuff
346 global->scan();
347
348 if (features_have(have: global->manager->allFeatures(), want: features))
349 return true;
350 }
351 return false;
352}
353
354bool isSupported(const char *features, const QString &provider)
355{
356 return isSupported(features: QString::fromLatin1(ba: features).split(sep: QLatin1Char(','), behavior: Qt::SkipEmptyParts), provider);
357}
358
359QStringList supportedFeatures()
360{
361 if (!global_check_load())
362 return QStringList();
363
364 // query all features
365 global->scan();
366 return global->manager->allFeatures();
367}
368
369QStringList defaultFeatures()
370{
371 if (!global_check_load())
372 return QStringList();
373
374 return global->manager->find(QStringLiteral("default"))->features();
375}
376
377ProviderList providers()
378{
379 if (!global_check_load())
380 return ProviderList();
381
382 global->ensure_first_scan();
383
384 return global->manager->providers();
385}
386
387bool insertProvider(Provider *p, int priority)
388{
389 if (!global_check_load())
390 return false;
391
392 global->ensure_first_scan();
393
394 return global->manager->add(p, priority);
395}
396
397bool unloadProvider(const QString &name)
398{
399 if (!global_check_load())
400 return false;
401
402 global->ensure_first_scan();
403
404 return global->manager->unload(name);
405}
406
407void setProviderPriority(const QString &name, int priority)
408{
409 if (!global_check_load())
410 return;
411
412 global->ensure_first_scan();
413
414 global->manager->changePriority(name, priority);
415}
416
417int providerPriority(const QString &name)
418{
419 if (!global_check_load())
420 return -1;
421
422 global->ensure_first_scan();
423
424 return global->manager->getPriority(name);
425}
426
427Provider *findProvider(const QString &name)
428{
429 if (!global_check_load())
430 return nullptr;
431
432 global->ensure_first_scan();
433
434 return global->manager->find(name);
435}
436
437Provider *defaultProvider()
438{
439 if (!global_check_load())
440 return nullptr;
441
442 return global->manager->find(QStringLiteral("default"));
443}
444
445QStringList pluginPaths()
446{
447 QStringList paths;
448#ifndef DEVELOPER_MODE
449 const QByteArray qcaPluginPath = qgetenv(varName: "QCA_PLUGIN_PATH");
450 if (!qcaPluginPath.isEmpty()) {
451#ifdef Q_OS_WIN
452 char pathSep(';');
453#else
454 char pathSep(':');
455#endif
456 foreach (const QByteArray &path, qcaPluginPath.split(pathSep)) {
457 const QString canonicalPath = QDir(QFile::decodeName(localFileName: path)).canonicalPath();
458 if (!canonicalPath.isEmpty())
459 paths << canonicalPath;
460 }
461 }
462 paths += QCoreApplication::libraryPaths();
463#endif
464 // In developer mode load plugins only from buildtree.
465 // In regular mode QCA_PLUGIN_PATH is path where plugins was installed
466 paths << QDir(QStringLiteral(QCA_PLUGIN_PATH)).canonicalPath();
467#ifndef DEVELOPER_MODE
468 paths.removeDuplicates();
469#endif
470 // No empty strings
471 paths.removeAll(t: QString());
472 return paths;
473}
474
475void scanForPlugins()
476{
477 if (!global_check_load())
478 return;
479
480 global->scan();
481 global->ksm_scan();
482}
483
484void unloadAllPlugins()
485{
486 if (!global_check_load())
487 return;
488
489 global->unloadAllPlugins();
490}
491
492QString pluginDiagnosticText()
493{
494 if (!global_check_load())
495 return QString();
496
497 return global->manager->diagnosticText();
498}
499
500void clearPluginDiagnosticText()
501{
502 if (!global_check_load())
503 return;
504
505 global->manager->clearDiagnosticText();
506}
507
508void appendPluginDiagnosticText(const QString &text)
509{
510 if (!global_check_load())
511 return;
512
513 global->manager->appendDiagnosticText(str: text);
514}
515
516void setProperty(const QString &name, const QVariant &value)
517{
518 if (!global_check_load())
519 return;
520
521 QMutexLocker locker(&global->prop_mutex);
522
523 global->properties[name] = value;
524}
525
526QVariant getProperty(const QString &name)
527{
528 if (!global_check_load())
529 return QVariant();
530
531 QMutexLocker locker(&global->prop_mutex);
532
533 return global->properties.value(key: name);
534}
535
536static bool configIsValid(const QVariantMap &config)
537{
538 if (!config.contains(QStringLiteral("formtype")))
539 return false;
540 QMapIterator<QString, QVariant> it(config);
541 while (it.hasNext()) {
542 it.next();
543 const QVariant &v = it.value();
544#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
545 if (v.typeId() != QMetaType::QString && v.typeId() != QMetaType::Int && v.typeId() != QMetaType::Bool)
546#else
547 if (v.type() != QVariant::String && v.type() != QVariant::Int && v.type() != QVariant::Bool)
548
549#endif
550 return false;
551 }
552 return true;
553}
554
555static QVariantMap readConfig(const QString &name)
556{
557 QSettings settings(QStringLiteral("Affinix"), QStringLiteral("QCA2"));
558 settings.beginGroup(QStringLiteral("ProviderConfig"));
559 const QStringList providerNames = settings.value(QStringLiteral("providerNames")).toStringList();
560 if (!providerNames.contains(str: name))
561 return QVariantMap();
562
563 settings.beginGroup(prefix: name);
564 const QStringList keys = settings.childKeys();
565 QVariantMap map;
566 foreach (const QString &key, keys)
567 map[key] = settings.value(key);
568 settings.endGroup();
569
570 if (!configIsValid(config: map))
571 return QVariantMap();
572 return map;
573}
574
575static bool writeConfig(const QString &name, const QVariantMap &config, bool systemWide = false)
576{
577 QSettings settings(QSettings::NativeFormat,
578 systemWide ? QSettings::SystemScope : QSettings::UserScope,
579 QStringLiteral("Affinix"),
580 QStringLiteral("QCA2"));
581 settings.beginGroup(QStringLiteral("ProviderConfig"));
582
583 // version
584 settings.setValue(QStringLiteral("version"), value: 2);
585
586 // add the entry if needed
587 QStringList providerNames = settings.value(QStringLiteral("providerNames")).toStringList();
588 if (!providerNames.contains(str: name))
589 providerNames += name;
590 settings.setValue(QStringLiteral("providerNames"), value: providerNames);
591
592 settings.beginGroup(prefix: name);
593 QMapIterator<QString, QVariant> it(config);
594 while (it.hasNext()) {
595 it.next();
596 settings.setValue(key: it.key(), value: it.value());
597 }
598 settings.endGroup();
599
600 if (settings.status() == QSettings::NoError)
601 return true;
602 return false;
603}
604
605void setProviderConfig(const QString &name, const QVariantMap &config)
606{
607 if (!global_check_load())
608 return;
609
610 if (!configIsValid(config))
611 return;
612
613 global->config_mutex.lock();
614 global->config[name] = config;
615 global->config_mutex.unlock();
616
617 Provider *p = findProvider(name);
618 if (p)
619 p->configChanged(config);
620}
621
622QVariantMap getProviderConfig(const QString &name)
623{
624 if (!global_check_load())
625 return QVariantMap();
626
627 QVariantMap conf;
628
629 global->config_mutex.lock();
630
631 // try loading from persistent storage
632 conf = readConfig(name);
633
634 // if not, load the one from memory
635 if (conf.isEmpty())
636 conf = global->config.value(key: name);
637
638 global->config_mutex.unlock();
639
640 // if provider doesn't exist or doesn't have a valid config form,
641 // use the config we loaded
642 Provider *p = findProvider(name);
643 if (!p)
644 return conf;
645 const QVariantMap pconf = p->defaultConfig();
646 if (!configIsValid(config: pconf))
647 return conf;
648
649 // if the config loaded was empty, use the provider's config
650 if (conf.isEmpty())
651 return pconf;
652
653 // if the config formtype doesn't match the provider's formtype,
654 // then use the provider's
655 if (pconf[QStringLiteral("formtype")] != conf[QStringLiteral("formtype")])
656 return pconf;
657
658 // otherwise, use the config loaded
659 return conf;
660}
661
662void saveProviderConfig(const QString &name)
663{
664 if (!global_check_load())
665 return;
666
667 QMutexLocker locker(&global->config_mutex);
668
669 QVariantMap conf = global->config.value(key: name);
670 if (conf.isEmpty())
671 return;
672
673 writeConfig(name, config: conf);
674}
675
676QVariantMap getProviderConfig_internal(Provider *p)
677{
678 QVariantMap conf;
679 const QString name = p->name();
680
681 global->config_mutex.lock();
682
683 // try loading from persistent storage
684 conf = readConfig(name);
685
686 // if not, load the one from memory
687 if (conf.isEmpty())
688 conf = global->config.value(key: name);
689
690 global->config_mutex.unlock();
691
692 // if provider doesn't exist or doesn't have a valid config form,
693 // use the config we loaded
694 const QVariantMap pconf = p->defaultConfig();
695 if (!configIsValid(config: pconf))
696 return conf;
697
698 // if the config loaded was empty, use the provider's config
699 if (conf.isEmpty())
700 return pconf;
701
702 // if the config formtype doesn't match the provider's formtype,
703 // then use the provider's
704 if (pconf[QStringLiteral("formtype")] != conf[QStringLiteral("formtype")])
705 return pconf;
706
707 // otherwise, use the config loaded
708 return conf;
709}
710
711QString globalRandomProvider()
712{
713 QMutexLocker locker(global_random_mutex());
714 return global_random()->provider()->name();
715}
716
717void setGlobalRandomProvider(const QString &provider)
718{
719 QMutexLocker locker(global_random_mutex());
720 delete global->rng;
721 global->rng = new Random(provider);
722}
723
724Logger *logger()
725{
726 return global->get_logger();
727}
728
729bool haveSystemStore()
730{
731 // ensure the system store is loaded
732 KeyStoreManager::start(QStringLiteral("default"));
733 KeyStoreManager ksm;
734 ksm.waitForBusyFinished();
735
736 const QStringList list = ksm.keyStores();
737 for (int n = 0; n < list.count(); ++n) {
738 KeyStore ks(list[n], &ksm);
739 if (ks.type() == KeyStore::System && ks.holdsTrustedCertificates())
740 return true;
741 }
742 return false;
743}
744
745CertificateCollection systemStore()
746{
747 // ensure the system store is loaded
748 KeyStoreManager::start(QStringLiteral("default"));
749 KeyStoreManager ksm;
750 ksm.waitForBusyFinished();
751
752 CertificateCollection col;
753 const QStringList list = ksm.keyStores();
754 for (int n = 0; n < list.count(); ++n) {
755 KeyStore ks(list[n], &ksm);
756
757 // system store
758 if (ks.type() == KeyStore::System && ks.holdsTrustedCertificates()) {
759 // extract contents
760 const QList<KeyStoreEntry> entries = ks.entryList();
761 for (int i = 0; i < entries.count(); ++i) {
762 if (entries[i].type() == KeyStoreEntry::TypeCertificate)
763 col.addCertificate(cert: entries[i].certificate());
764 else if (entries[i].type() == KeyStoreEntry::TypeCRL)
765 col.addCRL(crl: entries[i].crl());
766 }
767 break;
768 }
769 }
770 return col;
771}
772
773QString appName()
774{
775 if (!global_check())
776 return QString();
777
778 QMutexLocker locker(&global->name_mutex);
779
780 return global->app_name;
781}
782
783void setAppName(const QString &s)
784{
785 if (!global_check())
786 return;
787
788 QMutexLocker locker(&global->name_mutex);
789
790 global->app_name = s;
791}
792
793QString arrayToHex(const QByteArray &a)
794{
795 return Hex().arrayToString(a);
796}
797
798QByteArray hexToArray(const QString &str)
799{
800 return Hex().stringToArray(s: str).toByteArray();
801}
802
803QString arrayToBase64(const QByteArray &a)
804{
805 return Base64().arrayToString(a);
806}
807
808QByteArray base64ToArray(const QString &base64String)
809{
810 return Base64().stringToArray(s: base64String).toByteArray();
811}
812
813static Provider *getProviderForType(const QString &type, const QString &provider)
814{
815 Provider *p = nullptr;
816 bool scanned = global->ensure_first_scan();
817 if (!provider.isEmpty()) {
818 // try using specific provider
819 p = global->manager->findFor(name: provider, type);
820 if (!p && !scanned) {
821 // maybe this provider is new, so scan and try again
822 global->scan();
823 scanned = true;
824 p = global->manager->findFor(name: provider, type);
825 }
826 }
827 if (!p) {
828 // try using some other provider
829 p = global->manager->findFor(name: QString(), type);
830
831 // note: we used to rescan if no provider was found or if
832 // the only found provider was 'default'. now we only
833 // rescan if no provider was found. this optimizes lookups
834 // for features that are in the default provider (such as
835 // 'sha1') when no other plugin is available. the drawback
836 // is that if a plugin is installed later during runtime,
837 // then it won't be picked up without restarting the
838 // application or manually calling QCA::scanForPlugins.
839 // if((!p || p->name() == "default") && !scanned)
840 if (!p && !scanned) {
841 // maybe there are new providers, so scan and try again
842 // before giving up or using default
843 global->scan();
844 scanned = true;
845 p = global->manager->findFor(name: QString(), type);
846 }
847 }
848
849 return p;
850}
851
852static inline Provider::Context *doCreateContext(Provider *p, const QString &type)
853{
854 return p->createContext(type);
855}
856
857Provider::Context *getContext(const QString &type, const QString &provider)
858{
859 if (!global_check_load())
860 return nullptr;
861
862 Provider *p;
863 {
864 p = getProviderForType(type, provider);
865 if (!p)
866 return nullptr;
867 }
868
869 return doCreateContext(p, type);
870}
871
872Provider::Context *getContext(const QString &type, Provider *_p)
873{
874 if (!global_check_load())
875 return nullptr;
876
877 Provider *p;
878 {
879 p = global->manager->find(p: _p);
880 if (!p)
881 return nullptr;
882 }
883
884 return doCreateContext(p, type);
885}
886
887//----------------------------------------------------------------------------
888// Initializer
889//----------------------------------------------------------------------------
890Initializer::Initializer(MemoryMode m, int prealloc)
891{
892 init(mode: m, prealloc);
893}
894
895Initializer::~Initializer()
896{
897 deinit();
898}
899
900//----------------------------------------------------------------------------
901// Provider
902//----------------------------------------------------------------------------
903Provider::~Provider()
904{
905}
906
907void Provider::init()
908{
909}
910
911void Provider::deinit()
912{
913}
914
915int Provider::version() const
916{
917 return 0;
918}
919
920QString Provider::credit() const
921{
922 return QString();
923}
924
925QVariantMap Provider::defaultConfig() const
926{
927 return QVariantMap();
928}
929
930void Provider::configChanged(const QVariantMap &)
931{
932}
933
934Provider::Context::Context(Provider *parent, const QString &type)
935 : QObject()
936{
937 _provider = parent;
938 _type = type;
939}
940
941Provider::Context::Context(const Context &from)
942 : QObject()
943{
944 _provider = from._provider;
945 _type = from._type;
946}
947
948Provider::Context::~Context()
949{
950}
951
952Provider *Provider::Context::provider() const
953{
954 return _provider;
955}
956
957QString Provider::Context::type() const
958{
959 return _type;
960}
961
962bool Provider::Context::sameProvider(const Context *c) const
963{
964 return (c->provider() == _provider);
965}
966
967//----------------------------------------------------------------------------
968// BasicContext
969//----------------------------------------------------------------------------
970BasicContext::BasicContext(Provider *parent, const QString &type)
971 : Context(parent, type)
972{
973 moveToThread(thread: nullptr); // no thread association
974}
975
976BasicContext::BasicContext(const BasicContext &from)
977 : Context(from)
978{
979 moveToThread(thread: nullptr); // no thread association
980}
981
982BasicContext::~BasicContext()
983{
984}
985
986//----------------------------------------------------------------------------
987// InfoContext
988//----------------------------------------------------------------------------
989QStringList InfoContext::supportedHashTypes() const
990{
991 return QStringList();
992}
993
994QStringList InfoContext::supportedCipherTypes() const
995{
996 return QStringList();
997}
998
999QStringList InfoContext::supportedMACTypes() const
1000{
1001 return QStringList();
1002}
1003
1004//----------------------------------------------------------------------------
1005// PKeyBase
1006//----------------------------------------------------------------------------
1007PKeyBase::PKeyBase(Provider *p, const QString &type)
1008 : BasicContext(p, type)
1009{
1010}
1011
1012int PKeyBase::maximumEncryptSize(EncryptionAlgorithm) const
1013{
1014 return 0;
1015}
1016
1017SecureArray PKeyBase::encrypt(const SecureArray &, EncryptionAlgorithm)
1018{
1019 return SecureArray();
1020}
1021
1022bool PKeyBase::decrypt(const SecureArray &, SecureArray *, EncryptionAlgorithm)
1023{
1024 return false;
1025}
1026
1027void PKeyBase::startSign(SignatureAlgorithm, SignatureFormat)
1028{
1029}
1030
1031void PKeyBase::startVerify(SignatureAlgorithm, SignatureFormat)
1032{
1033}
1034
1035void PKeyBase::update(const MemoryRegion &)
1036{
1037}
1038
1039QByteArray PKeyBase::endSign()
1040{
1041 return QByteArray();
1042}
1043
1044bool PKeyBase::endVerify(const QByteArray &)
1045{
1046 return false;
1047}
1048
1049SymmetricKey PKeyBase::deriveKey(const PKeyBase &)
1050{
1051 return SymmetricKey();
1052}
1053
1054//----------------------------------------------------------------------------
1055// PKeyContext
1056//----------------------------------------------------------------------------
1057QByteArray PKeyContext::publicToDER() const
1058{
1059 return QByteArray();
1060}
1061
1062QString PKeyContext::publicToPEM() const
1063{
1064 return QString();
1065}
1066
1067ConvertResult PKeyContext::publicFromDER(const QByteArray &)
1068{
1069 return ErrorDecode;
1070}
1071
1072ConvertResult PKeyContext::publicFromPEM(const QString &)
1073{
1074 return ErrorDecode;
1075}
1076
1077SecureArray PKeyContext::privateToDER(const SecureArray &, PBEAlgorithm) const
1078{
1079 return SecureArray();
1080}
1081
1082QString PKeyContext::privateToPEM(const SecureArray &, PBEAlgorithm) const
1083{
1084 return QString();
1085}
1086
1087ConvertResult PKeyContext::privateFromDER(const SecureArray &, const SecureArray &)
1088{
1089 return ErrorDecode;
1090}
1091
1092ConvertResult PKeyContext::privateFromPEM(const QString &, const SecureArray &)
1093{
1094 return ErrorDecode;
1095}
1096
1097//----------------------------------------------------------------------------
1098// KeyStoreEntryContext
1099//----------------------------------------------------------------------------
1100bool KeyStoreEntryContext::isAvailable() const
1101{
1102 return true;
1103}
1104
1105KeyBundle KeyStoreEntryContext::keyBundle() const
1106{
1107 return KeyBundle();
1108}
1109
1110Certificate KeyStoreEntryContext::certificate() const
1111{
1112 return Certificate();
1113}
1114
1115CRL KeyStoreEntryContext::crl() const
1116{
1117 return CRL();
1118}
1119
1120PGPKey KeyStoreEntryContext::pgpSecretKey() const
1121{
1122 return PGPKey();
1123}
1124
1125PGPKey KeyStoreEntryContext::pgpPublicKey() const
1126{
1127 return PGPKey();
1128}
1129
1130bool KeyStoreEntryContext::ensureAccess()
1131{
1132 return true;
1133}
1134
1135//----------------------------------------------------------------------------
1136// KeyStoreListContext
1137//----------------------------------------------------------------------------
1138void KeyStoreListContext::start()
1139{
1140 QMetaObject::invokeMethod(obj: this, member: "busyEnd", c: Qt::QueuedConnection);
1141}
1142
1143void KeyStoreListContext::setUpdatesEnabled(bool)
1144{
1145}
1146
1147bool KeyStoreListContext::isReadOnly(int) const
1148{
1149 return true;
1150}
1151
1152KeyStoreEntryContext *KeyStoreListContext::entry(int id, const QString &entryId)
1153{
1154 KeyStoreEntryContext *out = nullptr;
1155 QList<KeyStoreEntryContext *> list = entryList(id);
1156 for (int n = 0; n < list.count(); ++n) {
1157 if (list[n]->id() == entryId) {
1158 out = list.takeAt(i: n);
1159 break;
1160 }
1161 }
1162 qDeleteAll(c: list);
1163 return out;
1164}
1165
1166KeyStoreEntryContext *KeyStoreListContext::entryPassive(const QString &serialized)
1167{
1168 Q_UNUSED(serialized);
1169 return nullptr;
1170}
1171
1172QString KeyStoreListContext::writeEntry(int, const KeyBundle &)
1173{
1174 return QString();
1175}
1176
1177QString KeyStoreListContext::writeEntry(int, const Certificate &)
1178{
1179 return QString();
1180}
1181
1182QString KeyStoreListContext::writeEntry(int, const CRL &)
1183{
1184 return QString();
1185}
1186
1187QString KeyStoreListContext::writeEntry(int, const PGPKey &)
1188{
1189 return QString();
1190}
1191
1192bool KeyStoreListContext::removeEntry(int, const QString &)
1193{
1194 return false;
1195}
1196
1197//----------------------------------------------------------------------------
1198// TLSContext
1199//----------------------------------------------------------------------------
1200void TLSContext::setMTU(int)
1201{
1202}
1203
1204//----------------------------------------------------------------------------
1205// MessageContext
1206//----------------------------------------------------------------------------
1207QString MessageContext::diagnosticText() const
1208{
1209 return QString();
1210}
1211
1212//----------------------------------------------------------------------------
1213// SMSContext
1214//----------------------------------------------------------------------------
1215void SMSContext::setTrustedCertificates(const CertificateCollection &)
1216{
1217}
1218
1219void SMSContext::setUntrustedCertificates(const CertificateCollection &)
1220{
1221}
1222
1223void SMSContext::setPrivateKeys(const QList<SecureMessageKey> &)
1224{
1225}
1226
1227//----------------------------------------------------------------------------
1228// BufferedComputation
1229//----------------------------------------------------------------------------
1230BufferedComputation::~BufferedComputation()
1231{
1232}
1233
1234MemoryRegion BufferedComputation::process(const MemoryRegion &a)
1235{
1236 clear();
1237 update(a);
1238 return final();
1239}
1240
1241//----------------------------------------------------------------------------
1242// Filter
1243//----------------------------------------------------------------------------
1244Filter::~Filter()
1245{
1246}
1247
1248MemoryRegion Filter::process(const MemoryRegion &a)
1249{
1250 clear();
1251 MemoryRegion buf = update(a);
1252 if (!ok())
1253 return MemoryRegion();
1254 const MemoryRegion fin = final();
1255 if (!ok())
1256 return MemoryRegion();
1257 if (buf.isSecure() || fin.isSecure())
1258 return (SecureArray(buf) + SecureArray(fin));
1259 else
1260 return QByteArray(buf.toByteArray() + fin.toByteArray());
1261}
1262
1263//----------------------------------------------------------------------------
1264// Algorithm
1265//----------------------------------------------------------------------------
1266class Algorithm::Private : public QSharedData
1267{
1268public:
1269 Provider::Context *c;
1270
1271 Private(Provider::Context *context)
1272 {
1273 c = context;
1274 // printf("** [%p] Algorithm Created\n", c);
1275 }
1276
1277 Private(const Private &from)
1278 : QSharedData(from)
1279 {
1280 c = from.c->clone();
1281 // printf("** [%p] Algorithm Copied (to [%p])\n", from.c, c);
1282 }
1283
1284 ~Private()
1285 {
1286 // printf("** [%p] Algorithm Destroyed\n", c);
1287 delete c;
1288 }
1289};
1290
1291Algorithm::Algorithm()
1292{
1293}
1294
1295Algorithm::Algorithm(const QString &type, const QString &provider)
1296{
1297 change(type, provider);
1298}
1299
1300Algorithm::Algorithm(const Algorithm &from)
1301{
1302 *this = from;
1303}
1304
1305Algorithm::~Algorithm()
1306{
1307}
1308
1309Algorithm &Algorithm::operator=(const Algorithm &from)
1310{
1311 d = from.d;
1312 return *this;
1313}
1314
1315QString Algorithm::type() const
1316{
1317 if (d)
1318 return d->c->type();
1319 else
1320 return QString();
1321}
1322
1323Provider *Algorithm::provider() const
1324{
1325 if (d)
1326 return d->c->provider();
1327 else
1328 return nullptr;
1329}
1330
1331Provider::Context *Algorithm::context()
1332{
1333 if (d)
1334 return d->c;
1335 else
1336 return nullptr;
1337}
1338
1339const Provider::Context *Algorithm::context() const
1340{
1341 if (d)
1342 return d->c;
1343 else
1344 return nullptr;
1345}
1346
1347void Algorithm::change(Provider::Context *c)
1348{
1349 if (c)
1350 d = new Private(c);
1351 else
1352 d = nullptr;
1353}
1354
1355void Algorithm::change(const QString &type, const QString &provider)
1356{
1357 if (!type.isEmpty())
1358 change(c: getContext(type, provider));
1359 else
1360 change(c: nullptr);
1361}
1362
1363Provider::Context *Algorithm::takeContext()
1364{
1365 if (d) {
1366 Provider::Context *c = d->c; // should cause a detach
1367 d->c = nullptr;
1368 d = nullptr;
1369 return c;
1370 } else
1371 return nullptr;
1372}
1373
1374//----------------------------------------------------------------------------
1375// SymmetricKey
1376//----------------------------------------------------------------------------
1377SymmetricKey::SymmetricKey()
1378{
1379}
1380
1381SymmetricKey::SymmetricKey(int size)
1382{
1383 set(Random::randomArray(size));
1384}
1385
1386SymmetricKey::SymmetricKey(const SecureArray &a)
1387{
1388 set(a);
1389}
1390
1391SymmetricKey::SymmetricKey(const QByteArray &a)
1392{
1393 set(SecureArray(a));
1394}
1395
1396/* from libgcrypt-1.2.0 */
1397static const unsigned char desWeakKeyTable[64][8] = {
1398 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*w*/
1399 {0x00, 0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e}, {0x00, 0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0},
1400 {0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe}, {0x00, 0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e}, /*sw*/
1401 {0x00, 0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00}, {0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe},
1402 {0x00, 0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0}, {0x00, 0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0}, /*sw*/
1403 {0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe}, {0x00, 0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00},
1404 {0x00, 0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e}, {0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe}, /*sw*/
1405 {0x00, 0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0}, {0x00, 0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e},
1406 {0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00}, {0x1e, 0x00, 0x00, 0x1e, 0x0e, 0x00, 0x00, 0x0e},
1407 {0x1e, 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x0e, 0x00}, /*sw*/
1408 {0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0, 0xfe}, {0x1e, 0x00, 0xfe, 0xe0, 0x0e, 0x00, 0xfe, 0xf0},
1409 {0x1e, 0x1e, 0x00, 0x00, 0x0e, 0x0e, 0x00, 0x00}, {0x1e, 0x1e, 0x1e, 0x1e, 0x0e, 0x0e, 0x0e, 0x0e}, /*w*/
1410 {0x1e, 0x1e, 0xe0, 0xe0, 0x0e, 0x0e, 0xf0, 0xf0}, {0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe, 0xfe},
1411 {0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00, 0xfe}, {0x1e, 0xe0, 0x1e, 0xe0, 0x0e, 0xf0, 0x0e, 0xf0}, /*sw*/
1412 {0x1e, 0xe0, 0xe0, 0x1e, 0x0e, 0xf0, 0xf0, 0x0e}, {0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0, 0xfe, 0x00},
1413 {0x1e, 0xfe, 0x00, 0xe0, 0x0e, 0xfe, 0x00, 0xf0}, {0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe}, /*sw*/
1414 {0x1e, 0xfe, 0xe0, 0x00, 0x0e, 0xfe, 0xf0, 0x00}, {0x1e, 0xfe, 0xfe, 0x1e, 0x0e, 0xfe, 0xfe, 0x0e},
1415 {0xe0, 0x00, 0x00, 0xe0, 0xf0, 0x00, 0x00, 0xf0}, {0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e, 0xfe},
1416 {0xe0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf0, 0x00}, /*sw*/
1417 {0xe0, 0x00, 0xfe, 0x1e, 0xf0, 0x00, 0xfe, 0x0e}, {0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00, 0xfe},
1418 {0xe0, 0x1e, 0x1e, 0xe0, 0xf0, 0x0e, 0x0e, 0xf0}, {0xe0, 0x1e, 0xe0, 0x1e, 0xf0, 0x0e, 0xf0, 0x0e}, /*sw*/
1419 {0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e, 0xfe, 0x00}, {0xe0, 0xe0, 0x00, 0x00, 0xf0, 0xf0, 0x00, 0x00},
1420 {0xe0, 0xe0, 0x1e, 0x1e, 0xf0, 0xf0, 0x0e, 0x0e}, {0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0}, /*w*/
1421 {0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe, 0xfe}, {0xe0, 0xfe, 0x00, 0x1e, 0xf0, 0xfe, 0x00, 0x0e},
1422 {0xe0, 0xfe, 0x1e, 0x00, 0xf0, 0xfe, 0x0e, 0x00}, {0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0, 0xfe}, /*sw*/
1423 {0xe0, 0xfe, 0xfe, 0xe0, 0xf0, 0xfe, 0xfe, 0xf0}, {0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe},
1424 {0xfe, 0x00, 0x1e, 0xe0, 0xfe, 0x00, 0x0e, 0xf0}, {0xfe, 0x00, 0xe0, 0x1e, 0xfe, 0x00, 0xf0, 0x0e},
1425 {0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00}, /*sw*/
1426 {0xfe, 0x1e, 0x00, 0xe0, 0xfe, 0x0e, 0x00, 0xf0}, {0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e, 0xfe},
1427 {0xfe, 0x1e, 0xe0, 0x00, 0xfe, 0x0e, 0xf0, 0x00}, {0xfe, 0x1e, 0xfe, 0x1e, 0xfe, 0x0e, 0xfe, 0x0e}, /*sw*/
1428 {0xfe, 0xe0, 0x00, 0x1e, 0xfe, 0xf0, 0x00, 0x0e}, {0xfe, 0xe0, 0x1e, 0x00, 0xfe, 0xf0, 0x0e, 0x00},
1429 {0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0, 0xfe}, {0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf0, 0xfe, 0xf0}, /*sw*/
1430 {0xfe, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x00}, {0xfe, 0xfe, 0x1e, 0x1e, 0xfe, 0xfe, 0x0e, 0x0e},
1431 {0xfe, 0xfe, 0xe0, 0xe0, 0xfe, 0xfe, 0xf0, 0xf0}, {0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe} /*w*/
1432};
1433
1434bool SymmetricKey::isWeakDESKey()
1435{
1436 if (size() != 8)
1437 return false; // dubious
1438 SecureArray workingCopy(8);
1439 // clear parity bits
1440 for (uint i = 0; i < 8; i++)
1441 workingCopy[i] = (data()[i]) & 0xfe;
1442
1443 for (auto n : desWeakKeyTable) {
1444 if (memcmp(s1: workingCopy.data(), s2: n, n: 8) == 0)
1445 return true;
1446 }
1447 return false;
1448}
1449
1450//----------------------------------------------------------------------------
1451// InitializationVector
1452//----------------------------------------------------------------------------
1453InitializationVector::InitializationVector()
1454{
1455}
1456
1457InitializationVector::InitializationVector(int size)
1458{
1459 set(Random::randomArray(size));
1460}
1461
1462InitializationVector::InitializationVector(const SecureArray &a)
1463{
1464 set(a);
1465}
1466
1467InitializationVector::InitializationVector(const QByteArray &a)
1468{
1469 set(SecureArray(a));
1470}
1471
1472//----------------------------------------------------------------------------
1473// AuthTag
1474//----------------------------------------------------------------------------
1475AuthTag::AuthTag()
1476{
1477}
1478
1479AuthTag::AuthTag(int size)
1480{
1481 resize(size);
1482}
1483
1484AuthTag::AuthTag(const SecureArray &a)
1485{
1486 set(a);
1487}
1488
1489AuthTag::AuthTag(const QByteArray &a)
1490{
1491 set(SecureArray(a));
1492}
1493
1494//----------------------------------------------------------------------------
1495// Event
1496//----------------------------------------------------------------------------
1497class Event::Private : public QSharedData
1498{
1499public:
1500 Type type;
1501 Source source;
1502 PasswordStyle style;
1503 KeyStoreInfo ksi;
1504 KeyStoreEntry kse;
1505 QString fname;
1506 void *ptr;
1507};
1508
1509Event::Event()
1510{
1511}
1512
1513Event::Event(const Event &from)
1514 : d(from.d)
1515{
1516}
1517
1518Event::~Event()
1519{
1520}
1521
1522Event &Event::operator=(const Event &from)
1523{
1524 d = from.d;
1525 return *this;
1526}
1527
1528bool Event::isNull() const
1529{
1530 return (d ? false : true);
1531}
1532
1533Event::Type Event::type() const
1534{
1535 return d->type;
1536}
1537
1538Event::Source Event::source() const
1539{
1540 return d->source;
1541}
1542
1543Event::PasswordStyle Event::passwordStyle() const
1544{
1545 return d->style;
1546}
1547
1548KeyStoreInfo Event::keyStoreInfo() const
1549{
1550 return d->ksi;
1551}
1552
1553KeyStoreEntry Event::keyStoreEntry() const
1554{
1555 return d->kse;
1556}
1557
1558QString Event::fileName() const
1559{
1560 return d->fname;
1561}
1562
1563void *Event::ptr() const
1564{
1565 return d->ptr;
1566}
1567
1568void Event::setPasswordKeyStore(PasswordStyle pstyle,
1569 const KeyStoreInfo &keyStoreInfo,
1570 const KeyStoreEntry &keyStoreEntry,
1571 void *ptr)
1572{
1573 if (!d)
1574 d = new Private;
1575 d->type = Password;
1576 d->source = KeyStore;
1577 d->style = pstyle;
1578 d->ksi = keyStoreInfo;
1579 d->kse = keyStoreEntry;
1580 d->fname = QString();
1581 d->ptr = ptr;
1582}
1583
1584void Event::setPasswordData(PasswordStyle pstyle, const QString &fileName, void *ptr)
1585{
1586 if (!d)
1587 d = new Private;
1588 d->type = Password;
1589 d->source = Data;
1590 d->style = pstyle;
1591 d->ksi = KeyStoreInfo();
1592 d->kse = KeyStoreEntry();
1593 d->fname = fileName;
1594 d->ptr = ptr;
1595}
1596
1597void Event::setToken(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr)
1598{
1599 if (!d)
1600 d = new Private;
1601 d->type = Token;
1602 d->source = KeyStore;
1603 d->style = StylePassword;
1604 d->ksi = keyStoreInfo;
1605 d->kse = keyStoreEntry;
1606 d->fname = QString();
1607 d->ptr = ptr;
1608}
1609
1610//----------------------------------------------------------------------------
1611// EventGlobal
1612//----------------------------------------------------------------------------
1613class HandlerBase : public QObject
1614{
1615 Q_OBJECT
1616public:
1617 HandlerBase(QObject *parent = nullptr)
1618 : QObject(parent)
1619 {
1620 }
1621
1622protected Q_SLOTS:
1623 virtual void ask(int id, const QCA::Event &e) = 0;
1624};
1625
1626class AskerBase : public QObject
1627{
1628 Q_OBJECT
1629public:
1630 AskerBase(QObject *parent = nullptr)
1631 : QObject(parent)
1632 {
1633 }
1634
1635 virtual void set_accepted(const SecureArray &password) = 0;
1636 virtual void set_rejected() = 0;
1637};
1638
1639static void handler_add(HandlerBase *h, int pos = -1);
1640static void handler_remove(HandlerBase *h);
1641static void handler_accept(HandlerBase *h, int id, const SecureArray &password);
1642static void handler_reject(HandlerBase *h, int id);
1643static bool asker_ask(AskerBase *a, const Event &e);
1644static void asker_cancel(AskerBase *a);
1645
1646Q_GLOBAL_STATIC(QMutex, g_event_mutex)
1647
1648class EventGlobal;
1649static EventGlobal *g_event = nullptr;
1650
1651class EventGlobal
1652{
1653public:
1654 class HandlerItem
1655 {
1656 public:
1657 HandlerBase *h;
1658 QList<int> ids;
1659 };
1660
1661 class AskerItem
1662 {
1663 public:
1664 AskerBase *a;
1665 int id;
1666 Event event;
1667 int handler_pos;
1668 };
1669
1670 QList<HandlerItem> handlers;
1671 QList<AskerItem> askers;
1672
1673 int next_id;
1674
1675 EventGlobal()
1676 {
1677 qRegisterMetaType<Event>(typeName: "QCA::Event");
1678 qRegisterMetaType<SecureArray>(typeName: "QCA::SecureArray");
1679 next_id = 0;
1680 }
1681
1682 int findHandlerItem(HandlerBase *h)
1683 {
1684 for (int n = 0; n < handlers.count(); ++n) {
1685 if (handlers[n].h == h)
1686 return n;
1687 }
1688 return -1;
1689 }
1690
1691 int findAskerItem(AskerBase *a)
1692 {
1693 for (int n = 0; n < askers.count(); ++n) {
1694 if (askers[n].a == a)
1695 return n;
1696 }
1697 return -1;
1698 }
1699
1700 int findAskerItemById(int id)
1701 {
1702 for (int n = 0; n < askers.count(); ++n) {
1703 if (askers[n].id == id)
1704 return n;
1705 }
1706 return -1;
1707 }
1708
1709 void ask(int asker_at)
1710 {
1711 AskerItem &i = askers[asker_at];
1712
1713 g_event->handlers[i.handler_pos].ids += i.id;
1714 QMetaObject::invokeMethod(
1715 obj: handlers[i.handler_pos].h, member: "ask", c: Qt::QueuedConnection, Q_ARG(int, i.id), Q_ARG(QCA::Event, i.event));
1716 }
1717
1718 void reject(int asker_at)
1719 {
1720 AskerItem &i = askers[asker_at];
1721
1722 // look for the next usable handler
1723 int pos = -1;
1724 for (int n = i.handler_pos + 1; n < g_event->handlers.count(); ++n) {
1725 // handler and asker can't be in the same thread
1726 // Q_ASSERT(g_event->handlers[n].h->thread() != i.a->thread());
1727 // if(g_event->handlers[n].h->thread() != i.a->thread())
1728 //{
1729 pos = n;
1730 break;
1731 //}
1732 }
1733
1734 // if there is one, try it
1735 if (pos != -1) {
1736 i.handler_pos = pos;
1737 ask(asker_at);
1738 }
1739 // if not, send official reject
1740 else {
1741 AskerBase *asker = i.a;
1742 askers.removeAt(i: asker_at);
1743
1744 asker->set_rejected();
1745 }
1746 }
1747};
1748
1749void handler_add(HandlerBase *h, int pos)
1750{
1751 QMutexLocker locker(g_event_mutex());
1752 if (!g_event)
1753 g_event = new EventGlobal;
1754
1755 EventGlobal::HandlerItem i;
1756 i.h = h;
1757
1758 if (pos != -1) {
1759 g_event->handlers.insert(i: pos, t: i);
1760
1761 // adjust handler positions
1762 for (int n = 0; n < g_event->askers.count(); ++n) {
1763 if (g_event->askers[n].handler_pos >= pos)
1764 g_event->askers[n].handler_pos++;
1765 }
1766 } else
1767 g_event->handlers += i;
1768}
1769
1770void handler_remove(HandlerBase *h)
1771{
1772 QMutexLocker locker(g_event_mutex());
1773 Q_ASSERT(g_event);
1774 if (!g_event)
1775 return;
1776 int at = g_event->findHandlerItem(h);
1777 Q_ASSERT(at != -1);
1778 if (at == -1)
1779 return;
1780
1781 const QList<int> ids = g_event->handlers[at].ids;
1782 g_event->handlers.removeAt(i: at);
1783
1784 // adjust handler positions within askers
1785 for (int n = 0; n < g_event->askers.count(); ++n) {
1786 if (g_event->askers[n].handler_pos >= at)
1787 g_event->askers[n].handler_pos--;
1788 }
1789
1790 // reject all askers
1791 foreach (int id, ids) {
1792 int asker_at = g_event->findAskerItemById(id);
1793 Q_ASSERT(asker_at != -1);
1794
1795 g_event->reject(asker_at);
1796 }
1797
1798 if (g_event->handlers.isEmpty()) {
1799 delete g_event;
1800 g_event = nullptr;
1801 }
1802}
1803
1804void handler_accept(HandlerBase *h, int id, const SecureArray &password)
1805{
1806 QMutexLocker locker(g_event_mutex());
1807 Q_ASSERT(g_event);
1808 if (!g_event)
1809 return;
1810 int at = g_event->findHandlerItem(h);
1811 Q_ASSERT(at != -1);
1812 if (at == -1)
1813 return;
1814 int asker_at = g_event->findAskerItemById(id);
1815 Q_ASSERT(asker_at != -1);
1816 if (asker_at == -1)
1817 return;
1818
1819 g_event->handlers[at].ids.removeAll(t: g_event->askers[asker_at].id);
1820
1821 AskerBase *asker = g_event->askers[asker_at].a;
1822 asker->set_accepted(password);
1823}
1824
1825void handler_reject(HandlerBase *h, int id)
1826{
1827 QMutexLocker locker(g_event_mutex());
1828 Q_ASSERT(g_event);
1829 if (!g_event)
1830 return;
1831 int at = g_event->findHandlerItem(h);
1832 Q_ASSERT(at != -1);
1833 if (at == -1)
1834 return;
1835 int asker_at = g_event->findAskerItemById(id);
1836 Q_ASSERT(asker_at != -1);
1837 if (asker_at == -1)
1838 return;
1839
1840 g_event->handlers[at].ids.removeAll(t: g_event->askers[asker_at].id);
1841
1842 g_event->reject(asker_at);
1843}
1844
1845bool asker_ask(AskerBase *a, const Event &e)
1846{
1847 QMutexLocker locker(g_event_mutex());
1848 if (!g_event)
1849 return false;
1850
1851 int pos = -1;
1852 for (int n = 0; n < g_event->handlers.count(); ++n) {
1853 // handler and asker can't be in the same thread
1854 // Q_ASSERT(g_event->handlers[n].h->thread() != a->thread());
1855 // if(g_event->handlers[n].h->thread() != a->thread())
1856 //{
1857 pos = n;
1858 break;
1859 //}
1860 }
1861 if (pos == -1)
1862 return false;
1863
1864 EventGlobal::AskerItem i;
1865 i.a = a;
1866 i.id = g_event->next_id++;
1867 i.event = e;
1868 i.handler_pos = pos;
1869 g_event->askers += i;
1870 const int asker_at = g_event->askers.count() - 1;
1871
1872 g_event->ask(asker_at);
1873 return true;
1874}
1875
1876void asker_cancel(AskerBase *a)
1877{
1878 QMutexLocker locker(g_event_mutex());
1879 if (!g_event)
1880 return;
1881 int at = g_event->findAskerItem(a);
1882 if (at == -1)
1883 return;
1884
1885 for (int n = 0; n < g_event->handlers.count(); ++n)
1886 g_event->handlers[n].ids.removeAll(t: g_event->askers[at].id);
1887
1888 g_event->askers.removeAt(i: at);
1889}
1890
1891//----------------------------------------------------------------------------
1892// EventHandler
1893//----------------------------------------------------------------------------
1894class EventHandler::Private : public HandlerBase
1895{
1896 Q_OBJECT
1897public:
1898 EventHandler *q;
1899 bool started;
1900 QList<int> activeIds;
1901
1902 Private(EventHandler *_q)
1903 : HandlerBase(_q)
1904 , q(_q)
1905 {
1906 started = false;
1907 }
1908
1909public Q_SLOTS:
1910 void ask(int id, const QCA::Event &e) override
1911 {
1912 activeIds += id;
1913 emit q->eventReady(id, context: e);
1914 }
1915};
1916
1917EventHandler::EventHandler(QObject *parent)
1918 : QObject(parent)
1919{
1920 d = new Private(this);
1921}
1922
1923EventHandler::~EventHandler()
1924{
1925 if (d->started) {
1926 foreach (int id, d->activeIds)
1927 handler_reject(h: d, id);
1928
1929 handler_remove(h: d);
1930 }
1931
1932 delete d;
1933}
1934
1935void EventHandler::start()
1936{
1937 d->started = true;
1938 handler_add(h: d);
1939}
1940
1941void EventHandler::submitPassword(int id, const SecureArray &password)
1942{
1943 if (!d->activeIds.contains(t: id))
1944 return;
1945
1946 d->activeIds.removeAll(t: id);
1947 handler_accept(h: d, id, password);
1948}
1949
1950void EventHandler::tokenOkay(int id)
1951{
1952 if (!d->activeIds.contains(t: id))
1953 return;
1954
1955 d->activeIds.removeAll(t: id);
1956 handler_accept(h: d, id, password: SecureArray());
1957}
1958
1959void EventHandler::reject(int id)
1960{
1961 if (!d->activeIds.contains(t: id))
1962 return;
1963
1964 d->activeIds.removeAll(t: id);
1965 handler_reject(h: d, id);
1966}
1967
1968//----------------------------------------------------------------------------
1969// PasswordAsker
1970//----------------------------------------------------------------------------
1971class AskerPrivate : public AskerBase
1972{
1973 Q_OBJECT
1974public:
1975 enum Type
1976 {
1977 Password,
1978 Token
1979 };
1980
1981 Type type;
1982 PasswordAsker *passwordAsker;
1983 TokenAsker *tokenAsker;
1984
1985 QMutex m;
1986 QWaitCondition w;
1987
1988 bool accepted;
1989 SecureArray password;
1990 bool waiting;
1991 bool done;
1992
1993 AskerPrivate(PasswordAsker *parent)
1994 : AskerBase(parent)
1995 {
1996 passwordAsker = parent;
1997 tokenAsker = nullptr;
1998 type = Password;
1999 accepted = false;
2000 waiting = false;
2001 done = true;
2002 }
2003
2004 AskerPrivate(TokenAsker *parent)
2005 : AskerBase(parent)
2006 {
2007 passwordAsker = nullptr;
2008 tokenAsker = parent;
2009 type = Token;
2010 accepted = false;
2011 waiting = false;
2012 done = true;
2013 }
2014
2015 void ask(const Event &e)
2016 {
2017 accepted = false;
2018 waiting = false;
2019 done = false;
2020 password.clear();
2021
2022 if (!asker_ask(a: this, e)) {
2023 done = true;
2024 QMetaObject::invokeMethod(obj: this, member: "emitResponseReady", c: Qt::QueuedConnection);
2025 }
2026 }
2027
2028 void cancel()
2029 {
2030 if (!done)
2031 asker_cancel(a: this);
2032 }
2033
2034 void set_accepted(const SecureArray &_password) override
2035 {
2036 QMutexLocker locker(&m);
2037 accepted = true;
2038 password = _password;
2039 done = true;
2040 if (waiting)
2041 w.wakeOne();
2042 else
2043 QMetaObject::invokeMethod(obj: this, member: "emitResponseReady", c: Qt::QueuedConnection);
2044 }
2045
2046 void set_rejected() override
2047 {
2048 QMutexLocker locker(&m);
2049 done = true;
2050 if (waiting)
2051 w.wakeOne();
2052 else
2053 QMetaObject::invokeMethod(obj: this, member: "emitResponseReady", c: Qt::QueuedConnection);
2054 }
2055
2056 void waitForResponse()
2057 {
2058 QMutexLocker locker(&m);
2059 if (done)
2060 return;
2061 waiting = true;
2062 w.wait(lockedMutex: &m);
2063 waiting = false;
2064 }
2065
2066public Q_SLOTS:
2067 virtual void emitResponseReady() = 0;
2068};
2069
2070class PasswordAsker::Private : public AskerPrivate
2071{
2072 Q_OBJECT
2073public:
2074 Private(PasswordAsker *_q)
2075 : AskerPrivate(_q)
2076 {
2077 }
2078
2079 void emitResponseReady() override
2080 {
2081 emit passwordAsker->responseReady();
2082 }
2083};
2084
2085PasswordAsker::PasswordAsker(QObject *parent)
2086 : QObject(parent)
2087{
2088 d = new Private(this);
2089}
2090
2091PasswordAsker::~PasswordAsker()
2092{
2093 delete d;
2094}
2095
2096void PasswordAsker::ask(Event::PasswordStyle pstyle,
2097 const KeyStoreInfo &keyStoreInfo,
2098 const KeyStoreEntry &keyStoreEntry,
2099 void *ptr)
2100{
2101 Event e;
2102 e.setPasswordKeyStore(pstyle, keyStoreInfo, keyStoreEntry, ptr);
2103 d->ask(e);
2104}
2105
2106void PasswordAsker::ask(Event::PasswordStyle pstyle, const QString &fileName, void *ptr)
2107{
2108 Event e;
2109 e.setPasswordData(pstyle, fileName, ptr);
2110 d->ask(e);
2111}
2112
2113void PasswordAsker::cancel()
2114{
2115 d->cancel();
2116}
2117
2118void PasswordAsker::waitForResponse()
2119{
2120 d->waitForResponse();
2121}
2122
2123bool PasswordAsker::accepted() const
2124{
2125 return d->accepted;
2126}
2127
2128SecureArray PasswordAsker::password() const
2129{
2130 return d->password;
2131}
2132
2133//----------------------------------------------------------------------------
2134// TokenAsker
2135//----------------------------------------------------------------------------
2136class TokenAsker::Private : public AskerPrivate
2137{
2138 Q_OBJECT
2139public:
2140 Private(TokenAsker *_q)
2141 : AskerPrivate(_q)
2142 {
2143 }
2144
2145 void emitResponseReady() override
2146 {
2147 emit tokenAsker->responseReady();
2148 }
2149};
2150
2151TokenAsker::TokenAsker(QObject *parent)
2152 : QObject(parent)
2153{
2154 d = new Private(this);
2155}
2156
2157TokenAsker::~TokenAsker()
2158{
2159 delete d;
2160}
2161
2162void TokenAsker::ask(const KeyStoreInfo &keyStoreInfo, const KeyStoreEntry &keyStoreEntry, void *ptr)
2163{
2164 Event e;
2165 e.setToken(keyStoreInfo, keyStoreEntry, ptr);
2166 d->ask(e);
2167}
2168
2169void TokenAsker::cancel()
2170{
2171 d->cancel();
2172}
2173
2174void TokenAsker::waitForResponse()
2175{
2176 d->waitForResponse();
2177}
2178
2179bool TokenAsker::accepted() const
2180{
2181 return d->accepted;
2182}
2183
2184}
2185
2186#include "qca_core.moc"
2187

source code of qca/src/qca_core.cpp