|
|
|
@ -12,10 +12,8 @@ |
|
|
|
|
|
|
|
|
|
#include <pinentry.hxx> |
|
|
|
|
|
|
|
|
|
#include <cryptoki.hxx> |
|
|
|
|
#include <pcsc.hxx> |
|
|
|
|
#include <suisseid.hxx> |
|
|
|
|
#include <openssl-engine.hxx> |
|
|
|
|
#include <openssl.hxx> |
|
|
|
|
|
|
|
|
|
#include <memory> |
|
|
|
|
|
|
|
|
@ -29,8 +27,7 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
CryptokiEngine(std::string lib): |
|
|
|
|
_cryptoki(lib) { |
|
|
|
|
CryptokiEngine() { |
|
|
|
|
TRC; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -41,10 +38,6 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
return _privateKey.get(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
cryptoki::Library& cryptoki() { |
|
|
|
|
return _cryptoki; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void cert(cryptoki::Object& privateKey, const std::string& certVal) { |
|
|
|
|
TRC; |
|
|
|
|
_privateKey = std::auto_ptr<cryptoki::Object> |
|
|
|
@ -110,12 +103,12 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
|
|
|
|
|
virtual const char* id() { |
|
|
|
|
TRC; |
|
|
|
|
return "CryptokiEngine_ID"; |
|
|
|
|
return "SuisseID Engine ID"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual const char* name() { |
|
|
|
|
TRC; |
|
|
|
|
return "CryptokiEngine_NAME"; |
|
|
|
|
return "SuisseID Engine NAME"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual std::string rsaSign(const std::string& in, unsigned int type) try { |
|
|
|
@ -139,7 +132,6 @@ class CryptokiEngine: public QObject, public openssl::Engine { |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
cryptoki::Library _cryptoki; |
|
|
|
|
std::auto_ptr<cryptoki::Object> _privateKey; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
@ -149,8 +141,8 @@ class SmartCardAuth: public QObject { |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
|
|
|
|
|
SmartCardAuth(const QString& lib, QWidget* p=0, bool loginAtStart=true): |
|
|
|
|
_parent(p), _e(new CryptokiEngine(lib.toStdString())), _reg(_e) { |
|
|
|
|
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()))); |
|
|
|
@ -160,84 +152,37 @@ class SmartCardAuth: public QObject { |
|
|
|
|
|
|
|
|
|
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 { |
|
|
|
|
Lock lock; |
|
|
|
|
LOG<<"got lock"; |
|
|
|
|
if (!_e || (!force && *_e)) return; // no smartcard or already logged in
|
|
|
|
|
LOG<<"start login to smartcard"; |
|
|
|
|
QList<CertInfo> authcerts; |
|
|
|
|
QList<CertInfo> allcerts; |
|
|
|
|
QSslConfiguration sslConfig(QSslConfiguration::defaultConfiguration()); |
|
|
|
|
_slots = _e->cryptoki().slotList(); |
|
|
|
|
LOG<<"number of slots"<<_slots.size(); |
|
|
|
|
// look for login certificates ----------------------------------------
|
|
|
|
|
for (cryptoki::SlotList::iterator slot(_slots.begin()); |
|
|
|
|
slot!=_slots.end(); ++slot) { |
|
|
|
|
cryptoki::Session session(*slot); |
|
|
|
|
cryptoki::ObjectList certs(session.find |
|
|
|
|
(cryptoki::Attribute(CKA_CLASS) |
|
|
|
|
.from<CK_OBJECT_CLASS>(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)); |
|
|
|
|
LOG<<"**** FOUND CERTIFICATE: "<<label.value.c_str(); |
|
|
|
|
cryptoki::ObjectList keys |
|
|
|
|
(session.find(cryptoki::Attribute(CKA_CLASS) |
|
|
|
|
.from<CK_OBJECT_CLASS>(CKO_PUBLIC_KEY), |
|
|
|
|
id)); |
|
|
|
|
LOG<<"**** with keys: "<<keys.size(); |
|
|
|
|
std::string data(cert->attribute(CKA_VALUE).value); |
|
|
|
|
if (!keys.size()) { // add CA-certificate
|
|
|
|
|
LOG<<"**** add to CA-certificates"; |
|
|
|
|
} else { |
|
|
|
|
LOG<<"**** user cert, check for authentictaion"; |
|
|
|
|
if (label.value.find("auth")==0 || |
|
|
|
|
label.value.find("Authentication")!=std::string::npos) { |
|
|
|
|
LOG<<"**** it's our authentication cert"; |
|
|
|
|
authcerts.push_back(CertInfo(data, slot, id)); |
|
|
|
|
} else { |
|
|
|
|
LOG<<"**** it's an unknown cert"; |
|
|
|
|
allcerts.push_back(CertInfo(data, slot, id)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// get pin and install client certificate ------------------------------
|
|
|
|
|
LOG<<"00000000000000000000000000000000000000000000000000"; |
|
|
|
|
if (!authcerts.isEmpty() || !allcerts.isEmpty()) { |
|
|
|
|
LOG<<"11111111111111111111111111111111111111111111111111"; |
|
|
|
|
CertInfo c(authcerts.size()?authcerts[0]:allcerts[0]); |
|
|
|
|
PinEntry pinEntry(QSslCertificate(QByteArray(c.data.data(), |
|
|
|
|
c.data.size()), |
|
|
|
|
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 { |
|
|
|
|
LOG<<"******************************************1*******"; |
|
|
|
|
pinEntry.tokeninfo(c.slot->tokeninfo()) |
|
|
|
|
.retries(retries(c.slot->slotinfo().slotDescription)); |
|
|
|
|
LOG<<"******************************************2*******"; |
|
|
|
|
int res(pinEntry.myexec()); |
|
|
|
|
LOG<<"******************************************3*******"; |
|
|
|
|
if (res!=PinEntry::Accepted) return; |
|
|
|
|
LOG<<"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; |
|
|
|
|
if (pinEntry |
|
|
|
|
.tokeninfo((*card)->minimalPinLength(), |
|
|
|
|
(*card)->maximalPinLength()) |
|
|
|
|
.retries((*card)->pkcs15PinRetries()) |
|
|
|
|
.myexec() |
|
|
|
|
!=PinEntry::Accepted) |
|
|
|
|
return; |
|
|
|
|
_session = // session login with pin
|
|
|
|
|
std::auto_ptr<cryptoki::Session> |
|
|
|
|
(new cryptoki::Session(*c.slot)); |
|
|
|
|
LOG<<"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"; |
|
|
|
|
std::shared_ptr<cryptoki::Session> |
|
|
|
|
(new cryptoki::Session((*card)->session())); |
|
|
|
|
_session->login(pinEntry.pin().toStdString()); |
|
|
|
|
LOG<<"CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"; |
|
|
|
|
cryptoki::ObjectList keys |
|
|
|
|
(_session->find(cryptoki::Attribute(CKA_CLASS) |
|
|
|
|
.from<CK_OBJECT_CLASS>(CKO_PRIVATE_KEY), |
|
|
|
|
c.id)); |
|
|
|
|
LOG<<"DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"; |
|
|
|
|
cert.id())); |
|
|
|
|
if (keys.size()==1) { |
|
|
|
|
LOG<<"**** found one private key"; |
|
|
|
|
_e->cert(keys[0], c.data); // install client cert
|
|
|
|
|
LOG<<"=================================================="; |
|
|
|
|
_e->cert(keys[0], cert); // install client cert
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
LOG<<"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; |
|
|
|
|
} catch (std::exception& x) { |
|
|
|
|
pinEntry.pin().clear(); |
|
|
|
|
LOG<<"**** ERROR"<<x.what(); |
|
|
|
@ -246,150 +191,16 @@ class SmartCardAuth: public QObject { |
|
|
|
|
" please try again.")); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
LOG<<"YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY"; |
|
|
|
|
} catch (std::exception& x) { |
|
|
|
|
LOG<<"**** ERROR"<<x.what(); |
|
|
|
|
throw; |
|
|
|
|
} |
|
|
|
|
LOG<<"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
int minPinLen(const std::string& name) { |
|
|
|
|
TRC; LOG<<name.c_str(); |
|
|
|
|
try { |
|
|
|
|
pcsc::Connection pcsc; |
|
|
|
|
mrw::Shared<pcsc::Connection::Reader> reader(pcsc.reader(name)); |
|
|
|
|
#ifndef Q_OS_MAC |
|
|
|
|
pcsc::Connection::Reader::Transaction lock(reader); |
|
|
|
|
#endif |
|
|
|
|
// first try to read version info
|
|
|
|
|
if (reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x3f\x00\x56\x49", 4) |
|
|
|
|
!= std::string("\x90\x00", 2) || !reader) { |
|
|
|
|
LOG<<"Select File failed"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
std::string res(reader->transmit(0x00, 0xB0, 0x00, 0x00)); |
|
|
|
|
if (res.substr(res.size()-2)!=std::string("\x90\x00", 2)) { |
|
|
|
|
LOG<<"read error"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
LOG<<"version text is: "<<res.substr(4, res[3]).c_str(); |
|
|
|
|
// if (res.substr(4, res[3]) != "RAPost 2009" &&
|
|
|
|
|
// res.substr(4, res[3]) != "RAPost 2010") {
|
|
|
|
|
// LOG<<"unsupported card";
|
|
|
|
|
// return -2;
|
|
|
|
|
// }
|
|
|
|
|
if (retCode(reader->transmit(0x00, 0xA4, 0x00, 0x0C)) == 0x9000) { |
|
|
|
|
int value(retCode(reader->transmit(0x00, 0x20, 0x00, 0x81))); |
|
|
|
|
if ((value&0x63C0)==0x63C0) return value&0x0F; |
|
|
|
|
} else { |
|
|
|
|
LOG<<"**** ERROR in select MF while reading pin status"; |
|
|
|
|
} |
|
|
|
|
return -1; // locked
|
|
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
LOG<<"**** ERROR while reading pin status: "<<x.what(); |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int maxPinLen(const std::string& name) { |
|
|
|
|
TRC; LOG<<name.c_str(); |
|
|
|
|
try { |
|
|
|
|
pcsc::Connection pcsc; |
|
|
|
|
mrw::Shared<pcsc::Connection::Reader> reader(pcsc.reader(name)); |
|
|
|
|
#ifndef Q_OS_MAC |
|
|
|
|
pcsc::Connection::Reader::Transaction lock(reader); |
|
|
|
|
#endif |
|
|
|
|
// first try to read version info
|
|
|
|
|
if (reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x3f\x00\x56\x49", 4) |
|
|
|
|
!= std::string("\x90\x00", 2) || !reader) { |
|
|
|
|
LOG<<"Select File failed"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
std::string res(reader->transmit(0x00, 0xB0, 0x00, 0x00)); |
|
|
|
|
if (res.substr(res.size()-2)!=std::string("\x90\x00", 2)) { |
|
|
|
|
LOG<<"read error"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
LOG<<"version text is: "<<res.substr(4, res[3]).c_str(); |
|
|
|
|
// if (res.substr(4, res[3]) != "RAPost 2009" &&
|
|
|
|
|
// res.substr(4, res[3]) != "RAPost 2010") {
|
|
|
|
|
// LOG<<"unsupported card";
|
|
|
|
|
// return -2;
|
|
|
|
|
// }
|
|
|
|
|
if (retCode(reader->transmit(0x00, 0xA4, 0x00, 0x0C)) == 0x9000) { |
|
|
|
|
int value(retCode(reader->transmit(0x00, 0x20, 0x00, 0x81))); |
|
|
|
|
if ((value&0x63C0)==0x63C0) return value&0x0F; |
|
|
|
|
} else { |
|
|
|
|
LOG<<"**** ERROR in select MF while reading pin status"; |
|
|
|
|
} |
|
|
|
|
return -1; // locked
|
|
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
LOG<<"**** ERROR while reading pin status: "<<x.what(); |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int retries(const std::string& name) { |
|
|
|
|
TRC; LOG<<name.c_str(); |
|
|
|
|
try { |
|
|
|
|
pcsc::Connection pcsc; |
|
|
|
|
mrw::Shared<pcsc::Connection::Reader> reader(pcsc.reader(name)); |
|
|
|
|
#ifndef Q_OS_MAC |
|
|
|
|
pcsc::Connection::Reader::Transaction lock(reader); |
|
|
|
|
#endif |
|
|
|
|
// first try to read version info
|
|
|
|
|
if (reader->transmit(0x00, 0xA4, 0x08, 0x0C, "\x3f\x00\x56\x49", 4) |
|
|
|
|
!= std::string("\x90\x00", 2) || !reader) { |
|
|
|
|
LOG<<"Select File failed"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
std::string res(reader->transmit(0x00, 0xB0, 0x00, 0x00)); |
|
|
|
|
if (res.substr(res.size()-2)!=std::string("\x90\x00", 2)) { |
|
|
|
|
LOG<<"read error"; |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
LOG<<"version text is: "<<res.substr(4, res[3]).c_str(); |
|
|
|
|
// if (res.substr(4, res[3]) != "RAPost 2009" &&
|
|
|
|
|
// res.substr(4, res[3]) != "RAPost 2010") {
|
|
|
|
|
// LOG<<"unsupported card";
|
|
|
|
|
// return -2;
|
|
|
|
|
// }
|
|
|
|
|
if (retCode(reader->transmit(0x00, 0xA4, 0x00, 0x0C)) == 0x9000) { |
|
|
|
|
int value(retCode(reader->transmit(0x00, 0x20, 0x00, 0x81))); |
|
|
|
|
if ((value&0x63C0)==0x63C0) return value&0x0F; |
|
|
|
|
} else { |
|
|
|
|
LOG<<"**** ERROR in select MF while reading pin status"; |
|
|
|
|
} |
|
|
|
|
return -1; // locked
|
|
|
|
|
} catch (const std::exception& x) { |
|
|
|
|
LOG<<"**** ERROR while reading pin status: "<<x.what(); |
|
|
|
|
return -2; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
int retCode(const std::string& res) { |
|
|
|
|
if (res.size()>=2) |
|
|
|
|
return ((((unsigned int)(unsigned char)res[res.size()-2])*256) |
|
|
|
|
+((unsigned int)(unsigned char)res[res.size()-1])); |
|
|
|
|
else |
|
|
|
|
return -1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
struct CertInfo { |
|
|
|
|
CertInfo(std::string d, cryptoki::SlotList::iterator s, |
|
|
|
|
cryptoki::Attribute i): |
|
|
|
|
data(d), slot(s), id(i) { |
|
|
|
|
} |
|
|
|
|
std::string data; |
|
|
|
|
cryptoki::SlotList::iterator slot; |
|
|
|
|
cryptoki::Attribute id; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class Lock { |
|
|
|
|
public: |
|
|
|
|
Lock() { |
|
|
|
@ -416,8 +227,8 @@ class SmartCardAuth: public QObject { |
|
|
|
|
QWidget* _parent; |
|
|
|
|
CryptokiEngine* _e; |
|
|
|
|
openssl::RegisterEngine<CryptokiEngine> _reg; |
|
|
|
|
cryptoki::SlotList _slots; |
|
|
|
|
std::auto_ptr<cryptoki::Session> _session; |
|
|
|
|
suisseid::Cards _cards; |
|
|
|
|
std::shared_ptr<cryptoki::Session> _session; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|