diff --git a/src/eng_back.c b/src/eng_back.c index 33c04f47..5dc6dad9 100644 --- a/src/eng_back.c +++ b/src/eng_back.c @@ -391,7 +391,7 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, { PKCS11_SLOT *slot; PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL; - PKCS11_TOKEN *tok, *match_tok = NULL; + PKCS11_TOKEN *match_tok = NULL; unsigned int n, m; char *obj_id = NULL; size_t obj_id_len = 0; @@ -406,6 +406,10 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, if (object_uri && *object_uri) { obj_id_len = strlen(object_uri) + 1; obj_id = OPENSSL_malloc(obj_id_len); + if (!obj_id) { + ctx_log(ctx, 0, "Could not allocate memory for ID\n"); + goto cleanup; + } if (!strncasecmp(object_uri, "pkcs11:", 7)) { n = parse_pkcs11_uri(ctx, object_uri, &match_tok, obj_id, &obj_id_len, tmp_pin, &tmp_pin_len, &obj_label); @@ -415,12 +419,12 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, "The PKCS#11 URI format is defined by RFC7512\n", object_typestr); ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_ID); - goto error; + goto cleanup; } if (tmp_pin_len > 0 && tmp_pin[0] != 0) { tmp_pin[tmp_pin_len] = 0; if (!ctx_ctrl_set_pin(ctx, tmp_pin)) { - goto error; + goto cleanup; } } ctx_log(ctx, 1, "Looking in slots for %s %s login: ", @@ -436,7 +440,7 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, "still accepted for now\n", object_typestr); ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_ID); - goto error; + goto cleanup; } ctx_log(ctx, 1, "Looking in slot %d for %s %s login: ", slot_nr, object_typestr, login ? "with" : "without"); @@ -455,8 +459,8 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count, sizeof(PKCS11_SLOT *)); if (!matched_slots) { - ctx_log(ctx, 0, "Could not allocate memory for matched slots\n"); - goto error; + ctx_log(ctx, 0, "Could not allocate memory for slots\n"); + goto cleanup; } for (n = 0; n < ctx->slot_count; n++) { @@ -504,8 +508,9 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, } ctx_log(ctx, 1, "\n"); - /* Ignore slots without tokens or with uninitialized token */ - if (found_slot && found_slot->token && found_slot->token->initialized) { + /* Ignore slots without tokens. Thales HSM (and potentially + * other modules) allow objects on uninitialized tokens. */ + if (found_slot && found_slot->token) { matched_slots[matched_count] = found_slot; matched_count++; } @@ -516,73 +521,151 @@ static void *ctx_try_load_object(ENGINE_CTX *ctx, if (match_tok) { ctx_log(ctx, 0, "No matching initialized token was found for %s\n", object_typestr); - goto error; + goto cleanup; } /* If the legacy slot ID format was used */ if (slot_nr != -1) { ctx_log(ctx, 0, "The %s was not found on slot %d\n", object_typestr, slot_nr); - goto error; + goto cleanup; } else { found_slot = PKCS11_find_token(ctx->pkcs11_ctx, ctx->slot_list, ctx->slot_count); - /* Ignore if the the token is not initialized */ - if (found_slot && found_slot->token && - found_slot->token->initialized) { + /* Ignore slots without tokens. Thales HSM (and potentially + * other modules) allow objects on uninitialized tokens. */ + if (found_slot && found_slot->token) { matched_slots[matched_count] = found_slot; matched_count++; } else { ctx_log(ctx, 0, "No tokens found\n"); - goto error; + goto cleanup; } } } - for (n = 0; n < matched_count; n++) { - slot = matched_slots[n]; - tok = slot->token; - if (!tok) { - ctx_log(ctx, 0, "Empty slot found\n"); - break; - } + /* In several tokens certificates are marked as private */ + if (login) { + /* Only try to login if a single slot matched to avoiding trying + * the PIN against all matching slots */ - ctx_log(ctx, 1, "Found slot: %s\n", slot->description); - ctx_log(ctx, 1, "Found token: %s\n", slot->token->label); + if (matched_count == 1) { + slot = matched_slots[0]; + if (!slot->token) { + ctx_log(ctx, 0, "Empty slot found: %s\n", slot->description); + goto cleanup; /* failed */ + } + ctx_log(ctx, 1, "Found slot: %s\n", slot->description); + ctx_log(ctx, 1, "Found token: %s\n", slot->token->label[0]? + slot->token->label : "no label"); - /* In several tokens certificates are marked as private */ - if (login) { /* Only try to login if login is required */ - if (tok->loginRequired || ctx->force_login) { - /* Only try to login if a single slot matched to avoiding trying - * the PIN against all matching slots */ - if (matched_count == 1) { - if (!ctx_login(ctx, slot, tok, - ui_method, callback_data)) { + if (slot->token->loginRequired || ctx->force_login) { + if (!ctx_login(ctx, slot, slot->token, ui_method, callback_data)) { + ctx_log(ctx, 0, "Login to token failed, returning NULL...\n"); + goto cleanup; /* failed */ + } + } + } else { + /* Multiple matching slots */ + size_t init_count = 0; + size_t uninit_count = 0; + PKCS11_SLOT **init_slots = NULL, **uninit_slots = NULL; + + init_slots = (PKCS11_SLOT **)calloc(ctx->slot_count, sizeof(PKCS11_SLOT *)); + if (!init_slots) { + ctx_log(ctx, 0, "Could not allocate memory for slots\n"); + goto cleanup; /* failed */ + } + uninit_slots = (PKCS11_SLOT **)calloc(ctx->slot_count, sizeof(PKCS11_SLOT *)); + if (!uninit_slots) { + ctx_log(ctx, 0, "Could not allocate memory for slots\n"); + free(init_slots); + goto cleanup; /* failed */ + } + + for (m = 0; m < matched_count; m++) { + slot = matched_slots[m]; + if (!slot->token) { + ctx_log(ctx, 0, "Empty slot found: %s\n", slot->description); + continue; /* skipped */ + } + if (slot->token->initialized) { + init_slots[init_count] = slot; + init_count++; + } else { + uninit_slots[uninit_count] = slot; + uninit_count++; + } + } + + /* Initialized tokens */ + if (init_count == 1) { + slot = init_slots[0]; + ctx_log(ctx, 1, "Found slot: %s\n", slot->description); + ctx_log(ctx, 1, "Found token: %s\n", slot->token->label[0]? + slot->token->label : "no label"); + + /* Only try to login if login is required */ + if (slot->token->loginRequired || ctx->force_login) { + if (!ctx_login(ctx, slot, slot->token, ui_method, callback_data)) { ctx_log(ctx, 0, "Login to token failed, returning NULL...\n"); - goto error; + free(init_slots); + free(uninit_slots); + goto cleanup; /* failed */ } - } else { - ctx_log(ctx, 0, "Multiple matching slots (%zu); will not try to" - " login\n", matched_count); - for (m = 0; m < matched_count; m++){ - slot = matched_slots[m]; - ctx_log(ctx, 0, "- [%u] %s: %s\n", m + 1, - slot->description? slot->description: - "(no description)", - (slot->token && slot->token->label)? - slot->token->label: "no label"); + } + } else { + /* Multiple slots with initialized token */ + if (init_count > 1) { + ctx_log(ctx, 0, "Multiple matching slots (%zu);" + " will not try to login\n", init_count); + } + for (m = 0; m < init_count; m++) { + slot = init_slots[m]; + ctx_log(ctx, 0, "- [%u] %s: %s\n", m + 1, + slot->description? slot->description: + "(no description)", + (slot->token && slot->token->label)? + slot->token->label: "no label"); + } + free(init_slots); + + /* Uninitialized tokens, user PIN is unset */ + for (m = 0; m < uninit_count; m++) { + slot = uninit_slots[m]; + ctx_log(ctx, 1, "Found slot: %s\n", slot->description); + ctx_log(ctx, 1, "Found token: %s\n", slot->token->label[0]? + slot->token->label : "no label"); + object = match_func(ctx, slot->token, obj_id, obj_id_len, obj_label); + if (object) { + free(uninit_slots); + goto cleanup; /* success */ } - goto error; } + free(uninit_slots); + goto cleanup; /* failed */ } } + object = match_func(ctx, slot->token, obj_id, obj_id_len, obj_label); - object = match_func(ctx, tok, obj_id, obj_id_len, obj_label); - if (object) - break; + } else { + /* Find public object */ + for (n = 0; n < matched_count; n++) { + slot = matched_slots[n]; + if (!slot->token) { + ctx_log(ctx, 0, "Empty slot found: %s\n", slot->description); + break; + } + ctx_log(ctx, 1, "Found slot: %s\n", slot->description); + ctx_log(ctx, 1, "Found token: %s\n", slot->token->label[0]? + slot->token->label : "no label"); + object = match_func(ctx, slot->token, obj_id, obj_id_len, obj_label); + if (object) + break; /* success */ + } } -error: +cleanup: /* Free the searched token data */ if (match_tok) { OPENSSL_free(match_tok->model); diff --git a/src/p11_slot.c b/src/p11_slot.c index 9561bdeb..8da2810b 100644 --- a/src/p11_slot.c +++ b/src/p11_slot.c @@ -180,6 +180,10 @@ int pkcs11_get_session(PKCS11_SLOT_private *slot, int rw, CK_SESSION_HANDLE *ses slot->num_sessions++; break; } + if (rv == CKR_TOKEN_NOT_RECOGNIZED) { + pthread_mutex_unlock(&slot->lock); + return -1; + } /* Remember the maximum session count */ if (rv == CKR_SESSION_COUNT)