Allow loading more keys from single PKCS#11 module
This commit is contained in:
parent
077597136c
commit
42fe13ff31
@ -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();
|
||||
+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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user