/* vi: set sw=4 ts=4: * * Copyright (C) 2001 - 2020 Christian Hohnstaedt. * * All rights reserved. */ #include "NewKey.h" #include "MainWindow.h" #include "lib/pki_evp.h" #include "lib/pkcs11.h" #include "distname.h" #include "clicklabel.h" #include "ItemCombo.h" #include #include #include #include keyjob NewKey::defaultjob("RSA:2048"); class keyListItem { public: bool card; keytype ktype; 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; } ktype = keytype::byMech(m); tkInfo ti = p11->tokenInfo(slot); #ifndef OPENSSL_NO_EC if (m == CKM_EC_KEY_PAIR_GEN) { 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(ktype.name). arg(minKeySize). arg(maxKeySize); card = true; } keyListItem(const keytype &t = keytype()) : ktype(t) { printname = ktype.name; card = false; slot = slotid(); minKeySize = 0; maxKeySize = INT_MAX; ec_flags = 0; } int type() const { return ktype.type; } }; Q_DECLARE_METATYPE(keyListItem); NewKey::NewKey(QWidget *parent, const QString &name) :QDialog(parent) { static const QList sizeList = { 1024, 2048, 4096, 8192 }; slotidList p11_slots; QList keytypes; setupUi(this); setWindowTitle(XCA_TITLE); image->setPixmap(QPixmap(":keyImg")); if (!name.isEmpty()) keyDesc->setText(name); keyLength->setEditable(true); foreach (int size, sizeList) keyLength->addItem(QString("%1 bit").arg(size)); foreach (const keytype t, keytype::types()) keytypes << keyListItem(t); updateCurves(); keyLength->setEditText(QString("%1 bit").arg(defaultjob.size)); keyDesc->setFocus(); if (pkcs11::libraries.loaded()) try { pkcs11 p11; p11_slots = p11.getSlotList(); foreach(slotid slot, p11_slots) { QList ml = p11.mechanismList(slot); foreach(keytype t, keytype::types()) if (ml.contains(t.mech)) keytypes << keyListItem(&p11, slot, t.type); } } catch (errorEx &err) { p11_slots.clear(); } for (int i=0; iaddItem(keytypes[i].printname, q); if (!keytypes[i].card && keytypes[i].type() == defaultjob.ktype.type) { keyType->setCurrentIndex(i); } } buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Create")); } void NewKey::addCurveBoxCurves(const QList &curves) { foreach(builtin_curve curve, curves) { QString sn(OBJ_nid2sn(curve.nid)); QString p, comment = curve.comment; if (comment.isEmpty()) comment = "---"; p = sn + ": " + comment; curveBox->addItem(sn + ": " + comment, curve.nid); } } void NewKey::updateCurves(unsigned min, unsigned max, unsigned long ec_flags) { #ifndef OPENSSL_NO_EC QList curve_rfc5480, curve_x962, curve_other; foreach(builtin_curve curve, builtinCurves) { const char *sn = OBJ_nid2sn(curve.nid); if (!sn || curve.order_size < min || curve.order_size > max) continue; if (ec_flags && (curve.type & ec_flags) == 0) continue; switch (curve.flags) { case CURVE_RFC5480: curve_rfc5480 << curve; break; case CURVE_X962: curve_x962 << curve; break; case CURVE_OTHER: curve_other << curve; break; } } curveBox->clear(); addCurveBoxCurves(curve_rfc5480); curveBox->insertSeparator(curveBox->count()); addCurveBoxCurves(curve_x962); curveBox->insertSeparator(curveBox->count()); addCurveBoxCurves(curve_other); int default_index = curveBox->findData(QVariant(defaultjob.ec_nid)); curveBox->setCurrentIndex(default_index == -1 ? 0 : default_index); #else (void)min; (void)max; (void)ec_flags; #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); } } keyjob NewKey::getKeyJob() const { keyjob job; keyListItem selected = keyType->itemData(keyType->currentIndex()) .value(); job.ktype = selected.ktype; if (job.isEC()) { int idx = curveBox->currentIndex(); job.ec_nid = curveBox->itemData(idx).toInt(); } else { QString size = keyLength->currentText(); size.replace(QRegExp("[^0-9]"), ""); job.size = size.toInt(); } job.slot = selected.slot; return job; } void NewKey::accept() { if (rememberDefault->isChecked()) { defaultjob = getKeyJob(); Settings["defaultkey"] = defaultjob.toString(); } QDialog::accept(); }