/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2014 Christian Hohnstaedt. * * All rights reserved. */ #include "NewKey.h" #include "MainWindow.h" #include "lib/pki_evp.h" #include "widgets/distname.h" #include "widgets/clicklabel.h" #include "lib/pkcs11.h" #include #include #include #include struct typelist { const char *name; int type; }; static const struct typelist typeList[] = { { "RSA", EVP_PKEY_RSA }, { "DSA", EVP_PKEY_DSA }, #ifndef OPENSSL_NO_EC { "EC", EVP_PKEY_EC }, #endif }; int NewKey::defaultType = EVP_PKEY_RSA; int NewKey::defaultEcNid = NID_undef; int NewKey::defaultSize = 2048; class keyListItem { protected: const struct typelist *tl; public: bool card; QString printname; slotid slot; unsigned minKeySize; unsigned maxKeySize; unsigned long ec_flags; keyListItem(pkcs11 *p11, slotid nslot, CK_MECHANISM_TYPE m) { slot = nslot; CK_MECHANISM_INFO mechinfo; p11->mechanismInfo(slot, m, &mechinfo); minKeySize = mechinfo.ulMinKeySize; maxKeySize = mechinfo.ulMaxKeySize; if (maxKeySize == 0) { /* Fallback for libraries not filling in the maxKeySize */ maxKeySize = INT_MAX; } tkInfo ti = p11->tokenInfo(slot); switch (m) { case CKM_RSA_PKCS_KEY_PAIR_GEN: tl = typeList; //idx of EVP_PKEY_RSA break; case CKM_DSA_KEY_PAIR_GEN: tl = typeList +1; break; #ifndef OPENSSL_NO_EC case CKM_EC_KEY_PAIR_GEN: tl = typeList +2; CK_MECHANISM_INFO info; p11->mechanismInfo(slot, m, &info); ec_flags = info.flags & (CKF_EC_F_P | CKF_EC_F_2M); if (!ec_flags) { /* Fallback: Assume to support both for * libraries leaving this flag empty */ ec_flags = CKF_EC_F_P | CKF_EC_F_2M; } } #endif printname = QString("%1 #%2 (%3 Key of %4 - %5 bits)"). arg(ti.label()).arg(ti.serial()). arg(tl->name). arg(minKeySize). arg(maxKeySize); card = true; } keyListItem(const struct typelist *t=typeList) { tl = t; printname = QString(tl->name); card = false; slot = slotid(); minKeySize = 0; maxKeySize = INT_MAX; ec_flags = 0; } keyListItem(const keyListItem &k) { tl = k.tl; printname = k.printname; card = k.card; slot = k.slot; minKeySize = k.minKeySize; maxKeySize = k.maxKeySize; ec_flags = k.ec_flags; } int type() { return tl->type; } QString typeName() { return QString(tl->name); } }; Q_DECLARE_METATYPE(keyListItem); NewKey::NewKey(QWidget *parent, QString name) :QDialog(parent) { static const char* const sizeList[] = { "1024", "2048", "4096" }; size_t i; slotidList p11_slots; QList keytypes; setupUi(this); setWindowTitle(tr(XCA_TITLE)); image->setPixmap(*MainWindow::keyImg); if (!name.isEmpty()) keyDesc->setText(name); keyLength->setEditable(true); for (i=0; i < ARRAY_SIZE(sizeList); i++ ) { keyLength->addItem(QString(sizeList[i]) + " bit"); } for (i=0; i < ARRAY_SIZE(typeList); i++ ) { keyListItem gk(typeList +i); keytypes << gk; } updateCurves(); keyLength->setEditText(QString::number(defaultSize) + " bit"); keyDesc->setFocus(); if (pkcs11::loaded()) try { pkcs11 p11; p11_slots = p11.getSlotList(); foreach(slotid slot, p11_slots) { QList ml = p11.mechanismList(slot); if (ml.contains(CKM_RSA_PKCS_KEY_PAIR_GEN)) { keyListItem tk(&p11, slot, CKM_RSA_PKCS_KEY_PAIR_GEN); keytypes << tk; } if (ml.contains(CKM_DSA_KEY_PAIR_GEN)) { keyListItem tk(&p11, slot, CKM_DSA_KEY_PAIR_GEN); keytypes << tk; } #ifndef OPENSSL_NO_EC if (ml.contains(CKM_EC_KEY_PAIR_GEN)) { keyListItem tk(&p11, slot, CKM_EC_KEY_PAIR_GEN); keytypes << tk; } #endif } } catch (errorEx &err) { p11_slots.clear(); } for (int i=0; iaddItem(keytypes[i].printname, q); if (!keytypes[i].card && keytypes[i].type() == defaultType) keyType->setCurrentIndex(i); } buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create")); } void NewKey::updateCurves(unsigned min, unsigned max, unsigned long ec_flags) { #ifndef OPENSSL_NO_EC QString ec_default; QStringList curve_x962, curve_other; foreach(builtin_curve curve, pki_key::builtinCurves) { const char *sn = OBJ_nid2sn(curve.nid); QString comment = curve.comment; if (!sn || curve.order_size < min || curve.order_size > max) continue; if (ec_flags) { if ((curve.type & ec_flags) == 0) continue; } if (comment.isEmpty()) comment = "---"; QString p = QString(sn) + ": " + comment; if (curve.nid == defaultEcNid) ec_default = p; switch (curve.flags) { case CURVE_X962: curve_x962 << p; break; case CURVE_OTHER: curve_other << p; break; } } curveBox->clear(); curveBox->addItems(curve_x962); curveBox->addItems(curve_other); curveBox->setCurrentIndex(curveBox->findText(ec_default)); if (curveBox->currentIndex() == -1) curveBox->setCurrentIndex(0); #endif } void NewKey::on_keyType_currentIndexChanged(int idx) { bool curve_enabled; keyListItem ki = keyType->itemData(idx).value(); curve_enabled = (ki.type() == EVP_PKEY_EC); curveBox->setVisible(curve_enabled); curveLabel->setVisible(curve_enabled); keySizeLabel->setVisible(!curve_enabled); keyLength->setVisible(!curve_enabled); rememberDefault->setEnabled(!ki.card); if (curve_enabled && ki.card) { updateCurves(ki.minKeySize, ki.maxKeySize, ki.ec_flags); } } static keyListItem currentKey(QComboBox *keyType) { QVariant q = keyType->itemData(keyType->currentIndex()); return q.value(); } int NewKey::getKeytype() { return currentKey(keyType).type(); } int NewKey::getKeysize() { if (getKeytype() == EVP_PKEY_EC) return -1; QString size = keyLength->currentText(); size.replace(QRegExp("[^0-9]"), ""); return size.toInt(); } int NewKey::getKeyCurve_nid() { if (getKeytype() != EVP_PKEY_EC) return NID_undef; QString desc = curveBox->currentText(); desc.replace(QRegExp("^(X9.62) "), ""); desc.replace(QRegExp(":.*"), ""); return OBJ_sn2nid(CCHAR(desc)); } bool NewKey::isToken() { keyListItem k = currentKey(keyType); return k.card; } slotid NewKey::getKeyCardSlot() { keyListItem k = currentKey(keyType); return k.slot; } QString NewKey::getAsString() { keyListItem k = currentKey(keyType); QString data; if (k.card) return QString(); if (k.type() == EVP_PKEY_EC) { data = OBJ_obj2QString(OBJ_nid2obj(getKeyCurve_nid()), 1); } else { data = QString::number(getKeysize()); } return QString("%1:%2").arg(currentKey(keyType).typeName()).arg(data); } int NewKey::setDefault(QString def) { int type = -1, size = 0, nid = NID_undef; QStringList sl = def.split(':'); if (sl.size() != 2) return -1; for (unsigned i=0; i < ARRAY_SIZE(typeList); i++ ) { if (sl[0] == typeList[i].name) { type = typeList[i].type; } } if (type == -1) return -2; if (type == EVP_PKEY_EC) { nid = OBJ_txt2nid(sl[1].toAscii()); if (nid == NID_undef) return -3; defaultEcNid = nid; } else { size = sl[1].toInt(); if (size <= 0) return -4; defaultSize = size; } defaultType = type; return 0; }