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"