diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-09-20 16:44:51 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2018-09-21 13:09:40 +0200 |
commit | 39a6de929c1a6baa2b7914bfa89275b3ee4db0e2 (patch) | |
tree | 71e1700c0e74282dec4e6cb6eda439a48890da6e /lib | |
parent | cc54c334f8a1f77a03d4e26ed6ac9a3f132a463f (diff) | |
download | gnutls-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.c | 141 | ||||
-rw-r--r-- | lib/pkcs11_int.h | 1 | ||||
-rw-r--r-- | lib/x509/common.c | 9 | ||||
-rw-r--r-- | lib/x509/common.h | 3 |
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); |