]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
when comparing a CA certificate with the trusted list compare the name and key
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 2 Sep 2014 18:56:32 +0000 (20:56 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Tue, 2 Sep 2014 20:05:46 +0000 (22:05 +0200)
That is to handle cases where a CA certificate was superceded by a different
one with the same name and the same key. That can happen when an intermediate
CA certificate is replaced by a self-signed one.

lib/includes/gnutls/pkcs11.h
lib/pkcs11.c
lib/x509/common.c
lib/x509/common.h
lib/x509/crl.c
lib/x509/verify.c
lib/x509/x509.c
lib/x509/x509_int.h

index da6cf8c4bd894ddf73f93fdb959abb02d9e3d6e9..8fd121dab68c3b53647388527fd6d82ab2364b47 100644 (file)
@@ -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;
 
 /**
index 030d5f8d1712ba8f21de63d2ff98f25fe8095463..3be05b897965a85afd08dbd0fc3f50609a735386 100644 (file)
@@ -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;
index ba8299fc37f404b082d89a1004aae5f7e15b8d5b..83833d541a17d6e8d9601785d458d2a05efe1a05 100644 (file)
@@ -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;
index 402d242beabe635893578472303a3955a429e0e9..76ba54a1230f36b614b6b1de66bcdf8daf1845c5 100644 (file)
@@ -172,9 +172,13 @@ 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);
index 28a5573459d2f6613f213e3e1d902fffb83d14b8..63e20c2ff446d8483fab247356f28defdf9c579e 100644 (file)
@@ -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) {
index 75381524fa952913f38d00931a957a63f020997e..7f9831a6e91a1174c32f8a71af6d6e21da6734f0 100644 (file)
 #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)) {
index 32052824f8a9d00565af622d3994fe458cba6946..69bdf88e32020555e343303b7fc3052029cf083a 100644 (file)
@@ -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;
index 455701eaf6a6c9b0f2ecdf97457d517ba628fab9..9ae7064f34e995cd60c8ebb695585f777c51823c 100644 (file)
@@ -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;