summaryrefslogtreecommitdiff
path: root/lib/pkcs11.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pkcs11.c')
-rw-r--r--lib/pkcs11.c141
1 files changed, 100 insertions, 41 deletions
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
index 6f9274856e..9909127903 100644
--- a/lib/pkcs11.c
+++ b/lib/pkcs11.c
@@ -3897,9 +3897,14 @@ const char *gnutls_pkcs11_type_get_name(gnutls_pkcs11_obj_type_t type)
}
static
-int check_found_cert(struct find_cert_st *priv, gnutls_datum_t *data, time_t now)
+int check_found_cert(struct find_cert_st *priv,
+ ck_object_handle_t ctx,
+ gnutls_datum_t *data,
+ time_t now,
+ ck_object_handle_t *cand_ctx)
{
gnutls_x509_crt_t tcrt = NULL;
+ unsigned has_ski;
int ret;
ret = gnutls_x509_crt_init(&tcrt);
@@ -3914,14 +3919,6 @@ int check_found_cert(struct find_cert_st *priv, gnutls_datum_t *data, time_t now
goto cleanup;
}
- if (priv->key_id.size > 0 &&
- !_gnutls_check_valid_key_id(&priv->key_id, tcrt, now)) {
- gnutls_assert();
- _gnutls_debug_log("check_found_cert: cert has invalid key ID\n");
- ret = -1;
- goto cleanup;
- }
-
if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE) {
if (priv->crt == NULL) {
gnutls_assert();
@@ -3952,6 +3949,20 @@ int check_found_cert(struct find_cert_st *priv, gnutls_datum_t *data, time_t now
}
}
+ if (priv->key_id.size > 0 &&
+ !_gnutls_check_valid_key_id(&priv->key_id, tcrt, now, &has_ski)) {
+ gnutls_assert();
+ if (has_ski) {
+ _gnutls_debug_log("check_found_cert: cert has invalid key ID\n");
+ ret = -1;
+ } else {
+ /* That's a possible match; there can be CA certificates without
+ * an SKI, which match a cert which has AKI. */
+ *cand_ctx = ctx;
+ }
+ goto cleanup;
+ }
+
ret = 0;
cleanup:
if (tcrt != NULL)
@@ -3959,6 +3970,44 @@ cleanup:
return ret;
}
+static int get_data_and_attrs(struct pkcs11_session_info *sinfo,
+ ck_object_handle_t object, gnutls_datum_t *data,
+ char *label, size_t label_size,
+ uint8_t *id, size_t id_size,
+ gnutls_datum_t *o_label, gnutls_datum_t *o_id)
+{
+ ck_rv_t rv;
+ struct ck_attribute a[2];
+
+ /* data will contain the certificate */
+ rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, object, CKA_VALUE, data);
+ if (rv == CKR_OK) {
+ a[0].type = CKA_LABEL;
+ a[0].value = label;
+ a[0].value_len = label_size;
+
+ a[1].type = CKA_ID;
+ a[1].value = id;
+ a[1].value_len = id_size;
+
+ if (pkcs11_get_attribute_value(sinfo->module, sinfo->pks, object, a,
+ 2) == CKR_OK) {
+ o_label->data = a[0].value;
+ o_label->size = a[0].value_len;
+ o_id->data = a[1].value;
+ o_id->size = a[1].value_len;
+
+ return 0;
+ } else {
+ _gnutls_free_datum(data);
+ _gnutls_debug_log
+ ("p11: Skipped cert, missing attrs.\n");
+ }
+ }
+
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+}
+
static int
find_cert_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
struct ck_token_info *tinfo, struct ck_info *lib_info, void *input)
@@ -3967,14 +4016,15 @@ find_cert_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
ck_object_class_t class = -1;
ck_certificate_type_t type = (ck_certificate_type_t) - 1;
ck_rv_t rv;
- ck_object_handle_t ctx;
+ ck_object_handle_t ctx, cand_ctx = CK_INVALID_HANDLE;
unsigned long count, a_vals;
int found = 0, ret;
struct find_cert_st *priv = input;
char label_tmp[PKCS11_LABEL_SIZE];
- char id_tmp[PKCS11_ID_SIZE];
+ uint8_t id_tmp[PKCS11_ID_SIZE];
gnutls_datum_t data = {NULL, 0};
- unsigned tries, i, finalized;
+ unsigned finalized;
+ int i, tries;
ck_bool_t trusted = 1;
time_t now;
gnutls_datum_t label = {NULL,0}, id = {NULL,0};
@@ -4087,38 +4137,38 @@ find_cert_cb(struct ck_function_list *module, struct pkcs11_session_info *sinfo,
break;
}
- /* data will contain the certificate */
- rv = pkcs11_get_attribute_avalue(sinfo->module, sinfo->pks, ctx, CKA_VALUE, &data);
- if (rv == CKR_OK) {
- ret = check_found_cert(priv, &data, now);
- if (ret < 0) {
- _gnutls_free_datum(&data);
- continue;
- }
+ ret = get_data_and_attrs(sinfo, ctx, &data,
+ label_tmp, sizeof(label_tmp),
+ id_tmp, sizeof(id_tmp),
+ &label,
+ &id);
+ if (ret < 0)
+ continue;
- a[0].type = CKA_LABEL;
- a[0].value = label_tmp;
- a[0].value_len = sizeof(label_tmp);
+ ret = check_found_cert(priv, ctx, &data, now, &cand_ctx);
+ if (ret < 0) {
+ _gnutls_free_datum(&data);
+ continue;
+ }
- a[1].type = CKA_ID;
- a[1].value = id_tmp;
- a[1].value_len = sizeof(id_tmp);
+ found = 1;
+ break;
+ }
- if (pkcs11_get_attribute_value(sinfo->module, sinfo->pks, ctx, a,
- 2) == CKR_OK) {
- label.data = a[0].value;
- label.size = a[0].value_len;
- id.data = a[1].value;
- id.size = a[1].value_len;
-
- found = 1;
- break;
- } else {
- _gnutls_free_datum(&data);
- _gnutls_debug_log
- ("p11: Skipped cert, missing attrs.\n");
- }
- }
+ if (!found && cand_ctx != CK_INVALID_HANDLE) {
+ /* there was a possible match; let's retrieve that one instead of
+ * failing */
+ ret = get_data_and_attrs(sinfo, cand_ctx, &data,
+ label_tmp, sizeof(label_tmp),
+ id_tmp, sizeof(id_tmp),
+ &label,
+ &id);
+ if (ret >= 0)
+ found = 1;
+
+ /* we do not need to use check_found_cert() because
+ * in case we have a candidate, we already have checked it
+ */
}
pkcs11_find_objects_final(sinfo);
@@ -4241,6 +4291,15 @@ int gnutls_pkcs11_get_raw_issuer(const char *url, gnutls_x509_crt_t cert,
ret =
_pkcs11_traverse_tokens(find_cert_cb, &priv, info,
&cert->pin, pkcs11_obj_flags_to_int(flags));
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ /* we have failed retrieving the right certificate; if there
+ * was a close match return that one. */
+ priv.flags |= GNUTLS_PKCS11_OBJ_FLAG_FIRST_CLOSE_MATCH;
+ ret =
+ _pkcs11_traverse_tokens(find_cert_cb, &priv, info,
+ &cert->pin, pkcs11_obj_flags_to_int(flags));
+ }
+
if (ret < 0) {
gnutls_assert();
goto cleanup;