summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2018-09-20 16:44:51 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-09-21 13:09:40 +0200
commit39a6de929c1a6baa2b7914bfa89275b3ee4db0e2 (patch)
tree71e1700c0e74282dec4e6cb6eda439a48890da6e /lib
parentcc54c334f8a1f77a03d4e26ed6ac9a3f132a463f (diff)
downloadgnutls-39a6de929c1a6baa2b7914bfa89275b3ee4db0e2.tar.gz
Provide a more flexible PKCS#11 search of trust store certificatestmp-pkcs11-lax-search
This addresses the problem where the CA certificate doesn't have a subject key identifier whereas the end certificates have an authority key identifier. Resolves #569 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/pkcs11.c141
-rw-r--r--lib/pkcs11_int.h1
-rw-r--r--lib/x509/common.c9
-rw-r--r--lib/x509/common.h3
4 files changed, 111 insertions, 43 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;
diff --git a/lib/pkcs11_int.h b/lib/pkcs11_int.h
index 62831d89c2..f52db0780c 100644
--- a/lib/pkcs11_int.h
+++ b/lib/pkcs11_int.h
@@ -187,6 +187,7 @@ ck_object_class_t pkcs11_strtype_to_class(const char *type);
/* Additional internal flags for gnutls_pkcs11_obj_flags */
/* @GNUTLS_PKCS11_OBJ_FLAG_EXPECT_CERT: When importing an object, provide a hint on the type, to allow incomplete URLs
* @GNUTLS_PKCS11_OBJ_FLAG_EXPECT_PRIVKEY: Hint for private key */
+#define GNUTLS_PKCS11_OBJ_FLAG_FIRST_CLOSE_MATCH ((unsigned int)1<<28)
#define GNUTLS_PKCS11_OBJ_FLAG_EXPECT_CERT (1<<29)
#define GNUTLS_PKCS11_OBJ_FLAG_EXPECT_PRIVKEY (1<<30)
#define GNUTLS_PKCS11_OBJ_FLAG_EXPECT_PUBKEY ((unsigned int)1<<31)
diff --git a/lib/x509/common.c b/lib/x509/common.c
index c978c024e1..4a3e8376f7 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1674,12 +1674,16 @@ int x509_raw_crt_to_raw_pubkey(const gnutls_datum_t * cert,
unsigned
_gnutls_check_valid_key_id(gnutls_datum_t *key_id,
- gnutls_x509_crt_t cert, time_t now)
+ gnutls_x509_crt_t cert, time_t now,
+ unsigned *has_ski)
{
uint8_t id[MAX_KEY_ID_SIZE];
size_t id_size;
unsigned result = 0;
+ if (has_ski)
+ *has_ski = 0;
+
if (now > gnutls_x509_crt_get_expiration_time(cert) ||
now < gnutls_x509_crt_get_activation_time(cert)) {
/* don't bother, certificate is not yet activated or expired */
@@ -1693,6 +1697,9 @@ _gnutls_check_valid_key_id(gnutls_datum_t *key_id,
goto out;
}
+ if (has_ski)
+ *has_ski = 1;
+
if (id_size == key_id->size && !memcmp(id, key_id->data, id_size))
result = 1;
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 637121c2ee..2ff979380f 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -236,7 +236,8 @@ _gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
unsigned
_gnutls_check_valid_key_id(gnutls_datum_t *key_id,
- gnutls_x509_crt_t cert, time_t now);
+ gnutls_x509_crt_t cert, time_t now,
+ unsigned *has_ski);
unsigned _gnutls_check_key_purpose(gnutls_x509_crt_t cert, const char *purpose, unsigned no_any);