openssl-pkcs11/SOURCES/openssl-pkcs11-0.4.10-search-objects-in-all-matching-tokens.patch
2021-09-09 23:20:00 +00:00

930 lines
30 KiB
Diff

From 3e219e92aecad385ba003c2276d58db3e80387cc Mon Sep 17 00:00:00 2001
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Date: Thu, 5 Sep 2019 18:29:53 +0200
Subject: [PATCH 1/4] tests/rsa-common: Add function to create various tokens
This allows the creation of multiple devices in the test scripts.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 712e869189610f900ebf8c50090e228167b6bf8f)
---
tests/rsa-common.sh | 54 +++++++++++++++++++++++++++++++++++----------
1 file changed, 42 insertions(+), 12 deletions(-)
diff --git a/tests/rsa-common.sh b/tests/rsa-common.sh
index 7db5ba0..e6e12cb 100755
--- a/tests/rsa-common.sh
+++ b/tests/rsa-common.sh
@@ -86,13 +86,13 @@ init_db () {
# Create a new device
init_card () {
- PIN="$1"
- PUK="$2"
- DEV_LABEL="$3"
+ pin="$1"
+ puk="$2"
+ dev_label="$3"
- echo -n "* Initializing smart card... "
- ${SOFTHSM_TOOL} --init-token ${SLOT} --label "${DEV_LABEL}" \
- --so-pin "${PUK}" --pin "${PIN}" >/dev/null
+ echo -n "* Initializing smart card ${dev_label}..."
+ ${SOFTHSM_TOOL} --init-token ${SLOT} --label "${dev_label}" \
+ --so-pin "${puk}" --pin "${pin}" >/dev/null
if test $? = 0; then
echo ok
else
@@ -103,22 +103,26 @@ init_card () {
# Import objects to the token
import_objects () {
- ID=$1
- OBJ_LABEL=$2
+ id=$1
+ obj_label=$2
+ token_label=$3
- pkcs11-tool -p ${PIN} --module ${MODULE} -d ${ID} -a ${OBJ_LABEL} -l -w \
+ pkcs11-tool -p ${PIN} --module ${MODULE} -d ${id} \
+ --token-label ${token_label} -a ${obj_label} -l -w \
${srcdir}/rsa-prvkey.der -y privkey >/dev/null
if test $? != 0;then
exit 1;
fi
- pkcs11-tool -p ${PIN} --module ${MODULE} -d ${ID} -a ${OBJ_LABEL} -l -w \
+ pkcs11-tool -p ${PIN} --module ${MODULE} -d ${id} \
+ --token-label ${token_label} -a ${obj_label} -l -w \
${srcdir}/rsa-pubkey.der -y pubkey >/dev/null
if test $? != 0;then
exit 1;
fi
- pkcs11-tool -p ${PIN} --module ${MODULE} -d ${ID} -a ${OBJ_LABEL} -l -w \
+ pkcs11-tool -p ${PIN} --module ${MODULE} -d ${id} \
+ --token-label ${token_label} -a ${obj_label} -l -w \
${srcdir}/rsa-cert.der -y cert >/dev/null
if test $? != 0;then
exit 1;
@@ -148,8 +152,34 @@ common_init () {
echo Importing
# Import the used objects (private key, public key, and certificate)
- import_objects 01020304 "server-key"
+ import_objects 01020304 "server-key" "libp11-test"
# List the imported objects
list_objects
}
+
+create_devices () {
+ num_devices=$1
+ pin="$2"
+ puk="$3"
+ common_label="$4"
+ object_label="$5"
+
+ i=0
+ while [ $i -le ${num_devices} ]; do
+ init_card ${pin} ${puk} "${common_label}-$i"
+
+ echo "Importing objects to token ${common_label}-$i"
+ # Import objects with different labels
+ import_objects 01020304 "${object_label}-$i" "${common_label}-$i"
+
+ pkcs11-tool -p ${pin} --module ${MODULE} -l -O --token-label \
+ "${common_label}-$i"
+ if test $? != 0;then
+ echo Failed!
+ exit 1;
+ fi
+
+ i=$(($i + 1))
+ done
+}
--
2.21.0
From 7530dc3ae1350a9968733a9318825f187bd09f77 Mon Sep 17 00:00:00 2001
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Date: Tue, 3 Sep 2019 19:04:27 +0200
Subject: [PATCH 2/4] eng_back: Search objects in all matching tokens
Previously, the search for objects would stop in the first matching
token when a more generic PKCS#11 URI was provided (e.g.
"pkcs11:type=public"). This change makes the search continue past the
first matching token if the object was not found.
In ctx_load_{key, cert}(), the search will try to login only if a single
token matched the search. This is to avoid trying the provided PIN
against all matching tokens which could lock the devices.
This also makes the search for objects to ignore uninitialized tokens
and to avoid trying to login when the token does not require login.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit 85a91f4502d48371df0d392d19cecfbced2388c0)
---
src/eng_back.c | 393 +++++++++++++++--------
tests/Makefile.am | 4 +-
tests/pkcs11-uri-without-token.softhsm | 62 ++++
tests/search-all-matching-tokens.softhsm | 106 ++++++
4 files changed, 426 insertions(+), 139 deletions(-)
create mode 100755 tests/pkcs11-uri-without-token.softhsm
create mode 100755 tests/search-all-matching-tokens.softhsm
diff --git a/src/eng_back.c b/src/eng_back.c
index 39a685a..afa6271 100644
--- a/src/eng_back.c
+++ b/src/eng_back.c
@@ -375,7 +375,7 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
const int login)
{
PKCS11_SLOT *slot;
- PKCS11_SLOT *found_slot = NULL;
+ PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
PKCS11_TOKEN *tok, *match_tok = NULL;
PKCS11_CERT *certs, *selected_cert = NULL;
X509 *x509;
@@ -387,6 +387,7 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
size_t tmp_pin_len = MAX_PIN_LENGTH;
int slot_nr = -1;
char flags[64];
+ size_t matched_count = 0;
if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
return NULL;
@@ -401,11 +402,9 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
"The certificate ID is not a valid PKCS#11 URI\n"
"The PKCS#11 URI format is defined by RFC7512\n");
ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
- return NULL;
+ goto error;
}
if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
- if (!login)
- return NULL; /* Process on second attempt */
ctx_destroy_pin(ctx);
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
if (ctx->pin != NULL) {
@@ -424,7 +423,7 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
"The legacy ENGINE_pkcs11 ID format is also "
"still accepted for now\n");
ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
- return NULL;
+ goto error;
}
}
ctx_log(ctx, 1, "Looking in slot %d for certificate: ",
@@ -440,6 +439,13 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
ctx_log(ctx, 1, "\n");
}
+ matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count,
+ sizeof(PKCS11_SLOT *));
+ if (matched_slots == NULL) {
+ ctx_log(ctx, 0, "Could not allocate memory for matched slots\n");
+ goto error;
+ }
+
for (n = 0; n < ctx->slot_count; n++) {
slot = ctx->slot_list + n;
flags[0] = '\0';
@@ -463,6 +469,7 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
found_slot = slot;
}
+
if (match_tok && slot->token &&
(match_tok->label == NULL ||
!strcmp(match_tok->label, slot->token->label)) &&
@@ -483,75 +490,115 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
slot->token->label : "no label");
}
ctx_log(ctx, 1, "\n");
- }
- if (match_tok) {
- OPENSSL_free(match_tok->model);
- OPENSSL_free(match_tok->manufacturer);
- OPENSSL_free(match_tok->serialnr);
- OPENSSL_free(match_tok->label);
- OPENSSL_free(match_tok);
- }
- if (found_slot) {
- slot = found_slot;
- } else if (match_tok) {
- ctx_log(ctx, 0, "Specified object not found\n");
- return NULL;
- } else if (slot_nr == -1) {
- if (!(slot = PKCS11_find_token(ctx->pkcs11_ctx,
- ctx->slot_list, ctx->slot_count))) {
- ctx_log(ctx, 0, "No tokens found\n");
- return NULL;
- }
- } else {
- ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
- return NULL;
- }
- tok = slot->token;
+ if (found_slot && found_slot->token && !found_slot->token->initialized)
+ ctx_log(ctx, 0, "Found uninitialized token\n");
- if (tok == NULL) {
- ctx_log(ctx, 0, "Empty token found\n");
- return NULL;
+ /* Ignore slots without tokens or with uninitialized token */
+ if (found_slot && found_slot->token && found_slot->token->initialized) {
+ matched_slots[matched_count] = found_slot;
+ matched_count++;
+ }
+ found_slot = NULL;
}
- ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
- ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
+ if (matched_count == 0) {
+ if (match_tok) {
+ ctx_log(ctx, 0, "Specified object not found\n");
+ goto error;
+ }
- /* In several tokens certificates are marked as private */
- if (login && !ctx_login(ctx, slot, tok,
- ctx->ui_method, ctx->callback_data)) {
- ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
- return NULL;
+ /* If the legacy slot ID format was used */
+ if (slot_nr != -1) {
+ ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
+ goto error;
+ } 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) {
+ matched_slots[matched_count] = found_slot;
+ matched_count++;
+ } else {
+ ctx_log(ctx, 0, "No tokens found\n");
+ goto error;
+ }
+ }
}
- if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
- ctx_log(ctx, 0, "Unable to enumerate certificates\n");
- return NULL;
- }
+ for (n = 0; n < matched_count; n++) {
+ slot = matched_slots[n];
+ tok = slot->token;
+ if (tok == NULL) {
+ ctx_log(ctx, 0, "Empty token found\n");
+ break;
+ }
- ctx_log(ctx, 1, "Found %u cert%s:\n", cert_count,
- (cert_count <= 1) ? "" : "s");
- if ((s_slot_cert_id && *s_slot_cert_id) &&
- (cert_id_len != 0 || cert_label != NULL)) {
- for (n = 0; n < cert_count; n++) {
- PKCS11_CERT *k = certs + n;
+ ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
+ ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
+
+ /* In several tokens certificates are marked as private */
+ if (login) {
+ /* Only try to login if login is required */
+ if (tok->loginRequired) {
+ /* 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,
+ ctx->ui_method, ctx->callback_data)) {
+ ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
+ goto error;
+ }
+ } else {
+ ctx_log(ctx, 0, "Multiple matching slots (%lu); 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");
+ }
+ goto error;
+ }
+ }
+ }
- if (cert_label != NULL && strcmp(k->label, cert_label) == 0)
- selected_cert = k;
- if (cert_id_len != 0 && k->id_len == cert_id_len &&
- memcmp(k->id, cert_id, cert_id_len) == 0)
- selected_cert = k;
+ if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
+ ctx_log(ctx, 0, "Unable to enumerate certificates\n");
+ continue;
}
- } else {
- for (n = 0; n < cert_count; n++) {
- PKCS11_CERT *k = certs + n;
- if (k->id && *(k->id)) {
- selected_cert = k; /* Use the first certificate with nonempty id */
- break;
+
+ ctx_log(ctx, 1, "Found %u cert%s:\n", cert_count,
+ (cert_count <= 1) ? "" : "s");
+ if ((s_slot_cert_id && *s_slot_cert_id) &&
+ (cert_id_len != 0 || cert_label != NULL)) {
+ for (m = 0; m < cert_count; m++) {
+ PKCS11_CERT *k = certs + m;
+
+ if (cert_label != NULL && strcmp(k->label, cert_label) == 0)
+ selected_cert = k;
+ if (cert_id_len != 0 && k->id_len == cert_id_len &&
+ memcmp(k->id, cert_id, cert_id_len) == 0)
+ selected_cert = k;
+ }
+ } else {
+ for (m = 0; m < cert_count; m++) {
+ PKCS11_CERT *k = certs + m;
+ if (k->id && *(k->id)) {
+ selected_cert = k; /* Use the first certificate with nonempty id */
+ break;
+ }
}
+ if (!selected_cert)
+ selected_cert = certs; /* Use the first certificate */
+ }
+
+ if (selected_cert) {
+ break;
}
- if (!selected_cert)
- selected_cert = certs; /* Use the first certificate */
}
if (selected_cert != NULL) {
@@ -561,8 +608,20 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
ctx_log(ctx, 0, "Certificate not found.\n");
x509 = NULL;
}
+error:
+ /* Free the searched token data */
+ if (match_tok) {
+ OPENSSL_free(match_tok->model);
+ OPENSSL_free(match_tok->manufacturer);
+ OPENSSL_free(match_tok->serialnr);
+ OPENSSL_free(match_tok->label);
+ OPENSSL_free(match_tok);
+ }
+
if (cert_label != NULL)
OPENSSL_free(cert_label);
+ if (matched_slots != NULL)
+ free(matched_slots);
return x509;
}
@@ -605,7 +664,7 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
const int isPrivate, const int login)
{
PKCS11_SLOT *slot;
- PKCS11_SLOT *found_slot = NULL;
+ PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
PKCS11_TOKEN *tok, *match_tok = NULL;
PKCS11_KEY *keys, *selected_key = NULL;
EVP_PKEY *pk = NULL;
@@ -617,6 +676,7 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
char tmp_pin[MAX_PIN_LENGTH+1];
size_t tmp_pin_len = MAX_PIN_LENGTH;
char flags[64];
+ size_t matched_count = 0;
if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
goto error;
@@ -637,7 +697,9 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
goto error;
}
if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
- if (!login)
+ /* If the searched key is public, try without login once even
+ * when the PIN is provided */
+ if (!login && isPrivate)
goto error; /* Process on second attempt */
ctx_destroy_pin(ctx);
ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
@@ -673,6 +735,13 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
ctx_log(ctx, 1, "\n");
}
+ matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count,
+ sizeof(PKCS11_SLOT *));
+ if (matched_slots == NULL) {
+ ctx_log(ctx, 0, "Could not allocate memory for matched slots\n");
+ goto error;
+ }
+
for (n = 0; n < ctx->slot_count; n++) {
slot = ctx->slot_list + n;
flags[0] = '\0';
@@ -696,6 +765,7 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
found_slot = slot;
}
+
if (match_tok && slot->token &&
(match_tok->label == NULL ||
!strcmp(match_tok->label, slot->token->label)) &&
@@ -716,92 +786,128 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
slot->token->label : "no label");
}
ctx_log(ctx, 1, "\n");
- }
- if (match_tok) {
- OPENSSL_free(match_tok->model);
- OPENSSL_free(match_tok->manufacturer);
- OPENSSL_free(match_tok->serialnr);
- OPENSSL_free(match_tok->label);
- OPENSSL_free(match_tok);
+ if (found_slot && found_slot->token && !found_slot->token->initialized)
+ ctx_log(ctx, 0, "Found uninitialized token\n");
+
+ /* Ignore slots without tokens or with uninitialized token */
+ if (found_slot && found_slot->token && found_slot->token->initialized) {
+ matched_slots[matched_count] = found_slot;
+ matched_count++;
+ }
+ found_slot = NULL;
}
- if (found_slot) {
- slot = found_slot;
- } else if (match_tok) {
- ctx_log(ctx, 0, "Specified object not found\n");
- goto error;
- } else if (slot_nr == -1) {
- if (!(slot = PKCS11_find_token(ctx->pkcs11_ctx,
- ctx->slot_list, ctx->slot_count))) {
- ctx_log(ctx, 0, "No tokens found\n");
+
+ if (matched_count == 0) {
+ if (match_tok) {
+ ctx_log(ctx, 0, "Specified object not found\n");
goto error;
}
- } else {
- ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
- goto error;
- }
- tok = slot->token;
- if (tok == NULL) {
- ctx_log(ctx, 0, "Found empty token\n");
- goto error;
+ /* If the legacy slot ID format was used */
+ if (slot_nr != -1) {
+ ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
+ goto error;
+ } 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) {
+ matched_slots[matched_count] = found_slot;
+ matched_count++;
+ } else {
+ ctx_log(ctx, 0, "No tokens found\n");
+ goto error;
+ }
+ }
}
- /* The following check is non-critical to ensure interoperability
- * with some other (which ones?) PKCS#11 libraries */
- if (!tok->initialized)
- ctx_log(ctx, 0, "Found uninitialized token\n");
- ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
- ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
+ for (n = 0; n < matched_count; n++) {
+ slot = matched_slots[n];
+ tok = slot->token;
+ if (tok == NULL) {
+ ctx_log(ctx, 0, "Found empty token\n");
+ break;
+ }
- /* Both private and public keys can have the CKA_PRIVATE attribute
- * set and thus require login (even to retrieve attributes!) */
- if (login && !ctx_login(ctx, slot, tok, ui_method, callback_data)) {
- ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
- goto error;
- }
+ ctx_log(ctx, 1, "Found slot: %s\n", slot->description);
+ ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
+
+ /* Both private and public keys can have the CKA_PRIVATE attribute
+ * set and thus require login (even to retrieve attributes!) */
+ if (login) {
+ /* Try to login only if login is required */
+ if (tok->loginRequired) {
+ /* Try to login only 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)) {
+ ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
+ goto error;
+ }
+ } else {
+ ctx_log(ctx, 0, "Multiple matching slots (%lu); will not try to"
+ " login\n", matched_count);
+ for (m = 0; m < matched_count; m++){
+ slot = matched_slots[m];
+ ctx_log(ctx, 1, "[%u] %s: %s\n", m + 1,
+ slot->description? slot->description:
+ "(no description)",
+ (slot->token && slot->token->label)?
+ slot->token->label: "no label");
+ }
+ goto error;
+ }
+ }
+ }
- if (isPrivate) {
- /* Make sure there is at least one private key on the token */
- if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
- ctx_log(ctx, 0, "Unable to enumerate private keys\n");
- goto error;
+ if (isPrivate) {
+ /* Make sure there is at least one private key on the token */
+ if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
+ ctx_log(ctx, 0, "Unable to enumerate private keys\n");
+ continue;
+ }
+ } else {
+ /* Make sure there is at least one public key on the token */
+ if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
+ ctx_log(ctx, 0, "Unable to enumerate public keys\n");
+ continue;
+ }
}
- } else {
- /* Make sure there is at least one public key on the token */
- if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
- ctx_log(ctx, 0, "Unable to enumerate public keys\n");
- goto error;
+ if (key_count == 0) {
+ if (login) /* Only print the error on the second attempt */
+ ctx_log(ctx, 0, "No %s keys found.\n",
+ (char *)(isPrivate ? "private" : "public"));
+ continue;
}
- }
- if (key_count == 0) {
- if (login) /* Only print the error on the second attempt */
- ctx_log(ctx, 0, "No %s keys found.\n",
- (char *)(isPrivate ? "private" : "public"));
- goto error;
- }
- ctx_log(ctx, 1, "Found %u %s key%s:\n", key_count,
- (char *)(isPrivate ? "private" : "public"),
- (key_count == 1) ? "" : "s");
-
- if (s_slot_key_id && *s_slot_key_id &&
- (key_id_len != 0 || key_label != NULL)) {
- for (n = 0; n < key_count; n++) {
- PKCS11_KEY *k = keys + n;
-
- ctx_log(ctx, 1, " %2u %c%c id=", n + 1,
- k->isPrivate ? 'P' : ' ',
- k->needLogin ? 'L' : ' ');
- dump_hex(ctx, 1, k->id, k->id_len);
- ctx_log(ctx, 1, " label=%s\n", k->label);
- if (key_label != NULL && strcmp(k->label, key_label) == 0)
- selected_key = k;
- if (key_id_len != 0 && k->id_len == key_id_len
- && memcmp(k->id, key_id, key_id_len) == 0)
- selected_key = k;
+ ctx_log(ctx, 1, "Found %u %s key%s:\n", key_count,
+ (char *)(isPrivate ? "private" : "public"),
+ (key_count == 1) ? "" : "s");
+
+ if (s_slot_key_id && *s_slot_key_id &&
+ (key_id_len != 0 || key_label != NULL)) {
+ for (m = 0; m < key_count; m++) {
+ PKCS11_KEY *k = keys + m;
+
+ ctx_log(ctx, 1, " %2u %c%c id=", m + 1,
+ k->isPrivate ? 'P' : ' ',
+ k->needLogin ? 'L' : ' ');
+ dump_hex(ctx, 1, k->id, k->id_len);
+ ctx_log(ctx, 1, " label=%s\n", k->label);
+ if (key_label != NULL && strcmp(k->label, key_label) == 0)
+ selected_key = k;
+ if (key_id_len != 0 && k->id_len == key_id_len
+ && memcmp(k->id, key_id, key_id_len) == 0)
+ selected_key = k;
+ }
+ } else {
+ selected_key = keys; /* Use the first key */
+ }
+
+ if (selected_key) {
+ break;
}
- } else {
- selected_key = keys; /* Use the first key */
}
if (selected_key != NULL) {
@@ -813,9 +919,20 @@ static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
ctx_log(ctx, 0, "Key not found.\n");
pk = NULL;
}
+
error:
+ /* Free the searched token data */
+ if (match_tok) {
+ OPENSSL_free(match_tok->model);
+ OPENSSL_free(match_tok->manufacturer);
+ OPENSSL_free(match_tok->serialnr);
+ OPENSSL_free(match_tok->label);
+ OPENSSL_free(match_tok);
+ }
if (key_label != NULL)
OPENSSL_free(key_label);
+ if (matched_slots != NULL)
+ free(matched_slots);
return pk;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2a84403..18886df 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -28,7 +28,9 @@ dist_check_SCRIPTS = \
rsa-pss-sign.softhsm \
rsa-oaep.softhsm \
case-insensitive.softhsm \
- ec-check-privkey.softhsm
+ ec-check-privkey.softhsm \
+ pkcs11-uri-without-token.softhsm \
+ search-all-matching-tokens.softhsm
dist_check_DATA = \
rsa-cert.der rsa-prvkey.der rsa-pubkey.der \
ec-cert.der ec-prvkey.der ec-pubkey.der
diff --git a/tests/pkcs11-uri-without-token.softhsm b/tests/pkcs11-uri-without-token.softhsm
new file mode 100755
index 0000000..f82e1f4
--- /dev/null
+++ b/tests/pkcs11-uri-without-token.softhsm
@@ -0,0 +1,62 @@
+#!/bin/sh
+
+# Copyright (C) 2015 Nikos Mavrogiannopoulos
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This test checks if it is possible to use the keys without specifying the
+# token if there is only one initialized token available.
+
+outdir="output.$$"
+
+# Load common test functions
+. ${srcdir}/rsa-common.sh
+
+# Do the common test initialization
+common_init
+
+sed -e "s|@MODULE_PATH@|${MODULE}|g" -e \
+ "s|@ENGINE_PATH@|../src/.libs/pkcs11.so|g" \
+ <"${srcdir}/engines.cnf.in" >"${outdir}/engines.cnf"
+
+export OPENSSL_ENGINES="../src/.libs/"
+export OPENSSL_CONF="${outdir}/engines.cnf"
+
+# These URIs don't contain the token specification
+PRIVATE_KEY="pkcs11:object=server-key;type=private;pin-value=1234"
+PUBLIC_KEY="pkcs11:object=server-key;type=public;pin-value=1234"
+
+# Create input file
+echo "secret" >"${outdir}/in.txt"
+
+# Generate signature without specifying the token in the PKCS#11 URI
+openssl pkeyutl -engine pkcs11 -keyform engine -inkey "${PRIVATE_KEY}" \
+ -sign -out "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? != 0;then
+ echo "Failed to generate signature using PKCS#11 URI ${PRIVATE_KEY}"
+ exit 1;
+fi
+
+# Verify the signature without specifying the token in the PKCS#11 URI
+openssl pkeyutl -engine pkcs11 -keyform engine -pubin -inkey "${PUBLIC_KEY}" \
+ -verify -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? != 0;then
+ echo "Failed to verify signature using PKCS#11 URI ${PUBLIC_KEY}"
+ exit 1;
+fi
+
+rm -rf "$outdir"
+
+exit 0
diff --git a/tests/search-all-matching-tokens.softhsm b/tests/search-all-matching-tokens.softhsm
new file mode 100755
index 0000000..d0810c4
--- /dev/null
+++ b/tests/search-all-matching-tokens.softhsm
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+# Copyright (C) 2015 Nikos Mavrogiannopoulos
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# This test checks if the search for objects in tokens will continue past the
+# first token found.
+#
+# Generic PKCS#11 URIs are used to make the search to match more than one
+# token. The search should be able to find the objects in each device, which are
+# labeled differently per token.
+#
+# This test also contains a negative test to verify that the engine will not try
+# to login to a token if more than one token matched the search. This is why it
+# is required to have only one match to be able to use a private key.
+
+outdir="output.$$"
+
+# Load common test functions
+. ${srcdir}/rsa-common.sh
+
+PIN=1234
+PUK=1234
+
+NUM_DEVICES=5
+
+# Initialize the SoftHSM DB
+init_db
+
+# Create some devices
+create_devices $NUM_DEVICES $PIN $PUK "libp11-test" "label"
+
+sed -e "s|@MODULE_PATH@|${MODULE}|g" -e "s|@ENGINE_PATH@|../src/.libs/pkcs11.so|g" <"${srcdir}/engines.cnf.in" >"${outdir}/engines.cnf"
+
+export OPENSSL_ENGINES="../src/.libs/"
+export OPENSSL_CONF="${outdir}/engines.cnf"
+
+PRIVATE_KEY="pkcs11:token=libp11-test-3;object=label-3;type=private;pin-value=1234"
+PRIVATE_KEY_WITHOUT_TOKEN="pkcs11:object=label-3;type=private;pin-value=1234"
+PUBLIC_KEY_ANY="pkcs11:type=public"
+CERTIFICATE="pkcs11:object=label-3;type=cert;pin-value=1234"
+
+# Create input file
+echo "secret" > "${outdir}/in.txt"
+
+# Verify that it doesn't try to login if more than one token matched the search
+openssl pkeyutl -engine pkcs11 -keyform engine \
+ -inkey "${PRIVATE_KEY_WITHOUT_TOKEN}" \
+ -sign -out "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? = 0;then
+ echo "Did not fail when the PKCS#11 URI matched multiple tokens"
+fi
+
+# Generate signature specifying the token in the PKCS#11 URI
+openssl pkeyutl -engine pkcs11 -keyform engine -inkey "${PRIVATE_KEY}" \
+ -sign -out "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? != 0;then
+ echo "Failed to sign file using PKCS#11 URI ${PRIVATE_KEY}"
+ exit 1;
+fi
+
+# Verify the signature using the public key from each token
+i=0
+while [ $i -le ${NUM_DEVICES} ]; do
+ pubkey="pkcs11:object=label-$i;type=public;pin-value=1234"
+ openssl pkeyutl -engine pkcs11 -keyform engine -pubin -inkey "${pubkey}" \
+ -verify -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt"
+ if test $? != 0;then
+ echo "Failed to verify the signature using the PKCS#11 URI ${pubkey}"
+ exit 1;
+ fi
+ i=$(($i + 1))
+done
+
+# Verify the signature using a certificate without specifying the token
+openssl pkeyutl -engine pkcs11 -keyform engine -pubin -inkey "${CERTIFICATE}" \
+ -verify -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? != 0;then
+ echo "Failed to verify the signature using the PKCS#11 URI ${CERTIFICATE}"
+ exit 1;
+fi
+
+# Verify the signature using the first public key found
+openssl pkeyutl -engine pkcs11 -keyform engine -pubin -inkey "${PUBLIC_KEY_ANY}" \
+ -verify -sigfile "${outdir}/signature.bin" -in "${outdir}/in.txt"
+if test $? != 0;then
+ echo "Failed to verify the signature using the PKCS#11 URI ${PUBLIC_KEY_ANY}."
+ exit 1;
+fi
+
+rm -rf "$outdir"
+
+exit 0
--
2.21.0
From f7e9c100386e8ed9c0670e36c6023d4c928d132f Mon Sep 17 00:00:00 2001
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Date: Thu, 21 Nov 2019 16:40:45 +0100
Subject: [PATCH 3/4] eng_back: Initialize variable
The unitialized variable could be returned to the caller in case of
error, being the value undefined.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit f9fd7e65f15d20d4f4f767bb84dfccce02f834e5)
---
src/eng_back.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/eng_back.c b/src/eng_back.c
index afa6271..0dd697d 100644
--- a/src/eng_back.c
+++ b/src/eng_back.c
@@ -378,7 +378,7 @@ static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
PKCS11_TOKEN *tok, *match_tok = NULL;
PKCS11_CERT *certs, *selected_cert = NULL;
- X509 *x509;
+ X509 *x509 = NULL;
unsigned int cert_count, n, m;
unsigned char cert_id[MAX_VALUE_LEN / 2];
size_t cert_id_len = sizeof(cert_id);
--
2.21.0
From 823a97403c80d475c5a0ba88e1f63923dd540db8 Mon Sep 17 00:00:00 2001
From: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Date: Mon, 25 Nov 2019 16:00:33 +0100
Subject: [PATCH 4/4] tests: Add missing exit when test case fail
The missing exit would make the test to pass even when the test case
failed.
Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
(cherry picked from commit a41cbb29083545ceee8da35fa0067e402ed7d676)
---
tests/search-all-matching-tokens.softhsm | 1 +
1 file changed, 1 insertion(+)
diff --git a/tests/search-all-matching-tokens.softhsm b/tests/search-all-matching-tokens.softhsm
index d0810c4..0db697e 100755
--- a/tests/search-all-matching-tokens.softhsm
+++ b/tests/search-all-matching-tokens.softhsm
@@ -62,6 +62,7 @@ openssl pkeyutl -engine pkcs11 -keyform engine \
-sign -out "${outdir}/signature.bin" -in "${outdir}/in.txt"
if test $? = 0;then
echo "Did not fail when the PKCS#11 URI matched multiple tokens"
+ exit 1;
fi
# Generate signature specifying the token in the PKCS#11 URI
--
2.21.0