@@ -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;
|
||||
}
|
||||
|
||||
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;
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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())));
|
||||
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;
|
||||
}
|
||||
public Q_SLOTS:
|
||||
|
||||
private:
|
||||
|
||||
openssl::RegisterEngine<CryptokiEngine> _reg;
|
||||
//std::map<ssl_ctx_st*, QSslSocket*> sockets;
|
||||
|
||||
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;
|
||||
|
||||
};
|
||||
|
Reference in New Issue
Block a user