diff --git a/lib/db_key.cpp b/lib/db_key.cpp index 08a99632..b401670b 100644 --- a/lib/db_key.cpp +++ b/lib/db_key.cpp @@ -197,6 +197,10 @@ void db_key::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) if (key->isScard()) { menu->addAction(tr("Change PIN"), this, SLOT(changePin())); + menu->addAction(tr("Init PIN with SO PIN (PUK)"), this, + SLOT(initPin())); + menu->addAction(tr("Change SO PIN (PUK)"), this, + SLOT(changeSoPin())); } } menu->exec(e->globalPos()); @@ -295,10 +299,43 @@ void db_key::changePin() scard = static_cast(currentIdx.internalPointer()); try { if (!scard->isScard()) { - throw errorEx(tr("Tried to change password of a smart card")); + throw errorEx(tr("Tried to change PIN of a key")); } scard->changePin(); } catch (errorEx &err) { mainwin->Error(err); } } + +void db_key::initPin() +{ + pki_scard *scard; + if (!currentIdx.isValid()) + return; + scard = static_cast(currentIdx.internalPointer()); + try { + if (!scard->isScard()) { + throw errorEx(tr("Tried to init PIN of a key")); + } + scard->initPin(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + +void db_key::changeSoPin() +{ + pki_scard *scard; + if (!currentIdx.isValid()) + return; + scard = static_cast(currentIdx.internalPointer()); + try { + if (!scard->isScard()) { + throw errorEx(tr("Tried to change SO PIN of a key")); + } + scard->changeSoPin(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + diff --git a/lib/db_key.h b/lib/db_key.h index 504608df..4f978910 100644 --- a/lib/db_key.h +++ b/lib/db_key.h @@ -42,6 +42,8 @@ class db_key: public db_base void setOwnPass(); void resetOwnPass(); void changePin(); + void initPin(); + void changeSoPin(); signals: void delKey(pki_key *delkey); diff --git a/lib/db_x509.cpp b/lib/db_x509.cpp index 5ff781db..7302f492 100644 --- a/lib/db_x509.cpp +++ b/lib/db_x509.cpp @@ -549,10 +549,10 @@ void db_x509::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) { QMenu *menu = new QMenu(mainwin); QMenu *subExport, *subCa; - QAction *itemReq, *itemRevoke, *itemExtend, - *itemTrust; - bool parentCanSign, canSign, hasTemplates, hasPrivkey; + QAction *itemReq, *itemRevoke, *itemExtend, *itemTrust, *itemScard; + bool parentCanSign, canSign, hasTemplates; currentIdx = index; + pki_key *privkey; pki_x509 *cert = static_cast(index.internalPointer()); @@ -567,6 +567,8 @@ void db_x509::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) subExport->addAction(tr("File"), this, SLOT(store())); itemReq = subExport->addAction(tr("Request"), this, SLOT(toRequest())); + itemScard = subExport->addAction(tr("Smart Card"), + this, SLOT(toScard())); menu->addAction(tr("Delete"), this, SLOT(delete_ask())); itemTrust = menu->addAction(tr("Trust"), this, SLOT(setTrust())); @@ -594,13 +596,14 @@ void db_x509::showContextMenu(QContextMenuEvent *e, const QModelIndex &index) && (cert->getSigner() != cert)); canSign = cert->canSign(); hasTemplates = mainwin->temps->getDesc().count() > 0 ; - hasPrivkey = cert->getRefKey(); + privkey = cert->getRefKey(); itemRevoke->setEnabled(parentCanSign); itemExtend->setEnabled(parentCanSign); subCa->setEnabled(canSign); - itemReq->setEnabled(hasPrivkey); + itemReq->setEnabled(privkey); + itemScard->setEnabled(privkey && privkey->isScard()); #if 0 - subP7->setEnabled(hasPrivkey); + subP7->setEnabled(privkey); #endif } menu->exec(e->globalPos()); @@ -1013,6 +1016,18 @@ void db_x509::toRequest() } } +void db_x509::toScard() +{ + pki_x509 *cert = static_cast(currentIdx.internalPointer()); + if (!cert) + return; + try { + cert->store_token(); + } catch (errorEx &err) { + mainwin->Error(err); + } +} + void db_x509::caProperties() { Ui::CaProperties ui; diff --git a/lib/db_x509.h b/lib/db_x509.h index 989fdfb6..e3dc6ad5 100644 --- a/lib/db_x509.h +++ b/lib/db_x509.h @@ -66,6 +66,7 @@ class db_x509: public db_x509super void genCrl(); void caProperties(); void toRequest(); + void toScard(); void newCert(pki_temp *); void newCert(pki_x509req *); void loadPKCS12(); diff --git a/lib/pk11_attribute.cpp b/lib/pk11_attribute.cpp index 938b859e..78eee42a 100644 --- a/lib/pk11_attribute.cpp +++ b/lib/pk11_attribute.cpp @@ -37,3 +37,22 @@ void pk11_attr_data::load(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) pkcs11::pk11error("C_GetAttributeValue(data)", rv); \ } +void pk11_attr_data::setValue(const void *ptr, unsigned long len) +{ + if (attr.pValue) + free(attr.pValue); + attr.pValue = malloc(len); + if (!attr.pValue) + throw errorEx("Out of Memory"); + memcpy(attr.pValue, ptr, len); + attr.ulValueLen = len; +} + +void pk11_attribute::store(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj) +{ + CK_RV rv; + rv = pkcs11::p11->C_SetAttributeValue(sess, obj, &attr, 1); + if (rv != CKR_OK) + pkcs11::pk11error("C_SetAttributeValue", rv); +} + diff --git a/lib/pk11_attribute.h b/lib/pk11_attribute.h index 36333865..a06321a9 100644 --- a/lib/pk11_attribute.h +++ b/lib/pk11_attribute.h @@ -32,6 +32,7 @@ public: { return &attr; } + void store(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); }; class pk11_attr_ulong: public pk11_attribute @@ -45,7 +46,6 @@ public: attr.pValue = &value; attr.ulValueLen = sizeof(value); } - unsigned long getValue() const { return value; @@ -66,13 +66,11 @@ public: attr.pValue = NULL; attr.ulValueLen = 0; } - unsigned long getValue(const unsigned char **ptr) { *ptr = (unsigned char*)attr.pValue; return attr.ulValueLen; } - ~pk11_attr_data() { if (attr.pValue) @@ -84,11 +82,11 @@ public: } BIGNUM *getBignum() const { - printf("attr.ulValueLen %lu\n", attr.ulValueLen); return BN_bin2bn((unsigned char*)attr.pValue, attr.ulValueLen, NULL); } void load(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); + void setValue(const void *ptr, unsigned long len); }; #endif diff --git a/lib/pkcs11.cpp b/lib/pkcs11.cpp index 88219a22..11f6f029 100644 --- a/lib/pkcs11.cpp +++ b/lib/pkcs11.cpp @@ -21,17 +21,6 @@ pkcs11::pkcs11() session = CK_INVALID_HANDLE; object = CK_INVALID_HANDLE; slot_id = 0; - - init_pkcs11(); -} - -void pkcs11::init_pkcs11() -{ - if (p11) { - CK_RV rv = p11->C_Initialize(NULL); - if (rv != CKR_OK && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) - pk11error("C_Initialize", rv); - } } pkcs11::~pkcs11() @@ -59,27 +48,69 @@ void pkcs11::startSession(unsigned long slot, bool rw) CK_SLOT_ID *pkcs11::getSlotList(unsigned long *num_slots) { CK_RV rv; - CK_SLOT_ID *p11_slots; + CK_SLOT_ID *p11_slots = NULL; - rv = p11->C_GetSlotList(CK_TRUE, NULL, num_slots); - if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) - pk11error("C_GetSlotList", rv); - p11_slots = (CK_SLOT_ID *)malloc(*num_slots *sizeof(CK_SLOT_ID)); - //oom_check(p11_slots); - - rv = p11->C_GetSlotList(CK_TRUE, p11_slots, num_slots); - if (rv != CKR_OK) - pk11error("C_GetSlotList", rv); + p11->C_GetSlotList(CK_TRUE, p11_slots, num_slots); + do { + rv = p11->C_GetSlotList(CK_TRUE, p11_slots, num_slots); + if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL) + pk11error("C_GetSlotList", rv); + printf("*num_slots = %d\n", *num_slots); + if (*num_slots == 0) + break; + p11_slots = (CK_SLOT_ID *)realloc(p11_slots, + *num_slots *sizeof(CK_SLOT_ID)); + if (!p11_slots) + throw errorEx("C_GetSlotList(Out of Memory)"); + } while (rv == CKR_BUFFER_TOO_SMALL); return p11_slots; } -void pkcs11::login(unsigned long slot, - unsigned char *pin, unsigned long pinlen, bool so) +void pkcs11::logout() +{ + CK_RV rv; + + rv = p11->C_Logout(session); + if (rv != CKR_OK) + pk11error("C_Logout", rv); +} + +bool pkcs11::needsLogin(bool so) +{ + CK_SESSION_INFO sinfo; + CK_RV rv; + + rv = p11->C_GetSessionInfo(session, &sinfo); + if (rv != CKR_OK) + pk11error("C_GetSessionInfo", rv); + switch (sinfo.state) { + case CKS_RO_PUBLIC_SESSION: + case CKS_RW_PUBLIC_SESSION: + return true; + case CKS_RW_SO_FUNCTIONS: + if (so) { + return false; + } else { + logout(); + return true; + } + case CKS_RO_USER_FUNCTIONS: + case CKS_RW_USER_FUNCTIONS: + if (!so) { + return false; + } else { + logout(); + return true; + } + } + return true; +} + +void pkcs11::login(unsigned char *pin, unsigned long pinlen, bool so) { unsigned long user = so ? CKU_SO : CKU_USER; CK_RV rv; - startSession(slot, true); rv = p11->C_Login(session, user, pin, pinlen); if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) pk11error("C_Login", rv); @@ -126,6 +157,11 @@ void pkcs11::loadAttribute(pk11_attribute &attribute, CK_OBJECT_HANDLE object) attribute.load(session, object); } +void pkcs11::storeAttribute(pk11_attribute &attribute, CK_OBJECT_HANDLE object) +{ + attribute.store(session, object); +} + QList pkcs11::objectList(const pk11_attribute *att) { CK_RV rv; diff --git a/lib/pkcs11.h b/lib/pkcs11.h index 4fc66356..d07b8437 100644 --- a/lib/pkcs11.h +++ b/lib/pkcs11.h @@ -31,9 +31,12 @@ class pkcs11 CK_SLOT_ID *getSlotList(unsigned long *num_slots); void loadAttribute(pk11_attribute &attribute, CK_OBJECT_HANDLE object); + void storeAttribute(pk11_attribute &attribute, + CK_OBJECT_HANDLE object); QList objectList(const pk11_attribute *att); - void login(unsigned long slot, - unsigned char *pin, unsigned long pinlen, bool so); + void login(unsigned char *pin, unsigned long pinlen, bool so); + void logout(); + bool needsLogin(bool so); void setPin(unsigned char *oldPin, unsigned long oldPinLen, unsigned char *pin, unsigned long pinLen); void initPin(unsigned char *pin, unsigned long pinLen); diff --git a/lib/pki_scard.cpp b/lib/pki_scard.cpp index bc98b70d..818e6ccd 100644 --- a/lib/pki_scard.cpp +++ b/lib/pki_scard.cpp @@ -38,24 +38,26 @@ QPixmap *pki_scard::icon[1] = { NULL }; #define XCA_ENGINE_cmd(e, cmd, value) \ do { \ if (!ENGINE_ctrl_cmd_string(e, cmd, value, 0)) { \ - openssl_error(); \ + printf("FAILED: '%s' : '%s'\n", cmd, value ? value:"");\ ENGINE_free(e); \ return 0; \ } \ + printf("SUCCESS: '%s' : '%s'\n", cmd, value ? value:""); \ } while(0); ENGINE *pki_scard::p11_engine = NULL; -int pki_scard::init_p11engine(void) const +int pki_scard::init_p11engine(void) { ENGINE *e; if (p11_engine) return 1; + pkcs11::load_lib("", true); + ENGINE_load_dynamic(); e = ENGINE_by_id("dynamic"); - openssl_error(); XCA_ENGINE_cmd(e, "SO_PATH", ENGINE_LIB); XCA_ENGINE_cmd(e, "ID", "pkcs11"); @@ -63,6 +65,7 @@ int pki_scard::init_p11engine(void) const XCA_ENGINE_cmd(e, "LOAD", NULL); XCA_ENGINE_cmd(e, "MODULE_PATH", PKCS11_DEFAULT_MODULE_NAME); + ENGINE_init(e); p11_engine = e; return 1; } @@ -137,9 +140,7 @@ int pki_scard::prepare_card() const CK_SLOT_ID *p11_slots = NULL; unsigned long i, num_slots; - while (1) { - p11.init_pkcs11(); p11_slots = p11.getSlotList(&num_slots); for (i=0; itranslate("MainWindow", - "Please enter the PIN of the token: ")+ getIntName()); + pass_info p(XCA_TITLE, + pki_scard::tr("Please enter the PIN of the token: ") + + getIntName()); + p.setPin(); + + slot = prepare_card(); + if (slot == -1) + return; + + int oldPinLen = MainWindow::passRead(oldPin, 256, 0, &p); + if (oldPinLen == -1) + return; + + pkcs11 p11; + p11.startSession(slot, true); + p11.logout(); + p11.login((unsigned char*)oldPin, oldPinLen, false); + p.setDescription(qApp->translate("MainWindow", + "Please enter the new Pin for the token: ") +getIntName()); + + int newPinLen = MainWindow::passWrite(newPin, 256, 0, &p); + if (newPinLen != -1) { + p11.setPin((unsigned char*)oldPin, oldPinLen, + (unsigned char*)newPin, newPinLen); + } +} + +void pki_scard::initPin() +{ + char soPin[256], newPin[256]; + int slot; + + pass_info p(XCA_TITLE, + pki_scard::tr("Please enter the SO PIN (PUK) of the token: ") + + getIntName()); + p.setPin(); + + slot = prepare_card(); + if (slot == -1) + return; + pkcs11 p11; + p11.startSession(slot, true); + if (p11.needsLogin(true)) { + int soPinLen = MainWindow::passRead(soPin, 256, 0, &p); + if (soPinLen == -1) + return; + p11.login((unsigned char*)soPin, soPinLen, true); + } + p.setDescription(qApp->translate("MainWindow", + "Please enter the new Pin for the token: ") +getIntName()); + + int newPinLen = MainWindow::passWrite(newPin, 256, 0, &p); + if (newPinLen != -1) { + p11.initPin((unsigned char*)newPin, newPinLen); + } + p11.logout(); +} + +void pki_scard::changeSoPin() +{ + char oldPin[256], newPin[256]; + int slot; + + pass_info p(XCA_TITLE, + pki_scard::tr("Please enter the SO PIN (PUK) of the token: ") + + getIntName()); p.setPin(); slot = prepare_card(); @@ -293,48 +400,19 @@ void pki_scard::changePin() if (oldPinLen == -1) return; pkcs11 p11; - p11.init_pkcs11(); - p11.login(slot, (unsigned char*)oldPin, oldPinLen, false); + p11.startSession(slot, true); + p11.logout(); + p11.login((unsigned char*)oldPin, oldPinLen, true); p.setDescription(qApp->translate("MainWindow", - "Please enter the new Pin for the token: ") +getIntName()); + "Please enter the new SO Pin for the token: ") +getIntName()); int newPinLen = MainWindow::passWrite(newPin, 256, 0, &p); - if (newPinLen == -1) - return; - - p11.setPin((unsigned char*)oldPin, oldPinLen, - (unsigned char*)newPin, newPinLen); -} - -void pki_scard::initPin() -{ - char soPin[256], newPin[256]; - int slot; - - pass_info p(XCA_TITLE, qApp->translate("MainWindow", - "Please enter the SO PIN (PUK) of the token: ") + - getIntName()); - p.setPin(); - - slot = prepare_card(); - if (slot == -1) - return; - int soPinLen = MainWindow::passRead(soPin, 256, 0, &p); - if (soPinLen == -1) - return; - pkcs11 p11; - p11.init_pkcs11(); - p11.login(slot, (unsigned char*)soPin, soPinLen, true); - - p.setDescription(qApp->translate("MainWindow", - "Please enter the new Pin for the token: ") +getIntName()); - - int newPinLen = MainWindow::passWrite(newPin, 256, 0, &p); - if (newPinLen == -1) - return; - - p11.initPin((unsigned char*)newPin, newPinLen); + if (newPinLen == -1) { + p11.setPin((unsigned char*)oldPin, oldPinLen, + (unsigned char*)newPin, newPinLen); + } + p11.logout(); } int pki_scard::verify() diff --git a/lib/pki_scard.h b/lib/pki_scard.h index 3bf35001..1cb0651d 100644 --- a/lib/pki_scard.h +++ b/lib/pki_scard.h @@ -32,7 +32,7 @@ class pki_scard: public pki_key virtual ~pki_scard(); static QPixmap *icon[1]; void load_token(pkcs11 &p11, CK_OBJECT_HANDLE object); - int init_p11engine(void) const; + static int init_p11engine(void); int prepare_card() const; void fromData(const unsigned char *p, db_header_t *head); unsigned char *toData(int *size); @@ -45,8 +45,10 @@ class pki_scard: public pki_key QString getCardLabel() const { return card_label; } EVP_PKEY *decryptKey() const; QString length(); + QString scardLogin(pkcs11 &p11, bool so, bool force=false)const; void changePin(); void initPin(); + void changeSoPin(); int verify(); bool isScard(); QVariant getIcon(); diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index ba8e14b2..b7bc16bf 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -8,8 +8,12 @@ #include "pki_x509.h" #include "pki_evp.h" +#include "pki_scard.h" #include "func.h" #include "base.h" +#include "exception.h" +#include "pass_info.h" +#include "widgets/MainWindow.h" #include QPixmap *pki_x509::icon[5] = { NULL, NULL, NULL, NULL, NULL }; @@ -172,6 +176,45 @@ void pki_x509::load_token(pkcs11 &p11, CK_OBJECT_HANDLE object) openssl_error(); } +void pki_x509::store_token() +{ + pki_scard *card = (pki_scard *)privkey; + int slot, size; + unsigned char*p, *p1; + QList objects; + + if (!privkey || !privkey->isScard()) + throw errorEx(tr("No associated Smart card")); + + slot = card->prepare_card(); + + size = i2d_X509(cert, NULL); + openssl_error(); + p = p1 = (unsigned char*)OPENSSL_malloc(size); + + i2d_X509(cert, &p1); + openssl_error(); + pk11_attr_data x509(CKA_VALUE); + x509.setValue(p, size); + free(p); + + pk11_attr_ulong class_att = pk11_attr_ulong(CKA_CLASS); + class_att.setValue(CKO_CERTIFICATE); + + pkcs11 p11; + p11.startSession(slot, true); + objects = p11.objectList(&class_att); + if (objects.count() == 0) + throw errorEx(tr("No certificate object found")); + if (objects.count() > 1) + throw errorEx(tr("More than one certificate objects found")); + + if (card->scardLogin(p11, false).isNull()) + return; + p11.storeAttribute(x509, objects[0]); + openssl_error(); +} + bool pki_x509::verifyQASerial(const a1int &secret) const { return getQASerial(secret) == getSerial(); @@ -329,8 +372,7 @@ unsigned char *pki_x509::toData(int *size) *size = i2d_X509(cert, NULL) + 11 + caSerial.toHex().length() + caTemplate.length() + crlExpiry.derSize() + revoked.derSize(); openssl_error(); - p = (unsigned char*)OPENSSL_malloc(*size); - p1 = p; + p = p1 = (unsigned char*)OPENSSL_malloc(*size); i2d_X509(cert, &p1); // cert db::intToData(&p1, trust); // trust diff --git a/lib/pki_x509.h b/lib/pki_x509.h index 84ca531c..d8e11cb2 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -44,6 +44,7 @@ class pki_x509 : public pki_x509super void fload(const QString fname); void load_token(pkcs11 &p11, CK_OBJECT_HANDLE object); + void store_token(); void fromPEM_BIO(BIO *bio, QString name); void writeDefault(const QString fname); a1int hashInfo(const EVP_MD *md) const; diff --git a/widgets/MainWindow.cpp b/widgets/MainWindow.cpp index 85dd1705..da010618 100644 --- a/widgets/MainWindow.cpp +++ b/widgets/MainWindow.cpp @@ -151,7 +151,7 @@ MainWindow::MainWindow(QWidget *parent ) homedir = getHomeDir(); init_curves(); - pkcs11::load_lib("", true); + pki_scard::init_p11engine(); // FIXME: Change pass isn't functional yet. BNchangePass->setDisabled(true); @@ -357,6 +357,9 @@ void MainWindow::importScard() pk11_attr_ulong class_att = pk11_attr_ulong(CKA_CLASS); p11_slots = p11.getSlotList(&num_slots); + if (num_slots == 0) + QMessageBox::warning(this, XCA_TITLE, + tr("No Smart card found")); for (i=0; i buflen) + return -1; + + for (int i=0; ihide(); } - if (dlg->exec()) { + while (dlg->exec()) { QString x = ui.pass->text(); if (ui.takeHex->isChecked()) { - // PARSE Hex string - abort(); + ret = hex2bin(x, buf, size); + if (ret != -1) + break; } else { strncpy(buf, x.toAscii(), size); ret = x.length(); + break; } + QMessageBox::warning(p->getWidget(), XCA_TITLE, hexwarn); } delete dlg; return ret; @@ -539,13 +564,24 @@ int MainWindow::passWrite(char *buf, int size, int, void *userdata) QString A = ui.passA->text(); QString B = ui.passB->text(); if (A == B) { - strncpy(buf, A.toAscii(), size); - ret = A.length(); - break; + if (ui.takeHex->isChecked()) { + ret = hex2bin(A, buf, size); + if (ret != -1) + break; + } else { + strncpy(buf, A.toAscii(), size); + ret = A.length(); + break; + } + QMessageBox::warning(p->getWidget(), XCA_TITLE, + hexwarn); } else { - QMessageBox::warning(p->getWidget(), tr(XCA_TITLE), p->getType() + tr(" missmatch")); + QMessageBox::warning(p->getWidget(), XCA_TITLE, + p->getType() + tr(" missmatch")); } } + for (int i=0; i