diff --git a/openssh-7.6p1-pkcs11-uri.patch b/openssh-7.6p1-pkcs11-uri.patch index 2a702ed..266063f 100644 --- a/openssh-7.6p1-pkcs11-uri.patch +++ b/openssh-7.6p1-pkcs11-uri.patch @@ -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 +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; +