diff options
-rw-r--r-- | lib/includes/gnutls/pkcs11.h | 8 | ||||
-rw-r--r-- | lib/pkcs11.c | 14 | ||||
-rw-r--r-- | lib/x509/common.c | 2 | ||||
-rw-r--r-- | lib/x509/common.h | 6 | ||||
-rw-r--r-- | lib/x509/crl.c | 2 | ||||
-rw-r--r-- | lib/x509/verify.c | 54 | ||||
-rw-r--r-- | lib/x509/x509.c | 12 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 1 |
8 files changed, 87 insertions, 12 deletions
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h index da6cf8c4bd..8fd121dab6 100644 --- a/lib/includes/gnutls/pkcs11.h +++ b/lib/includes/gnutls/pkcs11.h @@ -101,9 +101,10 @@ void gnutls_pkcs11_obj_set_pin_function(gnutls_pkcs11_obj_t obj, * @GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE: marked as not private. * @GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_ANY: When retrieving an object, do not set any requirements. * GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED: When retrieving an object, only retrieve the marked as trusted. - * In gnutls_pkcs11_crt_is_known() it implies GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_COMPARE. + * In gnutls_pkcs11_crt_is_known() it implies %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_COMPARE if %GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY is not given. * @GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED: When retrieving an object, only retrieve the marked as distrusted. - * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE: When checking an object's presence, full compare it before returning any result. + * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE: When checking an object's presence, fully compare it before returning any result. + * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY: When checking an object's presence, compare the key before returning any result. * @GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE: The object must be present in a marked as trusted module. * @GNUTLS_PKCS11_OBJ_FLAG_MARK_CA: Mark the object as a CA. * @GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP: Mark the generated key pair as wrapping and unwrapping keys. @@ -123,7 +124,8 @@ typedef enum gnutls_pkcs11_obj_flags { GNUTLS_PKCS11_OBJ_FLAG_COMPARE = (1<<9), GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE = (1<<10), GNUTLS_PKCS11_OBJ_FLAG_MARK_CA = (1<<11), - GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP = (1<<12) + GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP = (1<<12), + GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY = (1<<13) } gnutls_pkcs11_obj_flags; /** diff --git a/lib/pkcs11.c b/lib/pkcs11.c index 030d5f8d17..3be05b8979 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -3278,6 +3278,18 @@ find_cert_cb(struct pkcs11_session_info *sinfo, } } + if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY) { + if (priv->crt == NULL) { + gnutls_assert(); + break; + } + + if (_gnutls_check_if_same_key2(priv->crt, &data) == 0) { + /* doesn't match */ + break; + } + } + found = 1; break; } else { @@ -3479,7 +3491,7 @@ int gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert, /* when looking for a trusted certificate, we always fully compare * with the given */ - if (flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) + if (flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED && !(flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY)) flags |= GNUTLS_PKCS11_OBJ_FLAG_COMPARE; priv.flags = flags; diff --git a/lib/x509/common.c b/lib/x509/common.c index ba8299fc37..83833d541a 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -1844,7 +1844,7 @@ int _gnutls_strdatum_to_buf(gnutls_datum_t * d, void *buf, /* returns a constant string in @dn pointing to @raw */ int -_gnutls_x509_get_raw_dn2(ASN1_TYPE c2, gnutls_datum_t * raw, +_gnutls_x509_get_raw_field2(ASN1_TYPE c2, gnutls_datum_t * raw, const char *whom, gnutls_datum_t * dn) { int result, len1; diff --git a/lib/x509/common.h b/lib/x509/common.h index 402d242bea..76ba54a123 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -172,10 +172,14 @@ void _asnstr_append_name(char *name, size_t name_size, const char *part1, const char *part2); int -_gnutls_x509_get_raw_dn2(ASN1_TYPE c2, gnutls_datum_t * raw, +_gnutls_x509_get_raw_field2(ASN1_TYPE c2, gnutls_datum_t * raw, const char *whom, gnutls_datum_t * dn); bool +_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1, + gnutls_datum_t * cert2bin); + +bool _gnutls_check_if_same_cert(gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2); diff --git a/lib/x509/crl.c b/lib/x509/crl.c index 28a5573459..63e20c2ff4 100644 --- a/lib/x509/crl.c +++ b/lib/x509/crl.c @@ -165,7 +165,7 @@ gnutls_x509_crl_import(gnutls_x509_crl_t crl, goto cleanup; } - result = _gnutls_x509_get_raw_dn2(crl->crl, &crl->der, + result = _gnutls_x509_get_raw_field2(crl->crl, &crl->der, "tbsCertList.issuer.rdnSequence", &crl->raw_issuer_dn); if (result < 0) { diff --git a/lib/x509/verify.c b/lib/x509/verify.c index 75381524fa..7f9831a6e9 100644 --- a/lib/x509/verify.c +++ b/lib/x509/verify.c @@ -39,7 +39,51 @@ #include <gnutls_pk.h> #include <stdbool.h> -/* Checks if two certs are identical. Return 1 on match. */ +/* Checks if two certs have the same name and the same key. Return 1 on match. */ +static bool +_gnutls_check_if_same_key(gnutls_x509_crt_t cert1, + gnutls_x509_crt_t cert2) +{ + int ret; + bool result; + + ret = _gnutls_is_same_dn(cert1, cert2); + if (ret == 0) + return 0; + + if (cert1->raw_spki.size > 0 && (cert1->raw_spki.size == cert2->raw_spki.size) && + (memcmp(cert1->raw_spki.data, cert2->raw_spki.data, cert1->raw_spki.size) == 0)) + result = 1; + else + result = 0; + + fail: + return result; +} + +bool +_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1, + gnutls_datum_t * cert2bin) +{ + int ret; + gnutls_x509_crt_t cert2; + + ret = gnutls_x509_crt_init(&cert2); + if (ret < 0) + return gnutls_assert_val(0); + + ret = gnutls_x509_crt_import(cert2, cert2bin, GNUTLS_X509_FMT_DER); + if (ret < 0) { + gnutls_x509_crt_deinit(cert2); + return gnutls_assert_val(0); + } + + ret = _gnutls_check_if_same_key(cert1, cert2); + + gnutls_x509_crt_deinit(cert2); + return ret; +} + bool _gnutls_check_if_same_cert(gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2) @@ -838,7 +882,11 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list, int j; for (j = 0; j < tcas_size; j++) { - if (_gnutls_check_if_same_cert + /* we check for a certificate that may not be identical with the one + * sent by the client, but will have the same name and key. That is + * because it can happen that a CA certificate is upgraded from intermediate + * CA to self-signed CA at some point. */ + if (_gnutls_check_if_same_key (certificate_list[i], trusted_cas[j]) != 0) { /* explicit time check for trusted CA that we remove from * list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS @@ -986,7 +1034,7 @@ _gnutls_pkcs11_verify_crt_status(const char* url, for (; i < clist_size; i++) { if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE| - GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) != 0) { + GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) != 0) { if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) && !(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) { diff --git a/lib/x509/x509.c b/lib/x509/x509.c index 32052824f8..69bdf88e32 100644 --- a/lib/x509/x509.c +++ b/lib/x509/x509.c @@ -246,7 +246,7 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert, goto cleanup; } - result = _gnutls_x509_get_raw_dn2(cert->cert, &cert->der, + result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der, "tbsCertificate.issuer.rdnSequence", &cert->raw_issuer_dn); if (result < 0) { @@ -254,7 +254,7 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert, goto cleanup; } - result = _gnutls_x509_get_raw_dn2(cert->cert, &cert->der, + result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der, "tbsCertificate.subject.rdnSequence", &cert->raw_dn); if (result < 0) { @@ -262,6 +262,14 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert, goto cleanup; } + result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der, + "tbsCertificate.subjectPublicKeyInfo", + &cert->raw_spki); + if (result < 0) { + gnutls_assert(); + goto cleanup; + } + /* Since we do not want to disable any extension */ cert->use_extensions = 1; diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h index 455701eaf6..9ae7064f34 100644 --- a/lib/x509/x509_int.h +++ b/lib/x509/x509_int.h @@ -70,6 +70,7 @@ typedef struct gnutls_x509_crt_int { * get_raw_*_dn(). */ gnutls_datum_t raw_dn; gnutls_datum_t raw_issuer_dn; + gnutls_datum_t raw_spki; gnutls_datum_t der; struct pin_info_st pin; |