Allow loading more keys from single PKCS#11 module

This commit is contained in:
Jakub Jelen 2018-02-28 17:05:19 +01:00
parent 077597136c
commit 42fe13ff31

View File

@ -4471,3 +4471,295 @@ diff -up openssh-7.6p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-7.6p1/ssh-pkcs11-uri.
+struct pkcs11_uri *pkcs11_uri_init(); +struct pkcs11_uri *pkcs11_uri_init();
+char * pkcs11_uri_get(struct pkcs11_uri *uri); +char * pkcs11_uri_get(struct pkcs11_uri *uri);
+ +
commit 8cd98e76449fc112685882009c95e49eb555094a
Author: Jakub Jelen <jjelen@redhat.com>
Date: Wed Feb 28 16:58:07 2018 +0100
Allow to load multiple keys from a single pkcs11_module
diff --git a/ssh-pkcs11-uri.c b/ssh-pkcs11-uri.c
index 35ed6a09..da15c164 100644
--- a/ssh-pkcs11-uri.c
+++ b/ssh-pkcs11-uri.c
@@ -383,7 +383,7 @@ pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11)
rv = -1;
}
percent_decode(tok + key_len, &pkcs11->module_path);
- debug3("%s: Setting PKCS11Provider = %s from PKCS#11 URI\n",
+ debug3("%s: Setting PKCS11Provider = %s from PKCS#11 URI",
__func__, pkcs11->module_path);
/* } else if ( pin-value ) { */
} else {
diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index f54d905e..c9a79176 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -187,8 +187,8 @@ pkcs11_provider_lookup(char *provider_id)
struct pkcs11_provider *p;
TAILQ_FOREACH(p, &pkcs11_providers, next) {
- debug("check %p %s", p, p->name);
- if (!strcmp(provider_id, p->name))
+ debug("check %p %s", p, p->module_path);
+ if (!strcmp(provider_id, p->module_path))
return (p);
}
return (NULL);
@@ -232,7 +232,7 @@ pkcs11_del_provider_by_uri(struct pkcs11_uri *uri)
debug3("%s(%s): called", __func__, provider_uri);
- if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) {
+ if ((p = pkcs11_provider_lookup(uri->module_path)) != NULL) {
TAILQ_REMOVE(&pkcs11_providers, p, next);
pkcs11_provider_finalize(p);
pkcs11_provider_unref(p);
@@ -707,42 +707,42 @@ pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
return rv;
}
-int
-pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp)
+struct pkcs11_provider *
+pkcs11_provider_initialize(struct pkcs11_uri *uri)
{
- int nkeys, need_finalize = 0;
- struct pkcs11_provider *p = NULL;
+ int need_finalize = 0;
void *handle = NULL;
CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
CK_RV rv;
CK_FUNCTION_LIST *f = NULL;
CK_TOKEN_INFO *token;
CK_ULONG i;
- char *provider_id = NULL;
- char *provider_uri = pkcs11_uri_get(uri);
-
- debug("%s: called, provider_uri = %s", __func__, provider_uri);
+ char *provider_module = NULL;
+ struct pkcs11_provider *p;
/* if no provider specified, fallback to p11-kit */
if (uri->module_path == NULL) {
#ifdef PKCS11_DEFAULT_PROVIDER
- provider_id = strdup(PKCS11_DEFAULT_PROVIDER);
+ provider_module = strdup(PKCS11_DEFAULT_PROVIDER);
#else
error("%s: No module path provided", __func__);
goto fail;
#endif
} else
- provider_id = strdup(uri->module_path);
+ provider_module = strdup(uri->module_path);
- *keyp = NULL;
- if (pkcs11_provider_lookup(provider_uri) != NULL) {
- debug("%s: provider already registered: %s",
- __func__, provider_uri);
- goto fail;
+ if ((p = pkcs11_provider_lookup(provider_module)) != NULL) {
+ debug("%s: provider already initialized: %s",
+ __func__, provider_module);
+ p->refcount++;
+ /* Skip the initialization -- rereading the slot list would
+ * be more complicated job */
+ return p;
}
+
/* open shared pkcs11-libarary */
- if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
- error("dlopen %s failed: %s", provider_id, dlerror());
+ if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) {
+ error("dlopen %s failed: %s", provider_module, dlerror());
goto fail;
}
if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
@@ -750,25 +750,25 @@ pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***k
goto fail;
}
p = xcalloc(1, sizeof(*p));
- p->name = provider_uri;
- p->module_path = provider_id;
+ p->name = pkcs11_uri_get(uri);;
+ p->module_path = provider_module;
p->handle = handle;
/* setup the pkcs11 callbacks */
if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
error("C_GetFunctionList for provider %s failed: %lu",
- provider_uri, rv);
+ provider_module, rv);
goto fail;
}
p->function_list = f;
if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
error("C_Initialize for provider %s failed: %lu",
- provider_uri, rv);
+ provider_module, rv);
goto fail;
}
need_finalize = 1;
if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
error("C_GetInfo for provider %s failed: %lu",
- provider_uri, rv);
+ provider_module, rv);
goto fail;
}
rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
@@ -781,50 +781,91 @@ pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***k
rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
" libraryDescription <%s> libraryVersion %d.%d",
- provider_uri,
+ provider_module,
p->info.manufacturerID,
p->info.cryptokiVersion.major,
p->info.cryptokiVersion.minor,
p->info.libraryDescription,
p->info.libraryVersion.major,
p->info.libraryVersion.minor);
+
if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
error("C_GetSlotList failed: %lu", rv);
goto fail;
}
if (p->nslots == 0) {
debug("%s: provider %s returned no slots", __func__,
- provider_uri);
+ provider_module);
goto fail;
}
p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
!= CKR_OK) {
error("C_GetSlotList for provider %s failed: %lu",
- provider_uri, rv);
+ provider_module, rv);
goto fail;
}
p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
p->valid = 1;
- nkeys = 0;
+
for (i = 0; i < p->nslots; i++) {
token = &p->slotinfo[i].token;
if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
!= CKR_OK) {
error("C_GetTokenInfo for provider %s slot %lu "
- "failed: %lu", provider_uri, (unsigned long)i, rv);
+ "failed: %lu", provider_module, (unsigned long)i, rv);
continue;
}
if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
- debug2("%s: ignoring uninitialised token in "
- "provider %s slot %lu", __func__,
- provider_uri, (unsigned long)i);
continue;
}
rmspace(token->label, sizeof(token->label));
rmspace(token->manufacturerID, sizeof(token->manufacturerID));
rmspace(token->model, sizeof(token->model));
rmspace(token->serialNumber, sizeof(token->serialNumber));
+ }
+
+ /* insert unconditionally -- remove if there will be no keys later */
+ TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
+ p->refcount++; /* add to provider list */
+ return p;
+
+fail:
+ if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
+ error("C_Finalize for provider %s failed: %lu",
+ provider_module, rv);
+ if (handle)
+ dlclose(handle);
+ return NULL;
+}
+
+int
+pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp)
+{
+ int nkeys;
+ struct pkcs11_provider *p = NULL;
+ CK_TOKEN_INFO *token;
+ CK_ULONG i;
+ char *provider_uri = pkcs11_uri_get(uri);
+
+ debug("%s: called, provider_uri = %s", __func__, provider_uri);
+
+ *keyp = NULL;
+ if ((p = pkcs11_provider_initialize(uri)) == NULL) {
+ debug("%s: failed to initialize provider: %s",
+ __func__, provider_uri);
+ goto fail;
+ }
+
+ nkeys = 0;
+ for (i = 0; i < p->nslots; i++) {
+ token = &p->slotinfo[i].token;
+ if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
+ debug2("%s: ignoring uninitialised token in "
+ "provider %s slot %lu", __func__,
+ provider_uri, (unsigned long)i);
+ continue;
+ }
if (uri->token != NULL &&
strcmp(token->label, uri->token) != 0) {
debug2("%s: ignoring token not matching label (%s) "
@@ -845,29 +887,21 @@ pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***k
provider_uri, (unsigned long)i,
token->label, token->manufacturerID, token->model,
token->serialNumber, token->flags);
- /* open session, login with pin and retrieve public keys */
- if (pkcs11_open_session(p, i, pin) == 0)
+ /* open session if not yet opened, login with pin
+ * and retrieve public keys */
+ if ((p->slotinfo[i].session != 0) ||
+ pkcs11_open_session(p, i, pin) == 0)
pkcs11_fetch_keys(p, i, keyp, &nkeys, uri);
}
if (nkeys > 0) {
- TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
- p->refcount++; /* add to provider list */
return (nkeys);
}
debug("%s: provider %s returned no keys", __func__, provider_uri);
/* don't add the provider, since it does not have any keys */
fail:
- if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
- error("C_Finalize for provider %s failed: %lu",
- provider_uri, rv);
if (p) {
- free(p->slotlist);
- free(p->slotinfo);
- free(p);
+ pkcs11_provider_unref(p);
}
- if (handle)
- dlclose(handle);
- free(provider_id);
free(provider_uri);
return (-1);
}
diff --git a/ssh.c b/ssh.c
index 120e1ec4..92bb6a20 100644
--- a/ssh.c
+++ b/ssh.c
@@ -2017,8 +2017,7 @@ load_pkcs11_identity(char *pkcs11_uri, char *identity_files[],
if (options.pkcs11_provider != NULL && uri->module_path == NULL)
uri->module_path = strdup(options.pkcs11_provider);
- if (pkcs11_init(!options.batch_mode) == 0 &&
- options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
+ if (options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
(nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) {
for (i = 0; i < nkeys; i++) {
if (*n_ids >= SSH_MAX_IDENTITY_FILES) {
@@ -2057,6 +2056,8 @@ load_public_identity_files(struct passwd *pw)
#ifdef ENABLE_PKCS11
/* handle fallback from PKCS11Provider option */
+ pkcs11_init(!options.batch_mode);
+
if (options.pkcs11_provider != NULL) {
struct pkcs11_uri *uri;