File indexing completed on 2024-04-28 04:43:50

0001 /*
0002  * Copyright (C) 2007  Alon Bar-Lev <alon.barlev@gmail.com>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Lesser General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2.1 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Lesser General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Lesser General Public
0015  * License along with this library; if not, write to the Free Software
0016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
0017  *
0018  */
0019 
0020 #include <QFile>
0021 #include <QHash>
0022 #include <QtCrypto>
0023 #include <QtPlugin>
0024 
0025 using namespace QCA;
0026 
0027 // qPrintable is ASCII only!!!
0028 #define myPrintable(s) (s).toUtf8().constData()
0029 
0030 namespace softstoreQCAPlugin {
0031 
0032 class softstoreKeyStoreListContext;
0033 static softstoreKeyStoreListContext *s_keyStoreList = nullptr;
0034 
0035 enum KeyType
0036 {
0037     keyTypeInvalid,
0038     keyTypePKCS12,
0039     keyTypePKCS8Inline,
0040     keyTypePKCS8FilePEM,
0041     keyTypePKCS8FileDER
0042 };
0043 
0044 enum PublicType
0045 {
0046     publicTypeInvalid,
0047     publicTypeX509Chain
0048 };
0049 
0050 struct SoftStoreEntry
0051 {
0052     QString          name;
0053     CertificateChain chain;
0054     KeyType          keyReferenceType;
0055     QString          keyReference;
0056     bool             noPassphrase;
0057     int              unlockTimeout;
0058 };
0059 
0060 class softstorePKeyBase : public PKeyBase
0061 {
0062     Q_OBJECT
0063 
0064 private:
0065     bool           _has_privateKeyRole;
0066     SoftStoreEntry _entry;
0067     QString        _serialized;
0068     PrivateKey     _privkey;
0069     PrivateKey     _privkeySign;
0070     PublicKey      _pubkey;
0071     QDateTime      dueTime;
0072 
0073 public:
0074     static inline QString typeToString(PKey::Type t)
0075     {
0076         switch (t) {
0077         case PKey::RSA:
0078             return QStringLiteral("rsa");
0079         case PKey::DSA:
0080             return QStringLiteral("dsa");
0081         case PKey::DH:
0082             return QStringLiteral("dh");
0083         default:
0084             return QLatin1String("");
0085         }
0086     }
0087 
0088     softstorePKeyBase(const SoftStoreEntry &entry, const QString &serialized, Provider *p)
0089         : PKeyBase(p, QStringLiteral("rsa") /*typeToString (entry.chain.primary ().subjectPublicKey ().type ())*/)
0090     {
0091         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - entry"), Logger::Debug);
0092 
0093         _has_privateKeyRole = true;
0094         _entry              = entry;
0095         _serialized         = serialized;
0096         _pubkey             = _entry.chain.primary().subjectPublicKey();
0097 
0098         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBase1 - return"), Logger::Debug);
0099     }
0100 
0101     softstorePKeyBase(const softstorePKeyBase &from)
0102         : PKeyBase(from.provider(), QStringLiteral("rsa") /*typeToString (from._pubkey.type ())*/)
0103     {
0104         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - entry"), Logger::Debug);
0105 
0106         _has_privateKeyRole = from._has_privateKeyRole;
0107         _entry              = from._entry;
0108         _serialized         = from._serialized;
0109         _pubkey             = from._pubkey;
0110         _privkey            = from._privkey;
0111 
0112         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::softstorePKeyBaseC - return"), Logger::Debug);
0113     }
0114 
0115     ~softstorePKeyBase() override
0116     {
0117         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - entry"), Logger::Debug);
0118 
0119         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::~softstorePKeyBase - return"), Logger::Debug);
0120     }
0121 
0122     Provider::Context *clone() const override
0123     {
0124         return new softstorePKeyBase(*this);
0125     }
0126 
0127 public:
0128     bool isNull() const override
0129     {
0130         return _pubkey.isNull();
0131     }
0132 
0133     PKey::Type type() const override
0134     {
0135         return _pubkey.type();
0136     }
0137 
0138     bool isPrivate() const override
0139     {
0140         return _has_privateKeyRole;
0141     }
0142 
0143     bool canExport() const override
0144     {
0145         return !_has_privateKeyRole;
0146     }
0147 
0148     void convertToPublic() override
0149     {
0150         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - entry"), Logger::Debug);
0151 
0152         if (_has_privateKeyRole) {
0153             _has_privateKeyRole = false;
0154         }
0155 
0156         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::convertToPublic - return"), Logger::Debug);
0157     }
0158 
0159     int bits() const override
0160     {
0161         return _pubkey.bitSize();
0162     }
0163 
0164     int maximumEncryptSize(EncryptionAlgorithm alg) const override
0165     {
0166         return _pubkey.maximumEncryptSize(alg);
0167     }
0168 
0169     SecureArray encrypt(const SecureArray &in, EncryptionAlgorithm alg) override
0170     {
0171         return _pubkey.encrypt(in, alg);
0172     }
0173 
0174     bool decrypt(const SecureArray &in, SecureArray *out, EncryptionAlgorithm alg) override
0175     {
0176         if (_ensureAccess()) {
0177             return _privkey.decrypt(in, out, alg);
0178         } else {
0179             return false;
0180         }
0181     }
0182 
0183     void startSign(SignatureAlgorithm alg, SignatureFormat format) override
0184     {
0185         if (_ensureAccess()) {
0186             /*
0187              * We must use one object thought
0188              * signing, so it won't expire by
0189              * it-self or during passphrase.
0190              */
0191             _privkeySign = _privkey;
0192             _privkeySign.startSign(alg, format);
0193         }
0194     }
0195 
0196     void startVerify(SignatureAlgorithm alg, SignatureFormat sf) override
0197     {
0198         _pubkey.startVerify(alg, sf);
0199     }
0200 
0201     void update(const MemoryRegion &in) override
0202     {
0203         if (_has_privateKeyRole) {
0204             _privkeySign.update(in);
0205         } else {
0206             _pubkey.update(in);
0207         }
0208     }
0209 
0210     QByteArray endSign() override
0211     {
0212         const QByteArray r = _privkeySign.signature();
0213         _privkeySign       = PrivateKey();
0214         return r;
0215     }
0216 
0217     virtual bool validSignature(const QByteArray &sig)
0218     {
0219         return _pubkey.validSignature(sig);
0220     }
0221 
0222     virtual void createPrivate(int bits, int exp, bool block)
0223     {
0224         Q_UNUSED(bits);
0225         Q_UNUSED(exp);
0226         Q_UNUSED(block);
0227     }
0228 
0229     virtual void createPrivate(const BigInteger &n,
0230                                const BigInteger &e,
0231                                const BigInteger &p,
0232                                const BigInteger &q,
0233                                const BigInteger &d)
0234     {
0235         Q_UNUSED(n);
0236         Q_UNUSED(e);
0237         Q_UNUSED(p);
0238         Q_UNUSED(q);
0239         Q_UNUSED(d);
0240     }
0241 
0242     virtual void createPublic(const BigInteger &n, const BigInteger &e)
0243     {
0244         Q_UNUSED(n);
0245         Q_UNUSED(e);
0246     }
0247 
0248 public:
0249     PublicKey _publicKey() const
0250     {
0251         return _pubkey;
0252     }
0253 
0254     bool _ensureAccess()
0255     {
0256         bool ret = false;
0257 
0258         QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - entry"), Logger::Debug);
0259 
0260         if (_entry.unlockTimeout != -1) {
0261             if (dueTime >= QDateTime::currentDateTime()) {
0262                 QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - dueTime reached, clearing"),
0263                                    Logger::Debug);
0264                 _privkey = PrivateKey();
0265             }
0266         }
0267 
0268         if (!_privkey.isNull()) {
0269             ret = true;
0270         } else {
0271             KeyStoreEntry         entry;
0272             KeyStoreEntryContext *context = nullptr;
0273             QString               storeId, storeName;
0274             ConvertResult         cresult;
0275 
0276             QCA_logTextMessage(QStringLiteral("softstorePKeyBase::_ensureAccess - no current key, creating"),
0277                                Logger::Debug);
0278 
0279             // too lazy to create scope
0280             context = reinterpret_cast<KeyStoreListContext *>(s_keyStoreList)->entryPassive(_serialized);
0281             if (context != nullptr) {
0282                 storeId   = context->storeId();
0283                 storeName = context->storeName();
0284                 entry.change(context);
0285             }
0286 
0287             while (!ret) {
0288                 SecureArray passphrase;
0289 
0290                 switch (_entry.keyReferenceType) {
0291                 case keyTypeInvalid:
0292                 case keyTypePKCS8Inline:
0293                     break;
0294                 case keyTypePKCS12:
0295                 case keyTypePKCS8FilePEM:
0296                 case keyTypePKCS8FileDER:
0297                 {
0298                     QFile file(_entry.keyReference);
0299                     while (!file.open(QIODevice::ReadOnly)) {
0300                         TokenAsker asker;
0301                         asker.ask(KeyStoreInfo(KeyStore::SmartCard, storeId, storeName), entry, context);
0302                         asker.waitForResponse();
0303                         if (!asker.accepted()) {
0304                             goto cleanup1;
0305                         }
0306                     }
0307                 } break;
0308                 }
0309 
0310                 if (!_entry.noPassphrase) {
0311                     PasswordAsker asker;
0312                     asker.ask(Event::StylePassphrase, KeyStoreInfo(KeyStore::User, storeId, storeName), entry, context);
0313                     asker.waitForResponse();
0314                     passphrase = asker.password();
0315                     if (!asker.accepted()) {
0316                         goto cleanup1;
0317                     }
0318                 }
0319 
0320                 switch (_entry.keyReferenceType) {
0321                 case keyTypeInvalid:
0322                     break;
0323                 case keyTypePKCS12:
0324                 {
0325                     KeyBundle bundle = KeyBundle::fromFile(_entry.keyReference, passphrase, &cresult);
0326                     if (cresult == ConvertGood) {
0327                         _privkey = bundle.privateKey();
0328                         ret      = true;
0329                     }
0330                 } break;
0331                 case keyTypePKCS8Inline:
0332                 {
0333                     PrivateKey k =
0334                         PrivateKey::fromDER(Base64().stringToArray(_entry.keyReference), passphrase, &cresult);
0335                     if (cresult == ConvertGood) {
0336                         _privkey = k;
0337                         ret      = true;
0338                     }
0339                 } break;
0340                 case keyTypePKCS8FilePEM:
0341                 {
0342                     PrivateKey k = PrivateKey::fromPEMFile(_entry.keyReference, passphrase, &cresult);
0343                     if (cresult == ConvertGood) {
0344                         _privkey = k;
0345                         ret      = true;
0346                     }
0347                 } break;
0348                 case keyTypePKCS8FileDER:
0349                 {
0350                     QFile file(_entry.keyReference);
0351                     if (file.open(QIODevice::ReadOnly)) {
0352                         const QByteArray contents = file.readAll();
0353 
0354                         PrivateKey k = PrivateKey::fromDER(contents, passphrase, &cresult);
0355                         if (cresult == ConvertGood) {
0356                             _privkey = k;
0357                             ret      = true;
0358                         }
0359                     }
0360                 } break;
0361                 }
0362             }
0363 
0364             if (_entry.unlockTimeout != -1) {
0365                 dueTime = QDateTime::currentDateTime().addSecs(_entry.unlockTimeout);
0366             }
0367 
0368         cleanup1:;
0369         }
0370 
0371         QCA_logTextMessage(QString::asprintf("softstorePKeyBase::_ensureAccess - return ret=%d", ret ? 1 : 0),
0372                            Logger::Debug);
0373 
0374         return ret;
0375     }
0376 };
0377 
0378 class softstorePKeyContext : public PKeyContext
0379 {
0380     Q_OBJECT
0381 
0382 private:
0383     PKeyBase *_k;
0384 
0385 public:
0386     softstorePKeyContext(Provider *p)
0387         : PKeyContext(p)
0388     {
0389         _k = nullptr;
0390     }
0391 
0392     ~softstorePKeyContext() override
0393     {
0394         delete _k;
0395         _k = nullptr;
0396     }
0397 
0398     Provider::Context *clone() const override
0399     {
0400         softstorePKeyContext *c = new softstorePKeyContext(*this);
0401         c->_k                   = (PKeyBase *)_k->clone();
0402         return c;
0403     }
0404 
0405 public:
0406     QList<PKey::Type> supportedTypes() const override
0407     {
0408         QList<PKey::Type> list;
0409         list += static_cast<softstorePKeyBase *>(_k)->_publicKey().type();
0410         return list;
0411     }
0412 
0413     QList<PKey::Type> supportedIOTypes() const override
0414     {
0415         QList<PKey::Type> list;
0416         list += static_cast<softstorePKeyBase *>(_k)->_publicKey().type();
0417         return list;
0418     }
0419 
0420     QList<PBEAlgorithm> supportedPBEAlgorithms() const override
0421     {
0422         QList<PBEAlgorithm> list;
0423         return list;
0424     }
0425 
0426     PKeyBase *key() override
0427     {
0428         return _k;
0429     }
0430 
0431     const PKeyBase *key() const override
0432     {
0433         return _k;
0434     }
0435 
0436     void setKey(PKeyBase *key) override
0437     {
0438         delete _k;
0439         _k = key;
0440     }
0441 
0442     bool importKey(const PKeyBase *key) override
0443     {
0444         Q_UNUSED(key);
0445         return false;
0446     }
0447 
0448     static int passphrase_cb(char *buf, int size, int rwflag, void *u)
0449     {
0450         Q_UNUSED(buf);
0451         Q_UNUSED(size);
0452         Q_UNUSED(rwflag);
0453         Q_UNUSED(u);
0454         return 0;
0455     }
0456 
0457     QByteArray publicToDER() const override
0458     {
0459         return static_cast<softstorePKeyBase *>(_k)->_publicKey().toDER();
0460     }
0461 
0462     QString publicToPEM() const override
0463     {
0464         return static_cast<softstorePKeyBase *>(_k)->_publicKey().toPEM();
0465     }
0466 
0467     ConvertResult publicFromDER(const QByteArray &in) override
0468     {
0469         Q_UNUSED(in);
0470         return ErrorDecode;
0471     }
0472 
0473     ConvertResult publicFromPEM(const QString &s) override
0474     {
0475         Q_UNUSED(s);
0476         return ErrorDecode;
0477     }
0478 
0479     SecureArray privateToDER(const SecureArray &passphrase, PBEAlgorithm pbe) const override
0480     {
0481         Q_UNUSED(passphrase);
0482         Q_UNUSED(pbe);
0483         return SecureArray();
0484     }
0485 
0486     QString privateToPEM(const SecureArray &passphrase, PBEAlgorithm pbe) const override
0487     {
0488         Q_UNUSED(passphrase);
0489         Q_UNUSED(pbe);
0490         return QString();
0491     }
0492 
0493     ConvertResult privateFromDER(const SecureArray &in, const SecureArray &passphrase) override
0494     {
0495         Q_UNUSED(in);
0496         Q_UNUSED(passphrase);
0497         return ErrorDecode;
0498     }
0499 
0500     ConvertResult privateFromPEM(const QString &s, const SecureArray &passphrase) override
0501     {
0502         Q_UNUSED(s);
0503         Q_UNUSED(passphrase);
0504         return ErrorDecode;
0505     }
0506 };
0507 
0508 class softstoreKeyStoreEntryContext : public KeyStoreEntryContext
0509 {
0510     Q_OBJECT
0511 private:
0512     KeyStoreEntry::Type _item_type;
0513     KeyBundle           _key;
0514     SoftStoreEntry      _entry;
0515     QString             _serialized;
0516 
0517 public:
0518     softstoreKeyStoreEntryContext(const KeyBundle      &key,
0519                                   const SoftStoreEntry &entry,
0520                                   const QString        &serialized,
0521                                   Provider             *p)
0522         : KeyStoreEntryContext(p)
0523     {
0524         _item_type  = KeyStoreEntry::TypeKeyBundle;
0525         _key        = key;
0526         _entry      = entry;
0527         _serialized = serialized;
0528     }
0529 
0530     softstoreKeyStoreEntryContext(const softstoreKeyStoreEntryContext &from)
0531         : KeyStoreEntryContext(from)
0532     {
0533         _item_type  = from._item_type;
0534         _key        = from._key;
0535         _entry      = from._entry;
0536         _serialized = from._serialized;
0537     }
0538 
0539     Provider::Context *clone() const override
0540     {
0541         return new softstoreKeyStoreEntryContext(*this);
0542     }
0543 
0544 public:
0545     KeyStoreEntry::Type type() const override
0546     {
0547         return KeyStoreEntry::TypeKeyBundle;
0548     }
0549 
0550     QString name() const override
0551     {
0552         return _entry.name;
0553     }
0554 
0555     QString id() const override
0556     {
0557         return _entry.name;
0558     }
0559 
0560     KeyBundle keyBundle() const override
0561     {
0562         return _key;
0563     }
0564 
0565     Certificate certificate() const override
0566     {
0567         return _entry.chain.primary();
0568     }
0569 
0570     QString storeId() const override
0571     {
0572         return QString::asprintf("%s/%s", "qca-softstore", myPrintable(_entry.name));
0573     }
0574 
0575     QString storeName() const override
0576     {
0577         return _entry.name;
0578     }
0579 
0580     bool ensureAccess() override
0581     {
0582         return static_cast<softstorePKeyBase *>(static_cast<PKeyContext *>(_key.privateKey().context())->key())
0583             ->_ensureAccess();
0584     }
0585 
0586     QString serialize() const override
0587     {
0588         return _serialized;
0589     }
0590 };
0591 
0592 class softstoreKeyStoreListContext : public KeyStoreListContext
0593 {
0594     Q_OBJECT
0595 
0596 private:
0597     int                   _last_id;
0598     QList<SoftStoreEntry> _entries;
0599 
0600 public:
0601     softstoreKeyStoreListContext(Provider *p)
0602         : KeyStoreListContext(p)
0603     {
0604         QCA_logTextMessage(
0605             QString::asprintf("softstoreKeyStoreListContext::softstoreKeyStoreListContext - entry Provider=%p",
0606                               (void *)p),
0607             Logger::Debug);
0608 
0609         _last_id = 0;
0610 
0611         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::softstoreKeyStoreListContext - return"),
0612                            Logger::Debug);
0613     }
0614 
0615     ~softstoreKeyStoreListContext() override
0616     {
0617         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - entry"),
0618                            Logger::Debug);
0619 
0620         s_keyStoreList = nullptr;
0621 
0622         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::~softstoreKeyStoreListContext - return"),
0623                            Logger::Debug);
0624     }
0625 
0626     Provider::Context *clone() const override
0627     {
0628         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::clone - entry/return"), Logger::Debug);
0629         return nullptr;
0630     }
0631 
0632 public:
0633     void start() override
0634     {
0635         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - entry"), Logger::Debug);
0636 
0637         QMetaObject::invokeMethod(this, "doReady", Qt::QueuedConnection);
0638 
0639         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::start - return"), Logger::Debug);
0640     }
0641 
0642     void setUpdatesEnabled(bool enabled) override
0643     {
0644         QCA_logTextMessage(
0645             QString::asprintf("softstoreKeyStoreListContext::setUpdatesEnabled - entry/return enabled=%d",
0646                               enabled ? 1 : 0),
0647             Logger::Debug);
0648     }
0649 
0650     KeyStoreEntryContext *entry(int id, const QString &entryId) override
0651     {
0652         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entry - entry/return id=%d entryId='%s'",
0653                                              id,
0654                                              myPrintable(entryId)),
0655                            Logger::Debug);
0656 
0657         Q_UNUSED(id);
0658         Q_UNUSED(entryId);
0659         return nullptr;
0660     }
0661 
0662     KeyStoreEntryContext *entryPassive(const QString &serialized) override
0663     {
0664         KeyStoreEntryContext *entry = nullptr;
0665 
0666         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryPassive - entry serialized='%s'",
0667                                              myPrintable(serialized)),
0668                            Logger::Debug);
0669 
0670         if (serialized.startsWith(QLatin1String("qca-softstore/"))) {
0671             SoftStoreEntry sentry;
0672 
0673             if (_deserializeSoftStoreEntry(serialized, sentry)) {
0674                 entry = _keyStoreEntryBySoftStoreEntry(sentry);
0675             }
0676         }
0677 
0678         QCA_logTextMessage(
0679             QString::asprintf("softstoreKeyStoreListContext::entryPassive - return entry=%p", (void *)entry),
0680             Logger::Debug);
0681 
0682         return entry;
0683     }
0684 
0685     KeyStore::Type type(int id) const override
0686     {
0687         Q_UNUSED(id);
0688 
0689         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::type - entry/return id=%d", id),
0690                            Logger::Debug);
0691 
0692         return KeyStore::User;
0693     }
0694 
0695     QString storeId(int id) const override
0696     {
0697         QString ret;
0698 
0699         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - entry id=%d", id), Logger::Debug);
0700 
0701         ret = QStringLiteral("qca-softstore");
0702 
0703         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::storeId - return ret=%s", myPrintable(ret)),
0704                            Logger::Debug);
0705 
0706         return ret;
0707     }
0708 
0709     QString name(int id) const override
0710     {
0711         QString ret;
0712 
0713         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - entry id=%d", id), Logger::Debug);
0714 
0715         ret = QStringLiteral("User Software Store");
0716 
0717         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::name - return ret=%s", myPrintable(ret)),
0718                            Logger::Debug);
0719 
0720         return ret;
0721     }
0722 
0723     QList<KeyStoreEntry::Type> entryTypes(int id) const override
0724     {
0725         Q_UNUSED(id);
0726 
0727         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryTypes - entry/return id=%d", id),
0728                            Logger::Debug);
0729 
0730         QList<KeyStoreEntry::Type> list;
0731         list += KeyStoreEntry::TypeKeyBundle;
0732         list += KeyStoreEntry::TypeCertificate;
0733         return list;
0734     }
0735 
0736     QList<int> keyStores() override
0737     {
0738         QList<int> list;
0739 
0740         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::keyStores - entry"), Logger::Debug);
0741 
0742         list += _last_id;
0743 
0744         QCA_logTextMessage(
0745             QString::asprintf("softstoreKeyStoreListContext::keyStores - return out.size()=%d", int(list.size())),
0746             Logger::Debug);
0747 
0748         return list;
0749     }
0750 
0751     QList<KeyStoreEntryContext *> entryList(int id) override
0752     {
0753         QList<KeyStoreEntryContext *> list;
0754 
0755         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::entryList - entry id=%d", id),
0756                            Logger::Debug);
0757 
0758         foreach (const SoftStoreEntry &e, _entries) {
0759             list += _keyStoreEntryBySoftStoreEntry(e);
0760         }
0761 
0762         QCA_logTextMessage(
0763             QString::asprintf("softstoreKeyStoreListContext::entryList - return out.size()=%d", int(list.size())),
0764             Logger::Debug);
0765 
0766         return list;
0767     }
0768 
0769     void _emit_diagnosticText(const QString &t)
0770     {
0771         QCA_logTextMessage(
0772             QString::asprintf("softstoreKeyStoreListContext::_emit_diagnosticText - entry t='%s'", myPrintable(t)),
0773             Logger::Debug);
0774 
0775         QCA_logTextMessage(t, Logger::Warning);
0776 
0777         emit diagnosticText(t);
0778 
0779         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_emit_diagnosticText - return"),
0780                            Logger::Debug);
0781     }
0782 
0783 private Q_SLOTS:
0784     void doReady()
0785     {
0786         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - entry"), Logger::Debug);
0787 
0788         emit busyEnd();
0789 
0790         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doReady - return"), Logger::Debug);
0791     }
0792 
0793     void doUpdated()
0794     {
0795         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - entry"), Logger::Debug);
0796 
0797         emit updated();
0798 
0799         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::doUpdated - return"), Logger::Debug);
0800     }
0801 
0802 public:
0803     void _updateConfig(const QVariantMap &config, const int maxEntries)
0804     {
0805         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - entry"), Logger::Debug);
0806 
0807         QMap<QString, KeyType> keyTypeMap;
0808         keyTypeMap[QStringLiteral("pkcs12")]         = keyTypePKCS12;
0809         keyTypeMap[QStringLiteral("pkcs8")]          = keyTypePKCS8Inline;
0810         keyTypeMap[QStringLiteral("pkcs8-file-pem")] = keyTypePKCS8FilePEM;
0811         keyTypeMap[QStringLiteral("pkcs8-file-der")] = keyTypePKCS8FileDER;
0812 
0813         QMap<QString, PublicType> publicTypeMap;
0814         publicTypeMap[QStringLiteral("x509chain")] = publicTypeX509Chain;
0815 
0816         _last_id++;
0817         _entries.clear();
0818 
0819         for (int i = 0; i < maxEntries; i++) {
0820             if (config[QString::asprintf("entry_%02d_enabled", i)].toBool()) {
0821                 ConvertResult  cresult;
0822                 SoftStoreEntry entry;
0823                 PublicType     publicType = publicTypeInvalid;
0824 
0825                 entry.name                        = config[QString::asprintf("entry_%02d_name", i)].toString();
0826                 const QString stringReferenceType = config[QString::asprintf("entry_%02d_private_type", i)].toString();
0827                 const QString stringPublicType    = config[QString::asprintf("entry_%02d_public_type", i)].toString();
0828                 entry.noPassphrase                = config[QString::asprintf("entry_%02d_no_passphrase", i)].toBool();
0829                 entry.unlockTimeout               = config[QString::asprintf("entry_%02d_unlock_timeout", i)].toInt();
0830 
0831                 if (publicTypeMap.contains(stringPublicType)) {
0832                     publicType = publicTypeMap[stringPublicType];
0833                 } else {
0834                     _emit_diagnosticText(QString::asprintf("Software Store: Bad public key type of '%s' entry.\n",
0835                                                            myPrintable(entry.name)));
0836                     goto cleanup1;
0837                 }
0838 
0839                 if (keyTypeMap.contains(stringReferenceType)) {
0840                     entry.keyReferenceType = keyTypeMap[stringReferenceType];
0841                 } else {
0842                     _emit_diagnosticText(QString::asprintf("Software Store: Bad private key type of '%s' entry.\n",
0843                                                            myPrintable(entry.name)));
0844                     goto cleanup1;
0845                 }
0846 
0847                 entry.keyReference = config[QString::asprintf("entry_%02d_private", i)].toString();
0848 
0849                 switch (publicType) {
0850                 case publicTypeInvalid:
0851                     goto cleanup1;
0852                     break;
0853                 case publicTypeX509Chain:
0854                     const QStringList base64certs =
0855                         config[QString::asprintf("entry_%02d_public", i)].toString().split(QStringLiteral("!"));
0856 
0857                     foreach (const QString &s, base64certs) {
0858                         entry.chain += Certificate::fromDER(Base64().stringToArray(s).toByteArray(), &cresult);
0859                     }
0860 
0861                     if (cresult != ConvertGood) {
0862                         _emit_diagnosticText(QString::asprintf(
0863                             "Software Store: Cannot load certificate of '%s' entry.\n", myPrintable(entry.name)));
0864                         goto cleanup1;
0865                     }
0866                     break;
0867                 }
0868 
0869                 _entries += entry;
0870 
0871             cleanup1:; // nothing to do for this entry.
0872             }
0873         }
0874 
0875         QMetaObject::invokeMethod(s_keyStoreList, "doUpdated", Qt::QueuedConnection);
0876 
0877         QCA_logTextMessage(QStringLiteral("softstoreKeyStoreListContext::_updateConfig - return"), Logger::Debug);
0878     }
0879 
0880 private:
0881     QString _serializeSoftStoreEntry(const SoftStoreEntry &entry) const
0882     {
0883         QString serialized;
0884 
0885         QCA_logTextMessage(QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - entry name=%s",
0886                                              myPrintable(entry.name)),
0887                            Logger::Debug);
0888 
0889         serialized = QString::asprintf("qca-softstore/0/%s/%d/%s/%d/%d/x509chain/",
0890                                        myPrintable(_escapeString(entry.name)),
0891                                        entry.keyReferenceType,
0892                                        myPrintable(_escapeString(entry.keyReference)),
0893                                        entry.noPassphrase ? 1 : 0,
0894                                        entry.unlockTimeout);
0895 
0896         QStringList list;
0897         foreach (const Certificate &i, entry.chain) {
0898             list += _escapeString(Base64().arrayToString(i.toDER()));
0899         }
0900 
0901         serialized.append(list.join(QStringLiteral("/")));
0902 
0903         QCA_logTextMessage(
0904             QString::asprintf("softstoreKeyStoreListContext::_serializeSoftStoreEntry - return serialized='%s'",
0905                               myPrintable(serialized)),
0906             Logger::Debug);
0907 
0908         return serialized;
0909     }
0910 
0911     bool _deserializeSoftStoreEntry(const QString &serialized, SoftStoreEntry &entry) const
0912     {
0913         bool ret = false;
0914 
0915         QCA_logTextMessage(
0916             QString::asprintf("softstoreKeyStoreListContext::_deserializeSoftStoreEntry - entry from='%s'",
0917                               myPrintable(serialized)),
0918             Logger::Debug);
0919 
0920         entry = SoftStoreEntry();
0921 
0922         const QStringList list = serialized.split(QStringLiteral("/"));
0923         int               n    = 0;
0924 
0925         if (list.size() < 8) {
0926             goto cleanup;
0927         }
0928 
0929         if (list[n++] != QLatin1String("qca-softstore")) {
0930             goto cleanup;
0931         }
0932 
0933         if (list[n++].toInt() != 0) {
0934             goto cleanup;
0935         }
0936 
0937         entry.name             = _unescapeString(list[n++]);
0938         entry.keyReferenceType = (KeyType)list[n++].toInt();
0939         entry.keyReference     = _unescapeString(list[n++]);
0940         entry.noPassphrase     = list[n++].toInt() != 0;
0941         entry.unlockTimeout    = list[n++].toInt();
0942         n++; // skip public key for now.
0943 
0944         while (n < list.size()) {
0945             Certificate cert = Certificate::fromDER(Base64().stringToArray(_unescapeString(list[n++])).toByteArray());
0946             if (cert.isNull()) {
0947                 goto cleanup;
0948             }
0949             entry.chain += cert;
0950         }
0951 
0952         ret = true;
0953 
0954     cleanup:
0955 
0956         QCA_logTextMessage(
0957             QString::asprintf(
0958                 "softstoreKeyStoreListContext::_deserializeSoftStoreEntry - return ret=%d chain.size()=%d",
0959                 ret ? 1 : 0,
0960                 int(entry.chain.size())),
0961             Logger::Debug);
0962 
0963         return ret;
0964     }
0965 
0966     softstoreKeyStoreEntryContext *_keyStoreEntryBySoftStoreEntry(const SoftStoreEntry &sentry) const
0967     {
0968         softstoreKeyStoreEntryContext *entry = nullptr;
0969 
0970         QCA_logTextMessage(
0971             QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - entry name=%s",
0972                               myPrintable(sentry.name)),
0973             Logger::Debug);
0974 
0975         QString serialized = _serializeSoftStoreEntry(sentry);
0976 
0977         softstorePKeyBase *pkey = new softstorePKeyBase(sentry, serialized, provider());
0978 
0979         softstorePKeyContext *pkc = new softstorePKeyContext(provider());
0980         pkc->setKey(pkey);
0981         PrivateKey privkey;
0982         privkey.change(pkc);
0983         KeyBundle key;
0984         key.setCertificateChainAndKey(sentry.chain, privkey);
0985 
0986         entry = new softstoreKeyStoreEntryContext(key, sentry, serialized, provider());
0987 
0988         QCA_logTextMessage(
0989             QString::asprintf("softstoreKeyStoreListContext::_keyStoreEntryBySoftStoreEntry - return entry=%p",
0990                               (void *)entry),
0991             Logger::Debug);
0992 
0993         return entry;
0994     }
0995 
0996     QString _escapeString(const QString &from) const
0997     {
0998         QString to;
0999 
1000         foreach (const QChar &c, from) {
1001             if (c == QLatin1Char('/') || c == QLatin1Char('\\')) {
1002                 to += QString::asprintf("\\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(i + 2, 4).toInt(nullptr, 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 
1036 using namespace softstoreQCAPlugin;
1037 
1038 class softstoreProvider : public Provider
1039 {
1040 private:
1041     static const int _CONFIG_MAX_ENTRIES;
1042 
1043     QVariantMap _config;
1044 
1045 public:
1046     softstoreProvider()
1047     {
1048     }
1049 
1050     ~softstoreProvider() override
1051     {
1052     }
1053 
1054 public:
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_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("entry_%02d_enabled", i)]        = false;
1109             mytemplate[QString::asprintf("entry_%02d_name", i)]           = QLatin1String("");
1110             mytemplate[QString::asprintf("entry_%02d_public_type", i)]    = QLatin1String("");
1111             mytemplate[QString::asprintf("entry_%02d_private_type", i)]   = QLatin1String("");
1112             mytemplate[QString::asprintf("entry_%02d_public", i)]         = QLatin1String("");
1113             mytemplate[QString::asprintf("entry_%02d_private", i)]        = QLatin1String("");
1114             mytemplate[QString::asprintf("entry_%02d_unlock_timeout", i)] = -1;
1115             mytemplate[QString::asprintf("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_MAX_ENTRIES);
1129         }
1130 
1131         QCA_logTextMessage(QStringLiteral("softstoreProvider::configChanged - return"), Logger::Debug);
1132     }
1133 };
1134 
1135 const int softstoreProvider::_CONFIG_MAX_ENTRIES = 50;
1136 
1137 class 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 
1143 public:
1144     Provider *createProvider() override
1145     {
1146         return new softstoreProvider;
1147     }
1148 };
1149 
1150 #include "qca-softstore.moc"