1/*
2 * Copyright (C) 2007 Alon Bar-Lev <alon.barlev@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 *
18 */
19
20#include <QFile>
21#include <QHash>
22#include <QtCrypto>
23#include <QtPlugin>
24
25using namespace QCA;
26
27// qPrintable is ASCII only!!!
28#define myPrintable(s) (s).toUtf8().constData()
29
30namespace softstoreQCAPlugin {
31
32class softstoreKeyStoreListContext;
33static softstoreKeyStoreListContext *s_keyStoreList = nullptr;
34
35enum KeyType
36{
37 keyTypeInvalid,
38 keyTypePKCS12,
39 keyTypePKCS8Inline,
40 keyTypePKCS8FilePEM,
41 keyTypePKCS8FileDER
42};
43
44enum PublicType
45{
46 publicTypeInvalid,
47 publicTypeX509Chain
48};
49
50struct SoftStoreEntry
51{
52 QString name;
53 CertificateChain chain;
54 KeyType keyReferenceType;
55 QString keyReference;
56 bool noPassphrase;
57 int unlockTimeout;
58};
59
60class softstorePKeyBase : public PKeyBase
61{
62 Q_OBJECT
63
64private:
65 bool _has_privateKeyRole;
66 SoftStoreEntry _entry;
67 QString _serialized;
68 PrivateKey _privkey;
69 PrivateKey _privkeySign;
70 PublicKey _pubkey;
71 QDateTime dueTime;
72
73public:
74 static inline QString typeToString(PKey::Type t)
75 {
76 switch (t) {
77 case PKey::RSA:
78 return QStringLiteral("rsa");
79 case PKey::DSA:
80 return QStringLiteral("dsa");
81 case PKey::DH:
82 return QStringLiteral("dh");
83 default:
84 return QLatin1String("");
85 }
86 }
87
88 softstorePKeyBase(const SoftStoreEntry &entry, const QString &serialized, Provider *p)
89 : PKeyBase(p, QStringLiteral("rsa") /*typeToString (entry.chain.primary ().subjectPublicKey ().type ())*/)
90 {
91 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - entry"), Logger::Debug);
92
93 _has_privateKeyRole = true;
94 _entry = entry;
95 _serialized = serialized;
96 _pubkey = _entry.chain.primary().subjectPublicKey();
97
98 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - return"), Logger::Debug);
99 }
100
101 softstorePKeyBase(const softstorePKeyBase &from)
102 : PKeyBase(from.provider(), QStringLiteral("rsa") /*typeToString (from._pubkey.type ())*/)
103 {
104 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - entry"), Logger::Debug);
105
106 _has_privateKeyRole = from._has_privateKeyRole;
107 _entry = from._entry;
108 _serialized = from._serialized;
109 _pubkey = from._pubkey;
110 _privkey = from._privkey;
111
112 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - return"), Logger::Debug);
113 }
114
115 ~softstorePKeyBase() override
116 {
117 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - entry"), Logger::Debug);
118
119 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - return"), Logger::Debug);
120 }
121
122 Provider::Context *clone() const override
123 {
124 return new softstorePKeyBase(*this);
125 }
126
127public:
128 bool isNull() const override
129 {
130 return _pubkey.isNull();
131 }
132
133 PKey::Type type() const override
134 {
135 return _pubkey.type();
136 }
137
138 bool isPrivate() const override
139 {
140 return _has_privateKeyRole;
141 }
142
143 bool canExport() const override
144 {
145 return !_has_privateKeyRole;
146 }
147
148 void convertToPublic() override
149 {
150 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - entry"), Logger::Debug);
151
152 if (_has_privateKeyRole) {
153 _has_privateKeyRole = false;
154 }
155
156 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - return"), Logger::Debug);
157 }
158
159 int bits() const override
160 {
161 return _pubkey.bitSize();
162 }
163
164 int maximumEncryptSize(EncryptionAlgorithm alg) const override
165 {
166 return _pubkey.maximumEncryptSize(alg);
167 }
168
169 SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override
170 {
171 return _pubkey.encrypt(a: in, alg);
172 }
173
174 bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override
175 {
176 if (_ensureAccess()) {
177 return _privkey.decrypt(in, out, alg);
178 } else {
179 return false;
180 }
181 }
182
183 void startSign(SignatureAlgorithm alg, SignatureFormat format) override
184 {
185 if (_ensureAccess()) {
186 /*
187 * We must use one object thought
188 * signing, so it won't expire by
189 * it-self or during passphrase.
190 */
191 _privkeySign = _privkey;
192 _privkeySign.startSign(alg, format);
193 }
194 }
195
196 void startVerify(SignatureAlgorithm alg, SignatureFormat sf) override
197 {
198 _pubkey.startVerify(alg, format: sf);
199 }
200
201 void update(const MemoryRegion &in) override
202 {
203 if (_has_privateKeyRole) {
204 _privkeySign.update(a: in);
205 } else {
206 _pubkey.update(a: in);
207 }
208 }
209
210 QByteArray endSign() override
211 {
212 const QByteArray r = _privkeySign.signature();
213 _privkeySign = PrivateKey();
214 return r;
215 }
216
217 virtual bool validSignature(const QByteArray &sig)
218 {
219 return _pubkey.validSignature(sig);
220 }
221
222 virtual void createPrivate(int bits, int exp, bool block)
223 {
224 Q_UNUSED(bits);
225 Q_UNUSED(exp);
226 Q_UNUSED(block);
227 }
228
229 virtual void createPrivate(const BigInteger &n,
230 const BigInteger &e,
231 const BigInteger &p,
232 const BigInteger &q,
233 const BigInteger &d)
234 {
235 Q_UNUSED(n);
236 Q_UNUSED(e);
237 Q_UNUSED(p);
238 Q_UNUSED(q);
239 Q_UNUSED(d);
240 }
241
242 virtual void createPublic(const BigInteger &n, const BigInteger &e)
243 {
244 Q_UNUSED(n);
245 Q_UNUSED(e);
246 }
247
248public:
249 PublicKey _publicKey() const
250 {
251 return _pubkey;
252 }
253
254 bool _ensureAccess()
255 {
256 bool ret = false;
257
258 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - entry"), Logger::Debug);
259
260 if (_entry.unlockTimeout != -1) {
261 if (dueTime >= QDateTime::currentDateTime()) {
262 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - dueTime reached, clearing"),
263 Logger::Debug);
264 _privkey = PrivateKey();
265 }
266 }
267
268 if (!_privkey.isNull()) {
269 ret = true;
270 } else {
271 KeyStoreEntry entry;
272 KeyStoreEntryContext *context = nullptr;
273 QString storeId, storeName;
274 ConvertResult cresult;
275
276 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - no current key, creating"),
277 Logger::Debug);
278
279 // too lazy to create scope
280 context = reinterpret_cast<KeyStoreListContext *>(s_keyStoreList)->entryPassive(serialized: _serialized);
281 if (context != nullptr) {
282 storeId = context->storeId();
283 storeName = context->storeName();
284 entry.change(c: context);
285 }
286
287 while (!ret) {
288 SecureArray passphrase;
289
290 switch (_entry.keyReferenceType) {
291 case keyTypeInvalid:
292 case keyTypePKCS8Inline:
293 break;
294 case keyTypePKCS12:
295 case keyTypePKCS8FilePEM:
296 case keyTypePKCS8FileDER:
297 {
298 QFile file(_entry.keyReference);
299 while (!file.open(flags: QIODevice::ReadOnly)) {
300 TokenAsker asker;
301 asker.ask(keyStoreInfo: KeyStoreInfo(KeyStore::SmartCard, storeId, storeName), keyStoreEntry: entry, ptr: context);
302 asker.waitForResponse();
303 if (!asker.accepted()) {
304 goto cleanup1;
305 }
306 }
307 } break;
308 }
309
310 if (!_entry.noPassphrase) {
311 PasswordAsker asker;
312 asker.ask(pstyle: Event::StylePassphrase, keyStoreInfo: KeyStoreInfo(KeyStore::User, storeId, storeName), keyStoreEntry: entry, ptr: context);
313 asker.waitForResponse();
314 passphrase = asker.password();
315 if (!asker.accepted()) {
316 goto cleanup1;
317 }
318 }
319
320 switch (_entry.keyReferenceType) {
321 case keyTypeInvalid:
322 break;
323 case keyTypePKCS12:
324 {
325 KeyBundle bundle = KeyBundle::fromFile(fileName: _entry.keyReference, passphrase, result: &cresult);
326 if (cresult == ConvertGood) {
327 _privkey = bundle.privateKey();
328 ret = true;
329 }
330 } break;
331 case keyTypePKCS8Inline:
332 {
333 PrivateKey k =
334 PrivateKey::fromDER(a: Base64().stringToArray(s: _entry.keyReference), passphrase, result: &cresult);
335 if (cresult == ConvertGood) {
336 _privkey = k;
337 ret = true;
338 }
339 } break;
340 case keyTypePKCS8FilePEM:
341 {
342 PrivateKey k = PrivateKey::fromPEMFile(fileName: _entry.keyReference, passphrase, result: &cresult);
343 if (cresult == ConvertGood) {
344 _privkey = k;
345 ret = true;
346 }
347 } break;
348 case keyTypePKCS8FileDER:
349 {
350 QFile file(_entry.keyReference);
351 if (file.open(flags: QIODevice::ReadOnly)) {
352 const QByteArray contents = file.readAll();
353
354 PrivateKey k = PrivateKey::fromDER(a: contents, passphrase, result: &cresult);
355 if (cresult == ConvertGood) {
356 _privkey = k;
357 ret = true;
358 }
359 }
360 } break;
361 }
362 }
363
364 if (_entry.unlockTimeout != -1) {
365 dueTime = QDateTime::currentDateTime().addSecs(secs: _entry.unlockTimeout);
366 }
367
368 cleanup1:;
369 }
370
371 QCA_logTextMessage(QString::asprintf("softstorePKeyBase::_ensureAccess - return ret=%d", ret ? 1 : 0),
372 Logger::Debug);
373
374 return ret;
375 }
376};
377
378class softstorePKeyContext : public PKeyContext
379{
380 Q_OBJECT
381
382private:
383 PKeyBase *_k;
384
385public:
386 softstorePKeyContext(Provider *p)
387 : PKeyContext(p)
388 {
389 _k = nullptr;
390 }
391
392 ~softstorePKeyContext() override
393 {
394 delete _k;
395 _k = nullptr;
396 }
397
398 Provider::Context *clone() const override
399 {
400 softstorePKeyContext *c = new softstorePKeyContext(*this);
401 c->_k = (PKeyBase *)_k->clone();
402 return c;
403 }
404
405public:
406 QList<PKey::Type> supportedTypes() const override
407 {
408 QList<PKey::Type> list;
409 list += static_cast<softstorePKeyBase *>(_k)->_publicKey().type();
410 return list;
411 }
412
413 QList<PKey::Type> supportedIOTypes() const override
414 {
415 QList<PKey::Type> list;
416 list += static_cast<softstorePKeyBase *>(_k)->_publicKey().type();
417 return list;
418 }
419
420 QList<PBEAlgorithm> supportedPBEAlgorithms() const override
421 {
422 QList<PBEAlgorithm> list;
423 return list;
424 }
425
426 PKeyBase *key() override
427 {
428 return _k;
429 }
430
431 const PKeyBase *key() const override
432 {
433 return _k;
434 }
435
436 void setKey(PKeyBase *key) override
437 {
438 delete _k;
439 _k = key;
440 }
441
442 bool importKey(const PKeyBase *key) override
443 {
444 Q_UNUSED(key);
445 return false;
446 }
447
448 static int passphrase_cb(char *buf, int size, int rwflag, void *u)
449 {
450 Q_UNUSED(buf);
451 Q_UNUSED(size);
452 Q_UNUSED(rwflag);
453 Q_UNUSED(u);
454 return 0;
455 }
456
457 QByteArray publicToDER() const override
458 {
459 return static_cast<softstorePKeyBase *>(_k)->_publicKey().toDER();
460 }
461
462 QString publicToPEM() const override
463 {
464 return static_cast<softstorePKeyBase *>(_k)->_publicKey().toPEM();
465 }
466
467 ConvertResult publicFromDER(const QByteArray &in) override
468 {
469 Q_UNUSED(in);
470 return ErrorDecode;
471 }
472
473 ConvertResult publicFromPEM(const QString &s) override
474 {
475 Q_UNUSED(s);
476 return ErrorDecode;
477 }
478
479 SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override
480 {
481 Q_UNUSED(passphrase);
482 Q_UNUSED(pbe);
483 return SecureArray();
484 }
485
486 QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override
487 {
488 Q_UNUSED(passphrase);
489 Q_UNUSED(pbe);
490 return QString();
491 }
492
493 ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override
494 {
495 Q_UNUSED(in);
496 Q_UNUSED(passphrase);
497 return ErrorDecode;
498 }
499
500 ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override
501 {
502 Q_UNUSED(s);
503 Q_UNUSED(passphrase);
504 return ErrorDecode;
505 }
506};
507
508class softstoreKeyStoreEntryContext : public KeyStoreEntryContext
509{
510 Q_OBJECT
511private:
512 KeyStoreEntry::Type _item_type;
513 KeyBundle _key;
514 SoftStoreEntry _entry;
515 QString _serialized;
516
517public:
518 softstoreKeyStoreEntryContext(const KeyBundle &key,
519 const SoftStoreEntry &entry,
520 const QString &serialized,
521 Provider *p)
522 : KeyStoreEntryContext(p)
523 {
524 _item_type = KeyStoreEntry::TypeKeyBundle;
525 _key = key;
526 _entry = entry;
527 _serialized = serialized;
528 }
529
530 softstoreKeyStoreEntryContext(const softstoreKeyStoreEntryContext &from)
531 : KeyStoreEntryContext(from)
532 {
533 _item_type = from._item_type;
534 _key = from._key;
535 _entry = from._entry;
536 _serialized = from._serialized;
537 }
538
539 Provider::Context *clone() const override
540 {
541 return new softstoreKeyStoreEntryContext(*this);
542 }
543
544public:
545 KeyStoreEntry::Type type() const override
546 {
547 return KeyStoreEntry::TypeKeyBundle;
548 }
549
550 QString name() const override
551 {
552 return _entry.name;
553 }
554
555 QString id() const override
556 {
557 return _entry.name;
558 }
559
560 KeyBundle keyBundle() const override
561 {
562 return _key;
563 }
564
565 Certificate certificate() const override
566 {
567 return _entry.chain.primary();
568 }
569
570 QString storeId() const override
571 {
572 return QString::asprintf(format: "%s/%s", "qca-softstore", myPrintable(_entry.name));
573 }
574
575 QString storeName() const override
576 {
577 return _entry.name;
578 }
579
580 bool ensureAccess() override
581 {
582 return static_cast<softstorePKeyBase *>(static_cast<PKeyContext *>(_key.privateKey().context())->key())
583 ->_ensureAccess();
584 }
585
586 QString serialize() const override
587 {
588 return _serialized;
589 }
590};
591
592class softstoreKeyStoreListContext : public KeyStoreListContext
593{
594 Q_OBJECT
595
596private:
597 int _last_id;
598 QList<SoftStoreEntry> _entries;
599
600public:
601 softstoreKeyStoreListContext(Provider *p)
602 : KeyStoreListContext(p)
603 {
604 QCA_logTextMessage(
605 QString::asprintf("softstoreKeyStoreListContext::softstoreKeyStoreListContext - entry Provider=%p",
606 (void *)p),
607 Logger::Debug);
608
609 _last_id = 0;
610
611 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::softstoreKeyStoreListContext - return"),
612 Logger::Debug);
613 }
614
615 ~softstoreKeyStoreListContext() override
616 {
617 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - entry"),
618 Logger::Debug);
619
620 s_keyStoreList = nullptr;
621
622 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - return"),
623 Logger::Debug);
624 }
625
626 Provider::Context *clone() const override
627 {
628 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::clone - entry/return"), Logger::Debug);
629 return nullptr;
630 }
631
632public:
633 void start() override
634 {
635 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - entry"), Logger::Debug);
636
637 QMetaObject::invokeMethod(obj: this, member: "doReady", c: Qt::QueuedConnection);
638
639 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - return"), Logger::Debug);
640 }
641
642 void setUpdatesEnabled(bool enabled) override
643 {
644 QCA_logTextMessage(
645 QString::asprintf("softstoreKeyStoreListContext::setUpdatesEnabled - entry/return enabled=%d",
646 enabled ? 1 : 0),
647 Logger::Debug);
648 }
649
650 KeyStoreEntryContext *entry(int id, const QString &entryId) override
651 {
652 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entry - entry/return id=%d entryId='%s'",
653 id,
654 myPrintable(entryId)),
655 Logger::Debug);
656
657 Q_UNUSED(id);
658 Q_UNUSED(entryId);
659 return nullptr;
660 }
661
662 KeyStoreEntryContext *entryPassive(const QString &serialized) override
663 {
664 KeyStoreEntryContext *entry = nullptr;
665
666 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryPassive - entry serialized='%s'",
667 myPrintable(serialized)),
668 Logger::Debug);
669
670 if (serialized.startsWith(s: QLatin1String("qca-softstore/"))) {
671 SoftStoreEntry sentry;
672
673 if (_deserializeSoftStoreEntry(serialized, entry&: sentry)) {
674 entry = _keyStoreEntryBySoftStoreEntry(sentry);
675 }
676 }
677
678 QCA_logTextMessage(
679 QString::asprintf("softstoreKeyStoreListContext::entryPassive - return entry=%p", (void *)entry),
680 Logger::Debug);
681
682 return entry;
683 }
684
685 KeyStore::Type type(int id) const override
686 {
687 Q_UNUSED(id);
688
689 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::type - entry/return id=%d", id),
690 Logger::Debug);
691
692 return KeyStore::User;
693 }
694
695 QString storeId(int id) const override
696 {
697 QString ret;
698
699 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - entry id=%d", id), Logger::Debug);
700
701 ret = QStringLiteral("qca-softstore");
702
703 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - return ret=%s", myPrintable(ret)),
704 Logger::Debug);
705
706 return ret;
707 }
708
709 QString name(int id) const override
710 {
711 QString ret;
712
713 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - entry id=%d", id), Logger::Debug);
714
715 ret = QStringLiteral("User Software Store");
716
717 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - return ret=%s", myPrintable(ret)),
718 Logger::Debug);
719
720 return ret;
721 }
722
723 QList<KeyStoreEntry::Type> entryTypes(int id) const override
724 {
725 Q_UNUSED(id);
726
727 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryTypes - entry/return id=%d", id),
728 Logger::Debug);
729
730 QList<KeyStoreEntry::Type> list;
731 list += KeyStoreEntry::TypeKeyBundle;
732 list += KeyStoreEntry::TypeCertificate;
733 return list;
734 }
735
736 QList<int> keyStores() override
737 {
738 QList<int> list;
739
740 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::keyStores - entry"), Logger::Debug);
741
742 list += _last_id;
743
744 QCA_logTextMessage(
745 QString::asprintf("softstoreKeyStoreListContext::keyStores - return out.size()=%d", int(list.size())),
746 Logger::Debug);
747
748 return list;
749 }
750
751 QList<KeyStoreEntryContext *> entryList(int id) override
752 {
753 QList<KeyStoreEntryContext *> list;
754
755 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryList - entry id=%d", id),
756 Logger::Debug);
757
758 foreach (const SoftStoreEntry &e, _entries) {
759 list += _keyStoreEntryBySoftStoreEntry(sentry: e);
760 }
761
762 QCA_logTextMessage(
763 QString::asprintf("softstoreKeyStoreListContext::entryList - return out.size()=%d", int(list.size())),
764 Logger::Debug);
765
766 return list;
767 }
768
769 void _emit_diagnosticText(const QString &t)
770 {
771 QCA_logTextMessage(
772 QString::asprintf("softstoreKeyStoreListContext::_emit_diagnosticText - entry t='%s'", myPrintable(t)),
773 Logger::Debug);
774
775 QCA_logTextMessage(t, Logger::Warning);
776
777 emit diagnosticText(str: t);
778
779 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_emit_diagnosticText - return"),
780 Logger::Debug);
781 }
782
783private Q_SLOTS:
784 void doReady()
785 {
786 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - entry"), Logger::Debug);
787
788 emit busyEnd();
789
790 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - return"), Logger::Debug);
791 }
792
793 void doUpdated()
794 {
795 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - entry"), Logger::Debug);
796
797 emit updated();
798
799 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - return"), Logger::Debug);
800 }
801
802public:
803 void _updateConfig(const QVariantMap &config, const int maxEntries)
804 {
805 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - entry"), Logger::Debug);
806
807 QMap<QString, KeyType> keyTypeMap;
808 keyTypeMap[QStringLiteral("pkcs12")] = keyTypePKCS12;
809 keyTypeMap[QStringLiteral("pkcs8")] = keyTypePKCS8Inline;
810 keyTypeMap[QStringLiteral("pkcs8-file-pem")] = keyTypePKCS8FilePEM;
811 keyTypeMap[QStringLiteral("pkcs8-file-der")] = keyTypePKCS8FileDER;
812
813 QMap<QString, PublicType> publicTypeMap;
814 publicTypeMap[QStringLiteral("x509chain")] = publicTypeX509Chain;
815
816 _last_id++;
817 _entries.clear();
818
819 for (int i = 0; i < maxEntries; i++) {
820 if (config[QString::asprintf(format: "entry_%02d_enabled", i)].toBool()) {
821 ConvertResult cresult;
822 SoftStoreEntry entry;
823 PublicType publicType = publicTypeInvalid;
824
825 entry.name = config[QString::asprintf(format: "entry_%02d_name", i)].toString();
826 const QString stringReferenceType = config[QString::asprintf(format: "entry_%02d_private_type", i)].toString();
827 const QString stringPublicType = config[QString::asprintf(format: "entry_%02d_public_type", i)].toString();
828 entry.noPassphrase = config[QString::asprintf(format: "entry_%02d_no_passphrase", i)].toBool();
829 entry.unlockTimeout = config[QString::asprintf(format: "entry_%02d_unlock_timeout", i)].toInt();
830
831 if (publicTypeMap.contains(key: stringPublicType)) {
832 publicType = publicTypeMap[stringPublicType];
833 } else {
834 _emit_diagnosticText(t: QString::asprintf(format: "Software Store: Bad public key type of '%s' entry.\n",
835 myPrintable(entry.name)));
836 goto cleanup1;
837 }
838
839 if (keyTypeMap.contains(key: stringReferenceType)) {
840 entry.keyReferenceType = keyTypeMap[stringReferenceType];
841 } else {
842 _emit_diagnosticText(t: QString::asprintf(format: "Software Store: Bad private key type of '%s' entry.\n",
843 myPrintable(entry.name)));
844 goto cleanup1;
845 }
846
847 entry.keyReference = config[QString::asprintf(format: "entry_%02d_private", i)].toString();
848
849 switch (publicType) {
850 case publicTypeInvalid:
851 goto cleanup1;
852 break;
853 case publicTypeX509Chain:
854 const QStringList base64certs =
855 config[QString::asprintf(format: "entry_%02d_public", i)].toString().split(QStringLiteral("!"));
856
857 foreach (const QString &s, base64certs) {
858 entry.chain += Certificate::fromDER(a: Base64().stringToArray(s).toByteArray(), result: &cresult);
859 }
860
861 if (cresult != ConvertGood) {
862 _emit_diagnosticText(t: QString::asprintf(
863 format: "Software Store: Cannot load certificate of '%s' entry.\n", myPrintable(entry.name)));
864 goto cleanup1;
865 }
866 break;
867 }
868
869 _entries += entry;
870
871 cleanup1:; // nothing to do for this entry.
872 }
873 }
874
875 QMetaObject::invokeMethod(obj: s_keyStoreList, member: "doUpdated", c: Qt::QueuedConnection);
876
877 QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - return"), Logger::Debug);
878 }
879
880private:
881 QString _serializeSoftStoreEntry(const SoftStoreEntry &entry) const
882 {
883 QString serialized;
884
885 QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - entry name=%s",
886 myPrintable(entry.name)),
887 Logger::Debug);
888
889 serialized = QString::asprintf(format: "qca-softstore/0/%s/%d/%s/%d/%d/x509chain/",
890 myPrintable(_escapeString(entry.name)),
891 entry.keyReferenceType,
892 myPrintable(_escapeString(entry.keyReference)),
893 entry.noPassphrase ? 1 : 0,
894 entry.unlockTimeout);
895
896 QStringList list;
897 foreach (const Certificate &i, entry.chain) {
898 list += _escapeString(from: Base64().arrayToString(a: i.toDER()));
899 }
900
901 serialized.append(s: list.join(QStringLiteral("/")));
902
903 QCA_logTextMessage(
904 QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - return serialized='%s'",
905 myPrintable(serialized)),
906 Logger::Debug);
907
908 return serialized;
909 }
910
911 bool _deserializeSoftStoreEntry(const QString &serialized, SoftStoreEntry &entry) const
912 {
913 bool ret = false;
914
915 QCA_logTextMessage(
916 QString::asprintf("softstoreKeyStoreListContext::_deserializeSoftStoreEntry - entry from='%s'",
917 myPrintable(serialized)),
918 Logger::Debug);
919
920 entry = SoftStoreEntry();
921
922 const QStringList list = serialized.split(QStringLiteral("/"));
923 int n = 0;
924
925 if (list.size() < 8) {
926 goto cleanup;
927 }
928
929 if (list[n++] != QLatin1String("qca-softstore")) {
930 goto cleanup;
931 }
932
933 if (list[n++].toInt() != 0) {
934 goto cleanup;
935 }
936
937 entry.name = _unescapeString(from: list[n++]);
938 entry.keyReferenceType = (KeyType)list[n++].toInt();
939 entry.keyReference = _unescapeString(from: list[n++]);
940 entry.noPassphrase = list[n++].toInt() != 0;
941 entry.unlockTimeout = list[n++].toInt();
942 n++; // skip public key for now.
943
944 while (n < list.size()) {
945 Certificate cert = Certificate::fromDER(a: Base64().stringToArray(s: _unescapeString(from: list[n++])).toByteArray());
946 if (cert.isNull()) {
947 goto cleanup;
948 }
949 entry.chain += cert;
950 }
951
952 ret = true;
953
954 cleanup:
955
956 QCA_logTextMessage(
957 QString::asprintf(
958 "softstoreKeyStoreListContext::_deserializeSoftStoreEntry - return ret=%d chain.size()=%d",
959 ret ? 1 : 0,
960 int(entry.chain.size())),
961 Logger::Debug);
962
963 return ret;
964 }
965
966 softstoreKeyStoreEntryContext *_keyStoreEntryBySoftStoreEntry(const SoftStoreEntry &sentry) const
967 {
968 softstoreKeyStoreEntryContext *entry = nullptr;
969
970 QCA_logTextMessage(
971 QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - entry name=%s",
972 myPrintable(sentry.name)),
973 Logger::Debug);
974
975 QString serialized = _serializeSoftStoreEntry(entry: sentry);
976
977 softstorePKeyBase *pkey = new softstorePKeyBase(sentry, serialized, provider());
978
979 softstorePKeyContext *pkc = new softstorePKeyContext(provider());
980 pkc->setKey(pkey);
981 PrivateKey privkey;
982 privkey.change(c: pkc);
983 KeyBundle key;
984 key.setCertificateChainAndKey(c: sentry.chain, key: privkey);
985
986 entry = new softstoreKeyStoreEntryContext(key, sentry, serialized, provider());
987
988 QCA_logTextMessage(
989 QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - return entry=%p",
990 (void *)entry),
991 Logger::Debug);
992
993 return entry;
994 }
995
996 QString _escapeString(const QString &from) const
997 {
998 QString to;
999
1000 foreach (const QChar &c, from) {
1001 if (c == QLatin1Char('/') || c == QLatin1Char('\\')) {
1002 to += QString::asprintf(format: "\\x%04x", c.unicode());
1003 } else {
1004 to += c;
1005 }
1006 }
1007
1008 return to;
1009 }
1010
1011 QString _unescapeString(const QString &from) const
1012 {
1013 QString to;
1014
1015 for (int i = 0; i < from.size(); i++) {
1016 QChar c = from[i];
1017
1018 if (c == QLatin1Char('\\')) {
1019#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 2)
1020 to += QChar((ushort)QStringView(from).mid(pos: i + 2, n: 4).toInt(ok: nullptr, base: 16));
1021#else
1022 to += QChar((ushort)from.midRef(i + 2, 4).toInt(nullptr, 16));
1023#endif
1024 i += 5;
1025 } else {
1026 to += c;
1027 }
1028 }
1029
1030 return to;
1031 }
1032};
1033
1034}
1035
1036using namespace softstoreQCAPlugin;
1037
1038class softstoreProvider : public Provider
1039{
1040private:
1041 static const int _CONFIG_MAX_ENTRIES;
1042
1043 QVariantMap _config;
1044
1045public:
1046 softstoreProvider()
1047 {
1048 }
1049
1050 ~softstoreProvider() override
1051 {
1052 }
1053
1054public:
1055 int qcaVersion() const override
1056 {
1057 return QCA_VERSION;
1058 }
1059
1060 void init() override
1061 {
1062 }
1063
1064 QString name() const override
1065 {
1066 return QStringLiteral("qca-softstore");
1067 }
1068
1069 QStringList features() const override
1070 {
1071 QCA_logTextMessage(QStringLiteral("softstoreProvider::features - entry/return"), Logger::Debug);
1072
1073 QStringList list;
1074 list += QStringLiteral("pkey");
1075 list += QStringLiteral("keystorelist");
1076 return list;
1077 }
1078
1079 Context *createContext(const QString &type) override
1080 {
1081 Provider::Context *context = nullptr;
1082
1083 QCA_logTextMessage(QString::asprintf("softstoreProvider::createContext - entry type='%s'", myPrintable(type)),
1084 Logger::Debug);
1085
1086 if (type == QLatin1String("keystorelist")) {
1087 if (s_keyStoreList == nullptr) {
1088 s_keyStoreList = new softstoreKeyStoreListContext(this);
1089 s_keyStoreList->_updateConfig(config: _config, maxEntries: _CONFIG_MAX_ENTRIES);
1090 }
1091 context = s_keyStoreList;
1092 }
1093
1094 QCA_logTextMessage(QString::asprintf("softstoreProvider::createContext - return context=%p", (void *)context),
1095 Logger::Debug);
1096
1097 return context;
1098 }
1099
1100 QVariantMap defaultConfig() const override
1101 {
1102 QVariantMap mytemplate;
1103
1104 QCA_logTextMessage(QStringLiteral("softstoreProvider::defaultConfig - entry/return"), Logger::Debug);
1105
1106 mytemplate[QStringLiteral("formtype")] = QStringLiteral("http://affinix.com/qca/forms/qca-softstore#1.0");
1107 for (int i = 0; i < _CONFIG_MAX_ENTRIES; i++) {
1108 mytemplate[QString::asprintf(format: "entry_%02d_enabled", i)] = false;
1109 mytemplate[QString::asprintf(format: "entry_%02d_name", i)] = QLatin1String("");
1110 mytemplate[QString::asprintf(format: "entry_%02d_public_type", i)] = QLatin1String("");
1111 mytemplate[QString::asprintf(format: "entry_%02d_private_type", i)] = QLatin1String("");
1112 mytemplate[QString::asprintf(format: "entry_%02d_public", i)] = QLatin1String("");
1113 mytemplate[QString::asprintf(format: "entry_%02d_private", i)] = QLatin1String("");
1114 mytemplate[QString::asprintf(format: "entry_%02d_unlock_timeout", i)] = -1;
1115 mytemplate[QString::asprintf(format: "entry_%02d_no_passphrase", i)] = false;
1116 }
1117
1118 return mytemplate;
1119 }
1120
1121 void configChanged(const QVariantMap &config) override
1122 {
1123 QCA_logTextMessage(QStringLiteral("softstoreProvider::configChanged - entry"), Logger::Debug);
1124
1125 _config = config;
1126
1127 if (s_keyStoreList != nullptr) {
1128 s_keyStoreList->_updateConfig(config: _config, maxEntries: _CONFIG_MAX_ENTRIES);
1129 }
1130
1131 QCA_logTextMessage(QStringLiteral("softstoreProvider::configChanged - return"), Logger::Debug);
1132 }
1133};
1134
1135const int softstoreProvider::_CONFIG_MAX_ENTRIES = 50;
1136
1137class softstorePlugin : public QObject, public QCAPlugin
1138{
1139 Q_OBJECT
1140 Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0")
1141 Q_INTERFACES(QCAPlugin)
1142
1143public:
1144 Provider *createProvider() override
1145 {
1146 return new softstoreProvider;
1147 }
1148};
1149
1150#include "qca-softstore.moc"
1151

source code of qca/plugins/qca-softstore/qca-softstore.cpp