From 4b379020524447bdb85a2d07d5ffbc635d043f20 Mon Sep 17 00:00:00 2001 From: Christian Hohnstaedt Date: Wed, 28 Feb 2024 21:59:41 +0100 Subject: [PATCH] Yubikey select one of the special IDs Yubikey defines and enforces 4 (NEO) or 24 (YubiKey YK4, YubiKey YK5) slots with special, fixed names. Add a dropdown box if "fixed_ids" are present and let the user select the slot during key generation. --- lib/pkcs11.cpp | 10 ++++------ lib/pkcs11.h | 29 ++++++++++++++++++++++++++++- lib/pki_scard.cpp | 40 ++++++++++++++++++++++++++++++++++------ lib/pki_scard.h | 1 + 4 files changed, 67 insertions(+), 13 deletions(-) diff --git a/lib/pkcs11.cpp b/lib/pkcs11.cpp index 0037cef5..dd85ecc9 100644 --- a/lib/pkcs11.cpp +++ b/lib/pkcs11.cpp @@ -480,7 +480,7 @@ pk11_attr_data pkcs11::findUniqueID(unsigned long oclass) const } pk11_attr_data pkcs11::generateKey(QString name, unsigned long mech, - unsigned long bits, int nid) + unsigned long bits, int nid, const pk11_attr_data &id) { #ifdef OPENSSL_NO_EC (void)nid; @@ -492,9 +492,7 @@ pk11_attr_data pkcs11::generateKey(QString name, unsigned long mech, CK_MECHANISM mechanism = {mech, NULL_PTR, 0}; pk11_attr_data label(CKA_LABEL, name.toUtf8()); - pk11_attr_data new_id = findUniqueID(CKO_PUBLIC_KEY); - - pub_atts << label << new_id << + pub_atts << label << id << pk11_attr_ulong(CKA_CLASS, CKO_PUBLIC_KEY) << pk11_attr_bool(CKA_TOKEN, true) << pk11_attr_bool(CKA_PRIVATE, false) << @@ -502,7 +500,7 @@ pk11_attr_data pkcs11::generateKey(QString name, unsigned long mech, pk11_attr_bool(CKA_VERIFY, true) << pk11_attr_bool(CKA_WRAP, true); - priv_atts << label << new_id << + priv_atts << label << id << pk11_attr_ulong(CKA_CLASS, CKO_PRIVATE_KEY) << pk11_attr_bool(CKA_TOKEN, true) << pk11_attr_bool(CKA_PRIVATE, true) << @@ -571,7 +569,7 @@ pk11_attr_data pkcs11::generateKey(QString name, unsigned long mech, if (rv != CKR_OK) { pk11error("C_GenerateKeyPair", rv); } - return new_id; + return id; } QList pkcs11::objectList(pk11_attlist &atts) const diff --git a/lib/pkcs11.h b/lib/pkcs11.h index ff66b083..ff760d10 100644 --- a/lib/pkcs11.h +++ b/lib/pkcs11.h @@ -114,6 +114,32 @@ public: // issue to generate Domain Parameters return manufacturerID() == "nCipher Corp. Ltd"; } + QList fixed_ids() const + { + // Yubi keys have fixed set of IDs + // Use QStringList to not invent a new type: (QString + unsigned) + static const QList ids { + { "9a: PIV Authentication", "1" }, + { "9c: Digital Signature", "2" }, + { "9d: Key Management", "3" }, + { "9e: Card Authentication", "4" } + }; + if (manufacturerID() == "Yubico (www.yubico.com)") { + if (model() == "YubiKey NEO") + return ids; + if (model() == "YubiKey YK4" || model() == "YubiKey YK5") { + QList retired(ids); + for (int i=0; i< 20; i++) + retired.append(QStringList { + QString("%1: Retired Key %2") + .arg(i+0x82, 0, 16).arg(i+1), + QString::number(i + 5) + }); + return retired; + } + } + return QList(); + } }; class pkcs11 @@ -177,7 +203,8 @@ class pkcs11 CK_OBJECT_HANDLE createObject(pk11_attlist &attrs); pk11_attr_data findUniqueID(unsigned long oclass) const; pk11_attr_data generateKey(QString name, - unsigned long ec_rsa_mech, unsigned long bits, int nid); + unsigned long ec_rsa_mech, unsigned long bits, int nid, + const pk11_attr_data &id); int deleteObjects(QList objects); EVP_PKEY *getPrivateKey(EVP_PKEY *pub, CK_OBJECT_HANDLE obj); int encrypt(int flen, const unsigned char *from, diff --git a/lib/pki_scard.cpp b/lib/pki_scard.cpp index ef22bf5b..685e02a0 100644 --- a/lib/pki_scard.cpp +++ b/lib/pki_scard.cpp @@ -19,6 +19,7 @@ #include "XcaWarningCore.h" #include +#include void pki_scard::init(void) { @@ -450,7 +451,7 @@ void pki_scard::store_token(const slotid &slot, EVP_PKEY *pkey) load_token(p11, objs[0]); return; } - pk11_attr_data new_id = p11.findUniqueID(CKO_PUBLIC_KEY); + pk11_attr_data new_id = select_id(p11); pub_atts << new_id << pk11_attr_bool(CKA_TOKEN, true) << @@ -654,25 +655,50 @@ class keygenThread: public QThread { public: errorEx err; - pk11_attr_data id; const keyjob task; QString name; pkcs11 *p11; + pk11_attr_data id; - keygenThread(const keyjob &t, const QString &n, pkcs11 *_p11) - : QThread(), task(t), name(n), p11(_p11) { } + keygenThread(const keyjob &t, const QString &n, pkcs11 *_p11, + const pk11_attr_data &_id) + : QThread(), task(t), name(n), p11(_p11), id(_id) { } void run() { try { id = p11->generateKey(name, task.ktype.mech, task.size, - task.ec_nid); + task.ec_nid, id); } catch (errorEx &e) { err = e; } } }; +pk11_attr_data pki_scard::select_id(const pkcs11 &p11) const +{ + tkInfo ti = p11.tokenInfo(); + pk11_attr_data new_id(CKA_ID); + + QList fixed_ids = ti.fixed_ids(); + if (fixed_ids.size() > 0) { + QMap map; + QStringList items; + for (QStringList item : fixed_ids) { + items << item[0]; + map[item[0]] = item[1].toULong(); + } + QString idname = QInputDialog::getItem(nullptr, XCA_TITLE, + tr("Select Slot of %1").arg(ti.model()), + items, 0, false); + if (map.contains(idname)) + new_id.setULong(map[idname]); + } else { + new_id = p11.findUniqueID(CKO_PUBLIC_KEY); + } + return new_id; +} + void pki_scard::generate(const keyjob &task) { pk11_attlist atts; @@ -681,11 +707,13 @@ void pki_scard::generate(const keyjob &task) p11.startSession(task.slot, true); p11.getRandom(); + pk11_attr_data new_id = select_id(p11); + if (!p11.tokenLoginForModification()) return; XcaProgress progress; - keygenThread kt(task, getIntName(), &p11); + keygenThread kt(task, getIntName(), &p11, new_id); kt.start(); while (!kt.wait(20)) { progress.increment(); diff --git a/lib/pki_scard.h b/lib/pki_scard.h index c7ca710b..d65831bb 100644 --- a/lib/pki_scard.h +++ b/lib/pki_scard.h @@ -79,6 +79,7 @@ class pki_scard: public pki_key { return mech_list; } + pk11_attr_data select_id(const pkcs11 &p11) const; pk11_attlist objectAttributes(bool priv) const; pk11_attlist objectAttributesNoId(EVP_PKEY *pk, bool priv) const; void setMech_list(QList ml) { mech_list = ml; };