diff --git a/lib/hx509/ks_p11.c b/lib/hx509/ks_p11.c index bfe092106..63017002b 100644 --- a/lib/hx509/ks_p11.c +++ b/lib/hx509/ks_p11.c @@ -48,6 +48,11 @@ struct p11_slot { char *name; hx509_certs certs; char *pin; + struct { + CK_MECHANISM_TYPE_PTR list; + CK_ULONG num; + CK_MECHANISM_INFO_PTR *infos; + } mechs; }; struct p11_module { @@ -224,6 +229,70 @@ static const RSA_METHOD rsa_pkcs1_method = { * */ +static int +p11_mech_info(hx509_context context, + struct p11_module *p, + struct p11_slot *slot, + int num) +{ + CK_ULONG i; + int ret; + + ret = P11FUNC(p, GetMechanismList, (slot->id, NULL_PTR, &i)); + if (ret) { + hx509_set_error_string(context, 0, EINVAL, + "Failed to get mech list count for slot %d", + num); + return EINVAL; + } + if (i == 0) { + hx509_set_error_string(context, 0, EINVAL, + "no mech supported for slot %d", num); + return EINVAL; + } + slot->mechs.list = calloc(i, sizeof(slot->mechs.list[0])); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + slot->mechs.num = i; + ret = P11FUNC(p, GetMechanismList, (slot->id, slot->mechs.list, &i)); + if (ret) { + hx509_set_error_string(context, 0, EINVAL, + "Failed to get mech list for slot %d", + num); + return EINVAL; + } + assert(i == slot->mechs.num); + + slot->mechs.infos = calloc(i, sizeof(*slot->mechs.infos)); + if (slot->mechs.list == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + + for (i = 0; i < slot->mechs.num; i++) { + slot->mechs.infos[i] = calloc(1, sizeof(*(slot->mechs.infos[0]))); + if (slot->mechs.infos[i] == NULL) { + hx509_set_error_string(context, 0, ENOMEM, + "out of memory"); + return ENOMEM; + } + ret = P11FUNC(p, GetMechanismInfo, (slot->id, slot->mechs.list[i], + slot->mechs.infos[i])); + if (ret) { + hx509_set_error_string(context, 0, EINVAL, + "Failed to get mech info for slot %d", + num); + return EINVAL; + } + } + + return 0; +} + static int p11_init_slot(hx509_context context, struct p11_module *p, @@ -281,7 +350,13 @@ p11_init_slot(hx509_context context, num); return ret; } + + ret = p11_mech_info(context, p, slot, num); + if (ret) + goto out; + ret = p11_list_keys(context, p, slot, session, lock, &slot->certs); + out: p11_put_session(p, slot, session); return ret; @@ -535,9 +610,12 @@ collect_private_key(struct p11_module *p, struct p11_slot *slot, rsa->n = getattr_bn(p, slot, session, object, CKA_MODULUS); if (rsa->n == NULL) _hx509_abort("CKA_MODULUS missing"); + /* + * The exponent should always be present according to the pkcs11 + * specification, but some smartcards leaves it out, let ignore + * any failure to fetch it. + */ rsa->e = getattr_bn(p, slot, session, object, CKA_PUBLIC_EXPONENT); - if (rsa->e == NULL) - _hx509_abort("CKA_PUBLIC_EXPONENT missing"); p11rsa = calloc(1, sizeof(*p11rsa)); if (p11rsa == NULL) @@ -821,6 +899,7 @@ static void p11_release_module(struct p11_module *p) { int i; + if (p->refcount == 0) _hx509_abort("pkcs11 refcount to low"); if (--p->refcount > 0) @@ -838,6 +917,17 @@ p11_release_module(struct p11_module *p) memset(p->slot[i].pin, 0, strlen(p->slot[i].pin)); free(p->slot[i].pin); } + if (p->slot[i].mechs.num) { + free(p->slot[i].mechs.list); + + if (p->slot[i].mechs.infos) { + int j; + + for (j = 0 ; j < p->slot[i].mechs.num ; j++) + free(p->slot[i].mechs.infos[i]); + free(p->slot[i].mechs.infos); + } + } free(p->slot); } memset(p, 0, sizeof(*p)); @@ -915,6 +1005,70 @@ p11_iter_end(hx509_context context, return ret; } +static struct units mechflags[] = { + {"derive", 0x80000 }, + {"unwrap", 0x40000 }, + {"wrap", 0x20000 }, + {"genereate-key-pair", 0x10000 }, + {"generate", 0x08000 }, + {"verify-recover", 0x04000 }, + {"verify", 0x02000 }, + {"sign-recover", 0x01000 }, + {"sign", 0x00800 }, + {"digest", 0x00400 }, + {"decrypt", 0x00200 }, + {"encrypt", 0x00100 }, + {"hw", 0x00001 }, + { NULL, 0x00000 } +}; + +static int +p11_printinfo(hx509_context context, + hx509_certs certs, + void *data, + int (*func)(void *, char *), + void *ctx) +{ + struct p11_module *p = data; + int i, j; + + _hx509_pi_printf(func, ctx, "pkcs11 driver with %d slots", p->num_slots); + + for (i = 0; i < p->num_slots; i++) { + struct p11_slot *s = &p->slot[i]; + + _hx509_pi_printf(func, ctx, "slot %d: id: %d name: %s flags: %08x", + i, (int)s->id, s->name, s->flags); + + _hx509_pi_printf(func, ctx, "number of supported mechanisms: %lu", + (unsigned long)s->mechs.num); + for (j = 0; j < s->mechs.num; j++) { + const char *mechname = "unknown"; + char flags[256]; +#define MECHNAME(s,n) case s: mechname = n; break + switch(s->mechs.list[j]) { + MECHNAME(CKM_RSA_PKCS_KEY_PAIR_GEN, "rsa-pkcs-key-pair-gen"); + MECHNAME(CKM_RSA_PKCS, "rsa-pkcs"); + MECHNAME(CKM_RSA_X_509, "rsa-x-509"); + MECHNAME(CKM_MD5_RSA_PKCS, "md5-rsa-pkcs"); + MECHNAME(CKM_SHA1_RSA_PKCS, "sha1-rsa-pkcs"); + } +#undef MECHNAME + unparse_flags(s->mechs.infos[j]->flags, mechflags, + flags, sizeof(flags)); + + _hx509_pi_printf(func, ctx, + " %lu (%s) flags: (0x%08x) %s", + (unsigned long)s->mechs.list[j], + mechname, + (unsigned long)s->mechs.infos[j]->flags, + flags); + } + } + + return 0; +} + static struct hx509_keyset_ops keyset_pkcs11 = { "PKCS11", 0, @@ -924,7 +1078,8 @@ static struct hx509_keyset_ops keyset_pkcs11 = { NULL, p11_iter_start, p11_iter, - p11_iter_end + p11_iter_end, + p11_printinfo }; void