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

0001 /*
0002  * Copyright (C) 2007  Justin Karneges <justin@affinix.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 WITHOUT ANY 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 <QtCore>
0021 #include <QtCrypto>
0022 
0023 using namespace QCA;
0024 
0025 static char cert_pem[] =
0026     "-----BEGIN CERTIFICATE-----\n"
0027     "MIIBsTCCAVugAwIBAgIBADANBgkqhkiG9w0BAQUFADA4MRQwEgYDVQQDEwtUZXN0\n"
0028     "IENlcnQgMTELMAkGA1UEBhMCVVMxEzARBgNVBAoTClRlc3QgT3JnIDEwHhcNMDcw\n"
0029     "NjE5MjAzOTI4WhcNMTIwNjE5MjAzOTI4WjA4MRQwEgYDVQQDEwtUZXN0IENlcnQg\n"
0030     "MTELMAkGA1UEBhMCVVMxEzARBgNVBAoTClRlc3QgT3JnIDEwXDANBgkqhkiG9w0B\n"
0031     "AQEFAANLADBIAkEA3645RS/xBlWnjju6moaRYQuIDo7fwM+GxhE91HECLAg3Hnkr\n"
0032     "I+qx96VXd006olOn8MrkbjSqcTJ4LcDaCGI1YwIDAQABo1AwTjAdBgNVHQ4EFgQU\n"
0033     "nm5lNkkblHdoB0gLeh8mB6Ed+TMwDwYDVR0TAQH/BAUwAwIBADAcBgNVHREEFTAT\n"
0034     "gRF0ZXN0MUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQUFAANBAFTtXtwfYcJZBsXJ\n"
0035     "+Ckm9qbg7qR/XRERDzeR0yhHZE7F/jU5YQv7+iJL4l95iH9PkZNOk15Tu/Kzzekx\n"
0036     "6CTXzKA=\n"
0037     "-----END CERTIFICATE-----";
0038 
0039 static char key_n_dec[] =
0040     "1171510158037441543813157379806833168225785177834459013412026750"
0041     "9262193808059395366696241600386200064326196137137376912654785051"
0042     "560621331316573341676090723";
0043 
0044 static char key_e_dec[] = "65537";
0045 
0046 //----------------------------------------------------------------------------
0047 // TestProvider
0048 //----------------------------------------------------------------------------
0049 class TestProvider : public Provider
0050 {
0051 public:
0052     TestProvider()
0053     {
0054         appendPluginDiagnosticText("TestProvider constructed\n");
0055     }
0056 
0057     void init()
0058     {
0059         appendPluginDiagnosticText("TestProvider initialized\n");
0060     }
0061 
0062     void deinit()
0063     {
0064         appendPluginDiagnosticText("TestProvider deinitialized\n");
0065     }
0066 
0067     ~TestProvider()
0068     {
0069         appendPluginDiagnosticText("TestProvider destructed\n");
0070     }
0071 
0072     int version() const
0073     {
0074         return 0x010203; // 1.2.3
0075     }
0076 
0077     int qcaVersion() const
0078     {
0079         return QCA_VERSION;
0080     }
0081 
0082     QString name() const
0083     {
0084         return "qca-test";
0085     }
0086 
0087     QStringList features() const
0088     {
0089         QStringList list;
0090         list += "keystorelist";
0091         return list;
0092     }
0093 
0094     Context *createContext(const QString &type);
0095 };
0096 
0097 //----------------------------------------------------------------------------
0098 // TestData
0099 //----------------------------------------------------------------------------
0100 class TestKeyStore
0101 {
0102 public:
0103     int            contextId;
0104     KeyStore::Type type;
0105     QString        storeId;
0106     QString        name;
0107     bool           readOnly;
0108     bool           avail; // for simplicity, all items share this global toggle
0109 
0110     QList<KeyBundle> certs;
0111 
0112     TestKeyStore()
0113         : contextId(-1)
0114         , type(KeyStore::SmartCard)
0115         , readOnly(true)
0116         , avail(true)
0117     {
0118     }
0119 };
0120 
0121 class TestData
0122 {
0123 public:
0124     int                 context_at;
0125     QList<TestKeyStore> stores;
0126 
0127     TestData()
0128         : context_at(0)
0129     {
0130     }
0131 };
0132 
0133 //----------------------------------------------------------------------------
0134 // TestRSAContext
0135 //----------------------------------------------------------------------------
0136 static KeyStoreEntry make_entry(Provider *p, TestKeyStore *store);
0137 
0138 class TestRSAContext : public RSAContext
0139 {
0140     Q_OBJECT
0141 public:
0142     bool          priv;
0143     TestKeyStore *store;
0144 
0145     TestRSAContext(Provider *p)
0146         : RSAContext(p)
0147         , priv(true)
0148         , store(0)
0149     {
0150     }
0151 
0152     TestRSAContext(const TestRSAContext &from)
0153         : RSAContext(from)
0154         , priv(from.priv)
0155         , store(from.store)
0156     {
0157     }
0158 
0159     Context *clone() const
0160     {
0161         return new TestRSAContext(*this);
0162     }
0163 
0164     virtual bool isNull() const
0165     {
0166         return false;
0167     }
0168 
0169     virtual PKey::Type type() const
0170     {
0171         return PKey::RSA;
0172     }
0173 
0174     virtual bool isPrivate() const
0175     {
0176         return priv;
0177     }
0178 
0179     virtual bool canExport() const
0180     {
0181         return false;
0182     }
0183 
0184     virtual void convertToPublic()
0185     {
0186         priv = false;
0187     }
0188 
0189     virtual int bits() const
0190     {
0191         return 2048;
0192     }
0193 
0194     virtual void startSign(SignatureAlgorithm alg, SignatureFormat format)
0195     {
0196         Q_UNUSED(alg);
0197         Q_UNUSED(format);
0198     }
0199 
0200     virtual void update(const MemoryRegion &in)
0201     {
0202         Q_UNUSED(in);
0203     }
0204 
0205     virtual QByteArray endSign()
0206     {
0207         if (!store)
0208             return QByteArray();
0209 
0210         while (store->contextId == -1 || !store->avail) {
0211             KeyStoreInfo  info(store->type, store->storeId, store->name);
0212             KeyStoreEntry entry = make_entry(provider(), store);
0213 
0214             TokenAsker asker;
0215             asker.ask(info, entry, 0);
0216             asker.waitForResponse();
0217             if (!asker.accepted())
0218                 return QByteArray();
0219         }
0220 
0221         return "foobar";
0222     }
0223 
0224     virtual void createPrivate(int bits, int exp, bool block)
0225     {
0226         Q_UNUSED(bits);
0227         Q_UNUSED(exp);
0228         Q_UNUSED(block);
0229     }
0230 
0231     virtual void createPrivate(const BigInteger &n,
0232                                const BigInteger &e,
0233                                const BigInteger &p,
0234                                const BigInteger &q,
0235                                const BigInteger &d)
0236     {
0237         Q_UNUSED(n);
0238         Q_UNUSED(e);
0239         Q_UNUSED(p);
0240         Q_UNUSED(q);
0241         Q_UNUSED(d);
0242     }
0243 
0244     virtual void createPublic(const BigInteger &n, const BigInteger &e)
0245     {
0246         Q_UNUSED(n);
0247         Q_UNUSED(e);
0248     }
0249 
0250     virtual BigInteger n() const
0251     {
0252         return BigInteger(QString(key_n_dec));
0253     }
0254 
0255     virtual BigInteger e() const
0256     {
0257         return BigInteger(QString(key_e_dec));
0258     }
0259 
0260     virtual BigInteger p() const
0261     {
0262         return BigInteger();
0263     }
0264 
0265     virtual BigInteger q() const
0266     {
0267         return BigInteger();
0268     }
0269 
0270     virtual BigInteger d() const
0271     {
0272         return BigInteger();
0273     }
0274 };
0275 
0276 //----------------------------------------------------------------------------
0277 // TestPKeyContext
0278 //----------------------------------------------------------------------------
0279 class TestPKeyContext : public PKeyContext
0280 {
0281     Q_OBJECT
0282 public:
0283     TestRSAContext *_key;
0284 
0285     TestPKeyContext(Provider *p)
0286         : PKeyContext(p)
0287         , _key(0)
0288     {
0289     }
0290 
0291     TestPKeyContext(const TestPKeyContext &from)
0292         : PKeyContext(from)
0293         , _key(0)
0294     {
0295         if (from._key)
0296             _key = (TestRSAContext *)from._key->clone();
0297     }
0298 
0299     ~TestPKeyContext()
0300     {
0301         delete _key;
0302     }
0303 
0304     Context *clone() const
0305     {
0306         return new TestPKeyContext(*this);
0307     }
0308 
0309     virtual QList<PKey::Type> supportedTypes() const
0310     {
0311         QList<PKey::Type> list;
0312         list += PKey::RSA;
0313         return list;
0314     }
0315 
0316     virtual QList<PKey::Type> supportedIOTypes() const
0317     {
0318         return QList<PKey::Type>();
0319     }
0320 
0321     virtual QList<PBEAlgorithm> supportedPBEAlgorithms() const
0322     {
0323         return QList<PBEAlgorithm>();
0324     }
0325 
0326     virtual PKeyBase *key()
0327     {
0328         return _key;
0329     }
0330 
0331     virtual const PKeyBase *key() const
0332     {
0333         return _key;
0334     }
0335 
0336     virtual void setKey(PKeyBase *key)
0337     {
0338         delete _key;
0339         _key = (TestRSAContext *)key;
0340     }
0341 
0342     virtual bool importKey(const PKeyBase *key)
0343     {
0344         Q_UNUSED(key);
0345         return false;
0346     }
0347 };
0348 
0349 //----------------------------------------------------------------------------
0350 // TestCertContext
0351 //----------------------------------------------------------------------------
0352 class TestCertContext : public CertContext
0353 {
0354     Q_OBJECT
0355 public:
0356     CertContextProps _props;
0357 
0358     TestCertContext(Provider *p)
0359         : CertContext(p)
0360     {
0361     }
0362 
0363     Context *clone() const
0364     {
0365         return new TestCertContext(*this);
0366     }
0367 
0368     virtual QByteArray toDER() const
0369     {
0370         QStringList lines = toPEM().split('\n');
0371         lines.removeFirst();
0372         lines.removeLast();
0373         QString enc = lines.join("");
0374         return Base64().stringToArray(enc).toByteArray();
0375     }
0376 
0377     virtual QString toPEM() const
0378     {
0379         return QString(cert_pem);
0380     }
0381 
0382     virtual ConvertResult fromDER(const QByteArray &a)
0383     {
0384         Q_UNUSED(a);
0385         return ErrorDecode;
0386     }
0387 
0388     virtual ConvertResult fromPEM(const QString &s)
0389     {
0390         Q_UNUSED(s);
0391         return ErrorDecode;
0392     }
0393 
0394     virtual bool createSelfSigned(const CertificateOptions &opts, const PKeyContext &priv)
0395     {
0396         Q_UNUSED(opts);
0397         Q_UNUSED(priv);
0398         return false;
0399     }
0400 
0401     virtual const CertContextProps *props() const
0402     {
0403         return &_props;
0404     }
0405 
0406     virtual bool compare(const CertContext *other) const
0407     {
0408         Q_UNUSED(other);
0409         return false;
0410     }
0411 
0412     virtual PKeyContext *subjectPublicKey() const
0413     {
0414         TestRSAContext *rsa1 = new TestRSAContext(provider());
0415         rsa1->priv           = false;
0416         TestPKeyContext *kc1 = new TestPKeyContext(provider());
0417         kc1->setKey(rsa1);
0418         return kc1;
0419     }
0420 
0421     virtual bool isIssuerOf(const CertContext *other) const
0422     {
0423         Q_UNUSED(other);
0424         return false;
0425     }
0426 
0427     virtual Validity validate(const QList<CertContext *> &trusted,
0428                               const QList<CertContext *> &untrusted,
0429                               const QList<CRLContext *>  &crls,
0430                               UsageMode                   u,
0431                               ValidateFlags               vf) const
0432     {
0433         Q_UNUSED(trusted);
0434         Q_UNUSED(untrusted);
0435         Q_UNUSED(crls);
0436         Q_UNUSED(u);
0437         Q_UNUSED(vf);
0438         return ErrorValidityUnknown;
0439     }
0440 
0441     virtual Validity validate_chain(const QList<CertContext *> &chain,
0442                                     const QList<CertContext *> &trusted,
0443                                     const QList<CRLContext *>  &crls,
0444                                     UsageMode                   u,
0445                                     ValidateFlags               vf) const
0446     {
0447         Q_UNUSED(chain);
0448         Q_UNUSED(trusted);
0449         Q_UNUSED(crls);
0450         Q_UNUSED(u);
0451         Q_UNUSED(vf);
0452         return ErrorValidityUnknown;
0453     }
0454 };
0455 
0456 //----------------------------------------------------------------------------
0457 // TestKeyStoreEntryContext
0458 //----------------------------------------------------------------------------
0459 class TestKeyStoreEntryContext : public KeyStoreEntryContext
0460 {
0461     Q_OBJECT
0462 public:
0463     QString       _id, _name, _storeId, _storeName;
0464     KeyBundle     kb;
0465     TestKeyStore *store;
0466 
0467     TestKeyStoreEntryContext(Provider *p)
0468         : KeyStoreEntryContext(p)
0469     {
0470     }
0471 
0472     virtual Context *clone() const
0473     {
0474         return new TestKeyStoreEntryContext(*this);
0475     }
0476 
0477     virtual KeyStoreEntry::Type type() const
0478     {
0479         return KeyStoreEntry::TypeKeyBundle;
0480     }
0481 
0482     virtual QString id() const
0483     {
0484         return _id;
0485     }
0486 
0487     virtual QString name() const
0488     {
0489         return _name;
0490     }
0491 
0492     virtual QString storeId() const
0493     {
0494         return _storeId;
0495     }
0496 
0497     virtual QString storeName() const
0498     {
0499         return _storeName;
0500     }
0501 
0502     virtual bool isAvailable() const
0503     {
0504         return store->avail;
0505     }
0506 
0507     virtual QString serialize() const
0508     {
0509         return QString("qca-test-1/fake_serialized");
0510     }
0511 
0512     virtual KeyBundle keyBundle() const
0513     {
0514         return kb;
0515     }
0516 
0517     virtual bool ensureAccess()
0518     {
0519         return true;
0520     }
0521 };
0522 
0523 KeyStoreEntry make_entry(Provider *p, TestKeyStore *store)
0524 {
0525     KeyStoreEntry             entry;
0526     TestKeyStoreEntryContext *kse = new TestKeyStoreEntryContext(p);
0527     kse->_id                      = QString::number(0);
0528     kse->_name                    = store->certs[0].certificateChain().primary().commonName();
0529     kse->_storeId                 = store->storeId;
0530     kse->_storeName               = store->name;
0531     kse->kb                       = store->certs[0];
0532     kse->store                    = store;
0533     entry.change(kse);
0534     return entry;
0535 }
0536 
0537 //----------------------------------------------------------------------------
0538 // TestKeyStoreListContext
0539 //----------------------------------------------------------------------------
0540 class TestKeyStoreListContext : public KeyStoreListContext
0541 {
0542     Q_OBJECT
0543 public:
0544     TestData data;
0545     int      step;
0546     QTimer   t;
0547     bool     first;
0548     int      next_id;
0549 
0550     TestKeyStoreListContext(Provider *p)
0551         : KeyStoreListContext(p)
0552         , t(this)
0553     {
0554         step    = 0;
0555         next_id = 1;
0556 
0557         KeyBundle        cert1;
0558         Certificate      pub1;
0559         TestCertContext *cc1 = new TestCertContext(provider());
0560         cc1->_props.subject += CertificateInfoPair(CertificateInfoType(CommonName), "Test Cert 1");
0561         pub1.change(cc1);
0562         PrivateKey       sec1;
0563         TestRSAContext  *rsa1 = new TestRSAContext(provider());
0564         TestPKeyContext *kc1  = new TestPKeyContext(provider());
0565         kc1->setKey(rsa1);
0566         sec1.change(kc1);
0567         cert1.setCertificateChainAndKey(pub1, sec1);
0568 
0569         TestKeyStore ks1;
0570         ks1.storeId = "store1";
0571         ks1.name    = "Test Store 1";
0572         ks1.certs += cert1;
0573         ks1.avail = false;
0574         data.stores += ks1;
0575 
0576         TestKeyStore ks2;
0577         ks2.storeId  = "store2";
0578         ks2.name     = "Test Store 2";
0579         ks2.readOnly = false;
0580         data.stores += ks2;
0581 
0582         rsa1->store = &data.stores[0];
0583 
0584         connect(&t, SIGNAL(timeout()), SLOT(do_step()));
0585     }
0586 
0587     int findStore(int contextId) const
0588     {
0589         for (int n = 0; n < data.stores.count(); ++n) {
0590             if (data.stores[n].contextId == contextId)
0591                 return n;
0592         }
0593         return -1;
0594     }
0595 
0596     virtual Context *clone() const
0597     {
0598         return 0;
0599     }
0600 
0601     virtual void start()
0602     {
0603         first = true;
0604         emit diagnosticText("qca-test: TestKeyStoreListContext started\n");
0605         t.start(2000);
0606     }
0607 
0608     virtual void setUpdatesEnabled(bool enabled)
0609     {
0610         Q_UNUSED(enabled);
0611     }
0612 
0613     virtual QList<int> keyStores()
0614     {
0615         QList<int> list;
0616         for (int n = 0; n < data.stores.count(); ++n) {
0617             int id = data.stores[n].contextId;
0618             if (id != -1)
0619                 list += id;
0620         }
0621         return list;
0622     }
0623 
0624     virtual KeyStore::Type type(int id) const
0625     {
0626         int at = findStore(id);
0627         if (at == -1)
0628             return KeyStore::SmartCard;
0629         return data.stores[at].type;
0630     }
0631 
0632     virtual QString storeId(int id) const
0633     {
0634         int at = findStore(id);
0635         if (at == -1)
0636             return QString();
0637         return data.stores[at].storeId;
0638     }
0639 
0640     virtual QString name(int id) const
0641     {
0642         int at = findStore(id);
0643         if (at == -1)
0644             return QString();
0645         return data.stores[at].name;
0646     }
0647 
0648     virtual bool isReadOnly(int id) const
0649     {
0650         int at = findStore(id);
0651         if (at == -1)
0652             return true;
0653         return data.stores[at].readOnly;
0654     }
0655 
0656     virtual QList<KeyStoreEntry::Type> entryTypes(int id) const
0657     {
0658         Q_UNUSED(id);
0659         QList<KeyStoreEntry::Type> list;
0660         list += KeyStoreEntry::TypeKeyBundle;
0661         return list;
0662     }
0663 
0664     virtual QList<KeyStoreEntryContext *> entryList(int id)
0665     {
0666         QList<KeyStoreEntryContext *> out;
0667         int                           at = findStore(id);
0668         if (at == -1)
0669             return out;
0670         TestKeyStore &store = data.stores[at];
0671         for (int n = 0; n < store.certs.count(); ++n) {
0672             TestKeyStoreEntryContext *kse = new TestKeyStoreEntryContext(provider());
0673             kse->_id                      = QString::number(n);
0674             kse->_name                    = store.certs[n].certificateChain().primary().commonName();
0675             kse->_storeId                 = store.storeId;
0676             kse->_storeName               = store.name;
0677             kse->kb                       = store.certs[n];
0678             kse->store                    = &store;
0679             out += kse;
0680         }
0681         return out;
0682     }
0683 
0684     virtual KeyStoreEntryContext *entryPassive(const QString &serialized)
0685     {
0686         if (serialized == "qca-test-1/fake_serialized") {
0687             TestKeyStore             &store = data.stores[0];
0688             TestKeyStoreEntryContext *kse   = new TestKeyStoreEntryContext(provider());
0689             kse->_id                        = QString::number(0);
0690             kse->_name                      = store.certs[0].certificateChain().primary().commonName();
0691             kse->_storeId                   = store.storeId;
0692             kse->_storeName                 = store.name;
0693             kse->kb                         = store.certs[0];
0694             kse->store                      = &store;
0695             return kse;
0696         } else
0697             return 0;
0698     }
0699 
0700     virtual QString writeEntry(int id, const KeyBundle &kb)
0701     {
0702         int at = findStore(id);
0703         if (at == -1)
0704             return QString();
0705         if (data.stores[at].readOnly)
0706             return QString();
0707         data.stores[at].certs += kb;
0708         return QString::number(data.stores[at].certs.count() - 1);
0709     }
0710 
0711     virtual bool removeEntry(int id, const QString &entryId)
0712     {
0713         int at = findStore(id);
0714         if (at == -1)
0715             return false;
0716         if (data.stores[at].readOnly)
0717             return false;
0718         int index = entryId.toInt();
0719         if (index < 0 || index >= data.stores[at].certs.count())
0720             return false;
0721         data.stores[at].certs.removeAt(index);
0722         return true;
0723     }
0724 
0725 private Q_SLOTS:
0726     void do_step()
0727     {
0728         emit diagnosticText(QString("qca-test: TestKeyStoreListContext do_step %1\n").arg(step));
0729 
0730         if (step == 0) {
0731             // make first store available
0732             data.stores[0].contextId = next_id++;
0733             if (first) {
0734                 first = false;
0735                 emit busyEnd();
0736             } else
0737                 emit updated();
0738         } else if (step == 1) {
0739             // make second store available
0740             data.stores[1].contextId = next_id++;
0741             emit updated();
0742         } else if (step == 2) {
0743             // make items in the first store available
0744             data.stores[0].avail = true;
0745             emit storeUpdated(data.stores[0].contextId);
0746         } else if (step == 3) {
0747             // make the first store unavailable
0748             data.stores[0].contextId = -1;
0749             emit updated();
0750         } else if (step == 4) {
0751             // make the first store available
0752             data.stores[0].contextId = next_id++;
0753             emit updated();
0754         } else if (step == 5) {
0755             // make the second store unavailable
0756             data.stores[1].contextId = -1;
0757             emit updated();
0758         } else if (step == 6) {
0759             // make the first store unavailable
0760             data.stores[0].contextId = -1;
0761             emit updated();
0762         } else if (step == 7) {
0763             // do it all over again in 10 seconds
0764             // (2 seconds before, 6 seconds here, 2 seconds after)
0765             t.start(6000);
0766         } else {
0767             step                 = 0;
0768             data.stores[0].avail = false;
0769 
0770             // set interval to 2 seconds
0771             t.start(2000);
0772             return;
0773         }
0774 
0775         ++step;
0776     }
0777 };
0778 
0779 //----------------------------------------------------------------------------
0780 // TestProvider
0781 //----------------------------------------------------------------------------
0782 Provider::Context *TestProvider::createContext(const QString &type)
0783 {
0784     if (type == "keystorelist")
0785         return new TestKeyStoreListContext(this);
0786     else
0787         return 0;
0788 }
0789 
0790 //----------------------------------------------------------------------------
0791 // TestPlugin
0792 //----------------------------------------------------------------------------
0793 class TestPlugin : public QObject, public QCAPlugin
0794 {
0795     Q_OBJECT
0796     Q_PLUGIN_METADATA(IID "com.affinix.qca.Plugin/1.0")
0797     Q_INTERFACES(QCAPlugin)
0798 public:
0799     virtual Provider *createProvider()
0800     {
0801         return new TestProvider;
0802     }
0803 };
0804 
0805 #include "qca-test.moc"