|
|
|
@ -34,42 +34,79 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
operator bool() { |
|
|
|
|
OPENSSL_LOG("Status of CryptokiEngine: " |
|
|
|
|
<<(_privateKey.get() |
|
|
|
|
?"privateKey defined, ":"privateKey undefined") |
|
|
|
|
<<(_cert.get()?"cert defined":"cert undefined")); |
|
|
|
|
return _privateKey.get() && _cert.get(); |
|
|
|
|
?"privateKey defined, ":"privateKey undefined")); |
|
|
|
|
return _privateKey.get(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cryptoki::Init& cryptoki() { |
|
|
|
|
return _cryptoki; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cert(cryptoki::Object privateKey, std::auto_ptr<openssl::X509> c) { |
|
|
|
|
void cert(cryptoki::Object& privateKey, const std::string& certVal) { |
|
|
|
|
OPENSSL_LOG("log"); |
|
|
|
|
_cert = c; |
|
|
|
|
_privateKey = std::auto_ptr<cryptoki::Object> |
|
|
|
|
(new cryptoki::Object(privateKey)); |
|
|
|
|
_modulus = privateKey.attribute(CKA_MODULUS).value; |
|
|
|
|
_exponent = privateKey.attribute(CKA_PUBLIC_EXPONENT).value; |
|
|
|
|
try { // new
|
|
|
|
|
QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); |
|
|
|
|
QSslCertificate localcert(QByteArray(certVal.data(), |
|
|
|
|
certVal.size()), |
|
|
|
|
QSsl::Der); |
|
|
|
|
sslConfig.setLocalCertificate(localcert); |
|
|
|
|
assert(localcert.isValid()); |
|
|
|
|
|
|
|
|
|
QByteArray pem // empty dummy key for qt object instantiation
|
|
|
|
|
("-----BEGIN RSA PRIVATE KEY-----\n" |
|
|
|
|
"MIIBOwIBAAJBAMH2yqAGeVNPdgeZ2GoHo" |
|
|
|
|
"31m9aUxZ7QfK2Go2qLTahLpQ3UL1C8G\n" |
|
|
|
|
"LkuMS8SNK0ZGfRMalIpIhv6bW5l3kjogO" |
|
|
|
|
"ncCAwEAAQJABVGECtFCoGMsZFb2lSmy\n" |
|
|
|
|
"dOzOzYHGSy0TnnDn1dEgNnZ8sIljElPtU" |
|
|
|
|
"zm9dyXs2P3ICL1sOd7qjpzfJeyxknDL\n" |
|
|
|
|
"AQIhAO5iKdLmhyuW+EDEH19vDs1Pmqs3/" |
|
|
|
|
"ZnT5UgUiJnTJqz3AiEA0ExIfUOCnxq2\n" |
|
|
|
|
"a3Z46KEivcr8JB2P9VqouBbVryiq/oECI" |
|
|
|
|
"QDj8bPCejMoiEzMSX0iWWTTB9qC/KAg\n" |
|
|
|
|
"FtF4skHIrXKfEwIgPCs86Uo+Ch2aQjKHv" |
|
|
|
|
"JMHSRHAgeI0OmiEwiB+e0lhE4ECIQDd\n" |
|
|
|
|
"IbUmHIXt6oHLJmoGFX46bCcfil5eE5FXf" |
|
|
|
|
"iaw7Q9iPw==\n" |
|
|
|
|
"-----END RSA PRIVATE KEY-----\n"); |
|
|
|
|
QSslKey privkey(pem, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); |
|
|
|
|
RSA* rsa(0); |
|
|
|
|
do { |
|
|
|
|
rsa = ((RSA*)privkey.handle()); |
|
|
|
|
RSA_free(rsa); //→ occasional crashes?
|
|
|
|
|
rsa = RSA_new_method(_e); |
|
|
|
|
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()); |
|
|
|
|
} while (rsa!=(RSA*)privkey.handle()); |
|
|
|
|
sslConfig.setPrivateKey(privkey); |
|
|
|
|
QSslConfiguration::setDefaultConfiguration(sslConfig); |
|
|
|
|
} catch (const std::exception& e) { |
|
|
|
|
OPENSSL_LOG("SETUP ERROR: "<<e.what()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const openssl::X509& cert() { |
|
|
|
|
return *_cert; |
|
|
|
|
} |
|
|
|
|
protected: |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
void set(BIGNUM*& num, cryptoki::Object& key, int type, std::string name) { |
|
|
|
|
try { |
|
|
|
|
std::string value(key.attribute(type).value); |
|
|
|
|
num = BN_bin2bn((const unsigned char*)value.data(), |
|
|
|
|
value.size(), num); |
|
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
qDebug()<<"**** ERROR: key attribute missing:"<<name.c_str()<<x.what(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
|
|
|
|
|
virtual const char* id() { |
|
|
|
|
OPENSSL_LOG("log"); |
|
|
|
|
return "CryptokiEngine_ID"; |
|
|
|
@ -85,16 +122,18 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
if (type != NID_md5_sha1) throw std::runtime_error("wrong sign type"); |
|
|
|
|
if (in.size() != 36) throw std::runtime_error("wrong msg size to sign"); |
|
|
|
|
OPENSSL_LOG("ready to sign"); |
|
|
|
|
return _privateKey->sign(in, CKM_RSA_PKCS); |
|
|
|
|
try { |
|
|
|
|
return _privateKey->sign(in, CKM_RSA_PKCS); |
|
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
certRequired(); // get new certificate
|
|
|
|
|
return _privateKey->sign(in, CKM_RSA_PKCS); // try again
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
cryptoki::Init _cryptoki; |
|
|
|
|
std::string _modulus; |
|
|
|
|
std::string _exponent; |
|
|
|
|
std::auto_ptr<cryptoki::Object> _privateKey; |
|
|
|
|
std::auto_ptr<openssl::X509> _cert; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -104,36 +143,24 @@ class SmartCardAuth: public QObject { |
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
SmartCardAuth(const QString& lib, QWidget* p=0, bool loginAtStart=true): |
|
|
|
|
_reg(e(lib)), _parent(p) { |
|
|
|
|
_parent(p), _e(new CryptokiEngine(lib.toStdString())), _reg(_e) { |
|
|
|
|
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: "<<e.what(); |
|
|
|
|
return 0; |
|
|
|
|
assert(connect(_e, SIGNAL(certRequired()), SLOT(login()))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
openssl::RegisterEngine<CryptokiEngine> _reg; |
|
|
|
|
//std::map<ssl_ctx_st*, QSslSocket*> sockets;
|
|
|
|
|
public Q_SLOTS: |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
void login(bool force=false) { |
|
|
|
|
void login(bool force=true) { |
|
|
|
|
qDebug()<<__PRETTY_FUNCTION__; |
|
|
|
|
QMutexLocker lock(&_mutex); |
|
|
|
|
if (!e() || (!force && *e())) return; // no smartcard or already logged in
|
|
|
|
|
if (!_e || (!force && *_e)) return; // no smartcard or already logged in
|
|
|
|
|
try { |
|
|
|
|
QList<CertInfo> authcerts; |
|
|
|
|
QList<CertInfo> allcerts; |
|
|
|
|
QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); |
|
|
|
|
_slots = e()->cryptoki().slotList(); |
|
|
|
|
_slots = _e->cryptoki().slotList(); |
|
|
|
|
// look for login certificates ----------------------------------------
|
|
|
|
|
for (cryptoki::SlotList::iterator slot(_slots.begin()); |
|
|
|
|
slot!=_slots.end(); ++slot) { |
|
|
|
|
_session = |
|
|
|
@ -167,6 +194,7 @@ class SmartCardAuth: public QObject { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// get pin and install client certificate ------------------------------
|
|
|
|
|
if (!authcerts.isEmpty() || !allcerts.isEmpty()) { |
|
|
|
|
CertInfo c(authcerts.size()?authcerts[0]:allcerts[0]); |
|
|
|
|
PinEntry pinEntry(QSslCertificate(QByteArray(c.data.data(), |
|
|
|
@ -174,7 +202,7 @@ class SmartCardAuth: public QObject { |
|
|
|
|
QSsl::Der), _parent); |
|
|
|
|
while (pinEntry.exec()==PinEntry::Accepted) |
|
|
|
|
try { |
|
|
|
|
_session = |
|
|
|
|
_session = // session login with pin
|
|
|
|
|
std::auto_ptr<cryptoki::Session> |
|
|
|
|
(new cryptoki::Session(*c.slot)); |
|
|
|
|
_session->login(pinEntry.pin().toStdString()); |
|
|
|
@ -184,42 +212,7 @@ class SmartCardAuth: public QObject { |
|
|
|
|
c.id)); |
|
|
|
|
if (keys.size()==1) { |
|
|
|
|
OPENSSL_LOG("**** found one private key"); |
|
|
|
|
e()->cert(keys[0], |
|
|
|
|
std::auto_ptr<openssl::X509> |
|
|
|
|
(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: "<<e.what()); |
|
|
|
|
} |
|
|
|
|
_e->cert(keys[0], c.data); // install client cert
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} catch (std::exception& x) { |
|
|
|
@ -250,9 +243,12 @@ class SmartCardAuth: public QObject { |
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
QWidget* _parent; |
|
|
|
|
CryptokiEngine* _e; |
|
|
|
|
openssl::RegisterEngine<CryptokiEngine> _reg; |
|
|
|
|
cryptoki::SlotList _slots; |
|
|
|
|
std::auto_ptr<cryptoki::Session> _session; |
|
|
|
|
QMutex _mutex; |
|
|
|
|
//std::map<ssl_ctx_st*, QSslSocket*> sockets;
|
|
|
|
|
// std::list<std::string> _cacerts;
|
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|