#ifndef SMARTCARDAUTH_H #define SMARTCARDAUTH_H #include #include #include #include #include #include #include #include #include #include #include #include namespace qbrowserlib { class CryptokiEngine: public QObject, public openssl::Engine { Q_OBJECT; Q_SIGNALS: void certRequired(); public: CryptokiEngine() { TRC; } operator bool() { TRC; LOG<<"Status of CryptokiEngine: " <<(_privateKey.get() ?"privateKey defined, ":"privateKey undefined"); return _privateKey.get(); } void cert(cryptoki::Object& privateKey, const std::string& certVal) { TRC; _privateKey = std::auto_ptr (new cryptoki::Object(privateKey)); try { // new QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); QSslCertificate localcert(QByteArray(certVal.data(), certVal.size()), QSsl::Der); sslConfig.setLocalCertificate(localcert); //RSA_set_default_method(ENGINE_get_RSA(_e)); QByteArray pem // empty dummy key for qt object instantiation ("-----BEGIN RSA PRIVATE KEY-----\n" "MIIBOwIBAAJBAMH2yqAGeVNPdgeZ2GoHo31m9aUxZ7QfK2Go2qLTahLpQ3UL1C8G\n" "LkuMS8SNK0ZGfRMalIpIhv6bW5l3kjogOncCAwEAAQJABVGECtFCoGMsZFb2lSmy\n" "dOzOzYHGSy0TnnDn1dEgNnZ8sIljElPtUzm9dyXs2P3ICL1sOd7qjpzfJeyxknDL\n" "AQIhAO5iKdLmhyuW+EDEH19vDs1Pmqs3/ZnT5UgUiJnTJqz3AiEA0ExIfUOCnxq2\n" "a3Z46KEivcr8JB2P9VqouBbVryiq/oECIQDj8bPCejMoiEzMSX0iWWTTB9qC/KAg\n" "FtF4skHIrXKfEwIgPCs86Uo+Ch2aQjKHvJMHSRHAgeI0OmiEwiB+e0lhE4ECIQDd\n" "IbUmHIXt6oHLJmoGFX46bCcfil5eE5FXfiaw7Q9iPw==\n" "-----END RSA PRIVATE KEY-----\n"); QSslKey privkey(pem, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); RSA* rsa((RSA*)privkey.handle()); if (!ENGINE_init(_e)) return; rsa->engine=_e; rsa->meth=ENGINE_get_RSA(_e); if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_RSA, rsa, &rsa->ex_data)) { ENGINE_finish(_e); return; } set(rsa->n, privateKey, CKA_MODULUS, "CKA_MODULUS"); set(rsa->e, privateKey, CKA_PUBLIC_EXPONENT, "CKA_PUBLIC_EXPONENT"); set(rsa->d, privateKey, CKA_PRIVATE_EXPONENT, "CKA_PRIVATE_EXPONENT"); set(rsa->p, privateKey, CKA_PRIME_1, "CKA_PRIME_1"); set(rsa->q, privateKey, CKA_PRIME_2, "CKA_PRIME_2"); set(rsa->dmp1, privateKey, CKA_EXPONENT_1, "CKA_EXPONENT_1"); set(rsa->dmq1, privateKey, CKA_EXPONENT_2, "CKA_EXPONENT_2"); set(rsa->iqmp, privateKey, CKA_COEFFICIENT, "CKA_COEFFICIENT"); rsa->flags |= RSA_FLAG_SIGN_VER; // don't emulate with encrypt/decrypt assert(!privkey.isNull()); LOG<<"Setup RSA finished"; sslConfig.setPrivateKey(privkey); QSslConfiguration::setDefaultConfiguration(sslConfig); } catch (const std::exception& e) { LOG<<"SETUP ERROR: "<sign(in, algo); } catch (const std::exception& x) { LOG<<"signature failed, reason: "<sign(in, algo); // try again } } catch (const std::exception& x) { TRC; LOG<<"rsaSign failed, reason: "< _privateKey; }; class SmartCardAuth: public QObject { Q_OBJECT; public: SmartCardAuth(suisseid::Cards cards, QWidget* p=0, bool loginAtStart=true): _parent(p), _e(new CryptokiEngine()), _reg(_e), _cards(cards) { TRC; if (loginAtStart) login(); assert(connect(_e, SIGNAL(certRequired()), SLOT(login()))); } public Q_SLOTS: void login(bool force=true) { TRC; Lock lock; LOG<<"got lock"; if (!_e || (!force && *_e)) return; // no smartcard or already logged in LOG<<"get new certificate"; try { for (suisseid::Cards::iterator card(_cards.begin()); card!=_cards.end(); ++card) { suisseid::Certificate cert((*card)->authenticationCertificate()); PinEntry pinEntry(QSslCertificate(QByteArray(cert.data(), cert.size()), QSsl::Der), _parent); while (true) try { if (pinEntry .tokeninfo((*card)->minimalPinLength(), (*card)->maximalPinLength()) .retries((*card)->pkcs15PinRetries()) .myexec() !=PinEntry::Accepted) return; _session = // session login with pin std::shared_ptr (new cryptoki::Session((*card)->session())); _session->login(pinEntry.pin().toStdString()); cryptoki::ObjectList keys (_session->find(cryptoki::Attribute(CKA_CLASS) .from(CKO_PRIVATE_KEY), cert.id())); if (keys.size()==1) { _e->cert(keys[0], cert); // install client cert break; } } catch (std::exception& x) { pinEntry.pin().clear(); LOG<<"**** ERROR"<1) loops().back()->exec(); // wait } ~Lock() { TRC; LOG<exit(0); // wake up next } private: QList& loops() { // same as a static member variable static QList _loops; return _loops; } }; private: QWidget* _parent; CryptokiEngine* _e; openssl::RegisterEngine _reg; suisseid::Cards _cards; std::shared_ptr _session; }; } #endif // SMARTCARDAUTH_H