#ifndef SMARTCARDAUTH_H #define SMARTCARDAUTH_H #include #include #include #include #include #include #include #include #include #include #include class CryptokiEngine: public QObject, public openssl::Engine { Q_OBJECT; Q_SIGNALS: void certRequired(); public: CryptokiEngine(std::string lib): _cryptoki(lib) { OPENSSL_LOG("log"); } operator bool() { OPENSSL_LOG("Status of CryptokiEngine: " <<(_privateKey.get() ?"privateKey defined, ":"privateKey undefined") <<(_cert.get()?"cert defined":"cert undefined")); return _privateKey.get() && _cert.get(); } cryptoki::Init& cryptoki() { return _cryptoki; } void cert(cryptoki::Object privateKey, std::auto_ptr c) { OPENSSL_LOG("log"); _cert = c; _privateKey = std::auto_ptr (new cryptoki::Object(privateKey)); _modulus = privateKey.attribute(CKA_MODULUS).value; _exponent = privateKey.attribute(CKA_PUBLIC_EXPONENT).value; } const openssl::X509& cert() { return *_cert; } virtual RSA* setupRsa(RSA* r) { RSA_free(r); //→ occasional crashes? r = RSA_new_method(_e); r->n = BN_bin2bn((const unsigned char*)_modulus.data(), _modulus.size(), r->n); r->e = BN_bin2bn((const unsigned char*)_exponent.data(), _exponent.size(), r->e); // otherwise OpenSSL emulates sign/verify with encrypt/decrypt r->flags |= RSA_FLAG_SIGN_VER; return r; } protected: virtual const char* id() { OPENSSL_LOG("log"); return "CryptokiEngine_ID"; } virtual const char* name() { OPENSSL_LOG("log"); return "CryptokiEngine_NAME"; } virtual std::string rsaSign(const std::string& in, unsigned int type) { OPENSSL_LOG("log; type="<sign(in, CKM_RSA_PKCS); } private: cryptoki::Init _cryptoki; std::string _modulus; std::string _exponent; std::auto_ptr _privateKey; std::auto_ptr _cert; }; class SmartCardAuth: public QObject { Q_OBJECT; public: SmartCardAuth(const QString& lib, QWidget* p=0, bool loginAtStart=true): _reg(e(lib)), _parent(p) { qDebug()<<__PRETTY_FUNCTION__; if (loginAtStart) login(); //assert(connect(e(), SIGNAL(certRequired()), SLOT(login()))); } static CryptokiEngine* e(const QString& lib = QString()) try { static CryptokiEngine* _e(new CryptokiEngine(lib.toStdString())); return _e; } catch (const std::exception& e) { qDebug()<<"Smartcard Error: "< _reg; //std::map sockets; public: void login(bool force=false) { qDebug()<<__PRETTY_FUNCTION__; QMutexLocker lock(&_mutex); if (!e() || (!force && *e())) return; // no smartcard or already logged in try { QList authcerts; QList allcerts; QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); _slots = e()->cryptoki().slotList(); for (cryptoki::SlotList::iterator slot(_slots.begin()); slot!=_slots.end(); ++slot) { _session = std::auto_ptr(new cryptoki::Session(*slot)); cryptoki::ObjectList certs(_session->find (cryptoki::Attribute(CKA_CLASS) .from(CKO_CERTIFICATE))); for (cryptoki::ObjectList::iterator cert(certs.begin()); cert!=certs.end(); ++cert) { cryptoki::Attribute label(cert->attribute(CKA_LABEL)); cryptoki::Attribute id(cert->attribute(CKA_ID)); OPENSSL_LOG("**** FOUND CERTIFICATE: "<find(cryptoki::Attribute(CKA_CLASS) .from(CKO_PUBLIC_KEY), id)); OPENSSL_LOG("**** with keys: "<attribute(CKA_VALUE).value); if (!keys.size()) { // add CA-certificate OPENSSL_LOG("**** add to CA-certificates"); } else { OPENSSL_LOG("**** user cert, check for authentictaion"); if (label.value.find("auth")==0 || label.value.find("Authentication")!=std::string::npos) { OPENSSL_LOG("**** it's our authentication cert"); authcerts.push_back(CertInfo(data, slot, id)); } else { OPENSSL_LOG("**** it's an unknown cert"); allcerts.push_back(CertInfo(data, slot, id)); } } } } if (!authcerts.isEmpty() || !allcerts.isEmpty()) { CertInfo c(authcerts.size()?authcerts[0]:allcerts[0]); PinEntry pinEntry(QSslCertificate(QByteArray(c.data.data(), c.data.size()), QSsl::Der), _parent); while (pinEntry.exec()==PinEntry::Accepted) try { _session = std::auto_ptr (new cryptoki::Session(*c.slot)); _session->login(pinEntry.pin().toStdString()); cryptoki::ObjectList keys (_session->find(cryptoki::Attribute(CKA_CLASS) .from(CKO_PRIVATE_KEY), c.id)); if (keys.size()==1) { OPENSSL_LOG("**** found one private key"); e()->cert(keys[0], std::auto_ptr (new openssl::X509(c.data))); try { // new QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); QSslCertificate localcert(QByteArray(c.data.data(), c.data.size()), QSsl::Der); sslConfig.setLocalCertificate(localcert); assert(localcert.isValid()); QByteArray pem ("-----BEGIN RSA PRIVATE KEY-----\n" "MIIBOwIBAAJBAMH2yqAGeVNPdgeZ2GoHo31m9aUxZ7QfK2" "Go2qLTahLpQ3UL1C8G\n" "LkuMS8SNK0ZGfRMalIpIhv6bW5l3kjogOncCAwEAAQJABV" "GECtFCoGMsZFb2lSmy\n" "dOzOzYHGSy0TnnDn1dEgNnZ8sIljElPtUzm9dyXs2P3ICL" "1sOd7qjpzfJeyxknDL\n" "AQIhAO5iKdLmhyuW+EDEH19vDs1Pmqs3/ZnT5UgUiJnTJq" "z3AiEA0ExIfUOCnxq2\n" "a3Z46KEivcr8JB2P9VqouBbVryiq/oECIQDj8bPCejMoiE" "zMSX0iWWTTB9qC/KAg\n" "FtF4skHIrXKfEwIgPCs86Uo+Ch2aQjKHvJMHSRHAgeI0Om" "iEwiB+e0lhE4ECIQDd\n" "IbUmHIXt6oHLJmoGFX46bCcfil5eE5FXfiaw7Q9iPw==\n" "-----END RSA PRIVATE KEY-----\n"); QSslKey privkey(pem, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); e()->setupRsa((RSA*)privkey.handle()); assert(!privkey.isNull()); sslConfig.setPrivateKey(privkey); QSslConfiguration::setDefaultConfiguration(sslConfig); } catch (const std::exception& e) { OPENSSL_LOG("SETUP ERROR: "< _session; QMutex _mutex; // std::list _cacerts; }; #endif // SMARTCARDAUTH_H