]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Implements a callback function gnutls_x509_trust_list_set_getissuer_function()
authorSahana Prasad <sahana@redhat.com>
Fri, 22 May 2020 07:42:47 +0000 (09:42 +0200)
committerSahana Prasad <sahana@redhat.com>
Wed, 3 Jun 2020 13:41:26 +0000 (15:41 +0200)
Signed-off-by: Sahana Prasad <sahana@redhat.com>
lib/cert-cred.c
lib/includes/gnutls/x509.h
lib/libgnutls.map
lib/x509/verify-high.c
lib/x509/verify-high.h
lib/x509/verify.c
lib/x509/x509_int.h

index 7311737298b7e19e96ea51cf78d8f0ca6ed00f82..8d3214dcbbffeb898aa2bb8542b3435de97003e5 100644 (file)
@@ -882,6 +882,38 @@ void
        cred->verify_callback = func;
 }
 
+/**
+ * gnutls_x509_trust_list_set_getissuer_function:
+ * @tlist: is a #gnutls_x509_trust_list_t type.
+ * @func: is the callback function
+ *
+ * This function sets a callback to be called when the peer's certificate
+ * chain is incomplete due a missing intermediate certificate/certificates.
+ *
+ * The callback's function prototype is defined in `abstract.h':
+ * int (*callback)(
+ * gnutls_x509_trust_list_t tlist,
+ * const gnutls_x509_crt_t crt);
+ *
+ * If the callback function is provided then gnutls will call it, in the
+ * certificate verification procedure.
+ * To verify or obtain the certificate the verification functions such as
+ * gnutls_x509_trust_list_verify_crt() and gnutls_x509_trust_list_verify_crt2()
+ * can be used.
+ *
+ * The callback function should return 0 if the missing issuer certificate
+ * for 'crt' was properly polulated and added to the 'tlist' using
+ * gnutls_x509_trust_list_add_cas() or non-zero to continue the certificate list
+ * verification but with issuer as %NULL.
+ *
+ * Since: 3.7.0
+ **/
+void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
+               gnutls_x509_trust_list_getissuer_function * func)
+{
+       tlist->issuer_callback = func;
+}
+
 #define TEST_TEXT "test text"
 /* returns error if the certificate has different algorithm than
  * the given key parameters.
index 6807271b2a4f0d532be7688054b42969c155af63..bcb687ce2793816b2ff51edb4af267ad0ff73948 100644 (file)
@@ -1698,6 +1698,12 @@ gnutls_x509_trust_list_add_system_trust(gnutls_x509_trust_list_t
                                        unsigned int tl_flags,
                                        unsigned int tl_vflags);
 
+typedef int gnutls_x509_trust_list_getissuer_function(gnutls_x509_trust_list_t tlist,
+                                                     const gnutls_x509_crt_t crt);
+
+void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
+                               gnutls_x509_trust_list_getissuer_function *func);
+
 void gnutls_certificate_set_trust_list
     (gnutls_certificate_credentials_t res,
      gnutls_x509_trust_list_t tlist, unsigned flags);
index ac6be479f1145663d609f2a7905b0e48e72400a4..e29f064a30b23a629d6f5c3c57040a2bc2e818aa 100644 (file)
@@ -1331,6 +1331,14 @@ GNUTLS_3_6_14
        gnutls_pkcs7_print_signature_info;
 } GNUTLS_3_6_13;
 
+GNUTLS_3_7_0
+{
+ global:
+       gnutls_x509_trust_list_set_getissuer_function;
+ local:
+       *;
+} GNUTLS_3_4;
+
 GNUTLS_FIPS140_3_4 {
   global:
        gnutls_cipher_self_test;
index 40638ad3aab8d94d902958dd5d7cf6e19e666118..763c527a5937a37995fed718778b2cd2a56c1de0 100644 (file)
@@ -851,11 +851,10 @@ static int shorten_clist(gnutls_x509_trust_list_t list,
        return clist_size;
 }
 
-static
-int trust_list_get_issuer(gnutls_x509_trust_list_t list,
-                                     gnutls_x509_crt_t cert,
-                                     gnutls_x509_crt_t * issuer,
-                                     unsigned int flags)
+int _gnutls_trust_list_get_issuer(gnutls_x509_trust_list_t list,
+                                 gnutls_x509_crt_t cert,
+                                 gnutls_x509_crt_t * issuer,
+                                 unsigned int flags)
 {
        int ret;
        unsigned int i;
@@ -968,7 +967,7 @@ int gnutls_x509_trust_list_get_issuer(gnutls_x509_trust_list_t list,
 {
        int ret;
 
-       ret = trust_list_get_issuer(list, cert, issuer, flags);
+       ret = _gnutls_trust_list_get_issuer(list, cert, issuer, flags);
        if (ret == 0) {
                return 0;
        }
@@ -1335,11 +1334,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
        }
 
        *voutput =
-           _gnutls_verify_crt_status(cert_list, cert_list_size,
-                                           list->node[hash].trusted_cas,
-                                           list->
-                                           node[hash].trusted_ca_size,
-                                           flags, purpose, func);
+           _gnutls_verify_crt_status(list, cert_list, cert_list_size,
+                                     list->node[hash].trusted_cas,
+                                     list->node[hash].trusted_ca_size,
+                                     flags, purpose, func);
        saved_output = *voutput;
 
        if (SIGNER_OLD_OR_UNKNOWN(*voutput) &&
@@ -1357,11 +1355,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
                 _gnutls_debug_log("issuer in verification was not found or insecure; trying against trust list\n");
 
                *voutput =
-                   _gnutls_verify_crt_status(cert_list, cert_list_size,
-                                           list->node[hash].trusted_cas,
-                                           list->
-                                           node[hash].trusted_ca_size,
-                                           flags, purpose, func);
+                   _gnutls_verify_crt_status(list, cert_list, cert_list_size,
+                                             list->node[hash].trusted_cas,
+                                             list->node[hash].trusted_ca_size,
+                                             flags, purpose, func);
                if (*voutput != 0) {
                        if (SIGNER_WAS_KNOWN(saved_output))
                                *voutput = saved_output;
@@ -1375,10 +1372,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
        if (SIGNER_OLD_OR_UNKNOWN(*voutput) && list->pkcs11_token) {
                /* use the token for verification */
 
-               *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token,
-                                                               cert_list, cert_list_size,
-                                                               purpose,
-                                                               flags, func);
+               *voutput = _gnutls_pkcs11_verify_crt_status(list, list->pkcs11_token,
+                                                           cert_list, cert_list_size,
+                                                           purpose,
+                                                           flags, func);
                if (*voutput != 0) {
                        if (SIGNER_WAS_KNOWN(saved_output))
                                *voutput = saved_output;
index ca1f98b831ac6a8a37cd84f24a641dc6b8735dd4..6ce5f958aed5fde36029070b062167a59043c2d9 100644 (file)
@@ -39,8 +39,12 @@ struct gnutls_x509_trust_list_st {
         * will be deinitialized */
        gnutls_x509_crt_t *keep_certs;
        unsigned int keep_certs_size;
-       
+
        char* pkcs11_token;
+
+       /* set this callback if the issuer in the certificate
+        * chain is missing. */
+       gnutls_x509_trust_list_getissuer_function *issuer_callback;
 };
 
 int _gnutls_trustlist_inlist(gnutls_x509_trust_list_t list,
index fd7c6a164268cd096be2b84a9cc2aa2ee91cad74..4363e818b12d9e4cf686ebe3a49f38abb9c66ede 100644 (file)
@@ -38,6 +38,7 @@
 #include <x509_int.h>
 #include <common.h>
 #include <pk.h>
+#include <x509/verify-high.h>
 #include "supported_exts.h"
 #include "profiles.h"
 
@@ -604,11 +605,11 @@ static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
                                    gnutls_x509_crt_t issuer,
                                    unsigned vflags);
 
-/* 
+/*
  * Verifies the given certificate against a certificate list of
  * trusted CAs.
  *
- * Returns only 0 or 1. If 1 it means that the certificate 
+ * Returns only 0 or 1. If 1 it means that the certificate
  * was successfully verified.
  *
  * 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
@@ -616,13 +617,13 @@ static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
  * Output will hold some extra information about the verification
  * procedure.
  */
-static unsigned
-verify_crt(gnutls_x509_crt_t cert,
-                           const gnutls_x509_crt_t * trusted_cas,
-                           int tcas_size, unsigned int flags,
-                           unsigned int *output,
-                           verify_state_st *vparams,
-                           unsigned end_cert)
+static unsigned verify_crt(gnutls_x509_trust_list_t tlist,
+                          gnutls_x509_crt_t cert,
+                          const gnutls_x509_crt_t * trusted_cas,
+                          int tcas_size, unsigned int flags,
+                          unsigned int *output,
+                          verify_state_st *vparams,
+                          unsigned end_cert)
 {
        gnutls_datum_t cert_signed_data = { NULL, 0 };
        gnutls_datum_t cert_signature = { NULL, 0 };
@@ -646,6 +647,25 @@ verify_crt(gnutls_x509_crt_t cert,
        if (tcas_size >= 1)
                issuer = find_issuer(cert, trusted_cas, tcas_size);
 
+       if (issuer == NULL && tlist != NULL && tlist->issuer_callback != NULL) {
+               _gnutls_debug_log("Missing issuer callback set.\n");
+
+               /* missing issuer is populated by the callback */
+               ret = tlist->issuer_callback(tlist, cert);
+               if (ret < 0) {
+                       /* if the callback fails, continue as though the callback
+                        * wasn't invoked i.e issuer remains NULL */
+                       gnutls_assert();
+                       issuer = NULL;
+               }
+
+               ret = _gnutls_trust_list_get_issuer(tlist, cert, &issuer, 0);
+               if (ret < 0) {
+                       gnutls_assert();
+                       issuer = NULL;
+               }
+       }
+
        ret =
            _gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate",
                                         &cert_signed_data);
@@ -680,7 +700,7 @@ verify_crt(gnutls_x509_crt_t cert,
        } else {
                if (vparams->nc != NULL) {
                        /* append the issuer's constraints */
-                       ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc, 
+                       ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc,
                                GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, NULL);
                        if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
                                MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
@@ -909,13 +929,14 @@ unsigned check_ca_sanity(const gnutls_x509_crt_t issuer,
  * list should lead to a trusted certificate in order to be trusted.
  */
 unsigned int
-_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
-                               int clist_size,
-                               const gnutls_x509_crt_t * trusted_cas,
-                               int tcas_size,
-                               unsigned int flags,
-                               const char *purpose,
-                               gnutls_verify_output_function func)
+_gnutls_verify_crt_status(gnutls_x509_trust_list_t tlist,
+                         const gnutls_x509_crt_t * certificate_list,
+                         int clist_size,
+                         const gnutls_x509_crt_t * trusted_cas,
+                         int tcas_size,
+                         unsigned int flags,
+                         const char *purpose,
+                         gnutls_verify_output_function func)
 {
        int i = 0, ret;
        unsigned int status = 0, output;
@@ -1010,11 +1031,12 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
         */
        output = 0;
 
-       ret = verify_crt(certificate_list[clist_size - 1],
-                                         trusted_cas, tcas_size, flags,
-                                         &output,
-                                         &vparams,
-                                         clist_size==1?1:0);
+       ret = verify_crt(tlist,
+                         certificate_list[clist_size - 1],
+                        trusted_cas, tcas_size, flags,
+                        &output,
+                        &vparams,
+                        clist_size==1?1:0);
        if (ret != 1) {
                /* if the last certificate in the certificate
                 * list is invalid, then the certificate is not
@@ -1053,11 +1075,12 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
                }
 
                if ((ret =
-                    verify_crt(certificate_list[i - 1],
-                                                &certificate_list[i], 1,
-                                                flags, &output,
-                                                &vparams,
-                                                i==1?1:0)) != 1) {
+                     verify_crt(tlist,
+                                certificate_list[i - 1],
+                               &certificate_list[i], 1,
+                               flags, &output,
+                               &vparams,
+                               i==1?1:0)) != 1) {
                        gnutls_assert();
                        status |= output;
                        status |= GNUTLS_CERT_INVALID;
@@ -1147,12 +1170,13 @@ unsigned _gnutls_check_key_purpose(gnutls_x509_crt_t cert, const char *purpose,
  * list should lead to a trusted certificate in order to be trusted.
  */
 unsigned int
-_gnutls_pkcs11_verify_crt_status(const char* url,
-                               const gnutls_x509_crt_t * certificate_list,
-                               unsigned clist_size,
-                               const char *purpose,
-                               unsigned int flags,
-                               gnutls_verify_output_function func)
+_gnutls_pkcs11_verify_crt_status(gnutls_x509_trust_list_t tlist,
+                                const char* url,
+                                const gnutls_x509_crt_t * certificate_list,
+                                unsigned clist_size,
+                                const char *purpose,
+                                unsigned int flags,
+                                gnutls_verify_output_function func)
 {
        int ret;
        unsigned int status = 0, i;
@@ -1249,9 +1273,10 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
                        ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1],
                                GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE);
                        if (ret != 0) {
-                               return _gnutls_verify_crt_status(certificate_list, clist_size,
-                                       &certificate_list[clist_size - 1], 1, flags,
-                                       purpose, func);
+                               return _gnutls_verify_crt_status(tlist,
+                                               certificate_list, clist_size,
+                                               &certificate_list[clist_size - 1],
+                                               1, flags, purpose, func);
                        }
                }
 
@@ -1260,7 +1285,7 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
                /* verify the certificate list against 0 trusted CAs in order
                 * to get, any additional flags from the certificate list (e.g.,
                 * insecure algorithms or expired */
-               status |= _gnutls_verify_crt_status(certificate_list, clist_size,
+               status |= _gnutls_verify_crt_status(tlist, certificate_list, clist_size,
                                                    NULL, 0, flags, purpose, func);
                goto cleanup;
        }
@@ -1303,8 +1328,8 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
                goto cleanup;
        }
 
-       status = _gnutls_verify_crt_status(certificate_list, clist_size,
-                               &issuer, 1, flags, purpose, func);
+       status = _gnutls_verify_crt_status(tlist, certificate_list, clist_size,
+                                          &issuer, 1, flags, purpose, func);
 
 cleanup:
        gnutls_free(raw_issuer.data);
@@ -1468,18 +1493,20 @@ gnutls_x509_crt_list_verify(const gnutls_x509_crt_t * cert_list,
 {
        unsigned i;
        int ret;
+        gnutls_x509_trust_list_t tlist;
 
        if (cert_list == NULL || cert_list_length == 0)
                return GNUTLS_E_NO_CERTIFICATE_FOUND;
 
-       /* Verify certificate 
+        gnutls_x509_trust_list_init(&tlist, 0);
+
+       /* Verify certificate
         */
-       *verify =
-           _gnutls_verify_crt_status(cert_list, cert_list_length,
+       *verify = _gnutls_verify_crt_status(tlist, cert_list, cert_list_length,
                                            CA_list, CA_list_length,
                                            flags, NULL, NULL);
 
-       /* Check for revoked certificates in the chain. 
+       /* Check for revoked certificates in the chain.
         */
        for (i = 0; i < cert_list_length; i++) {
                ret = gnutls_x509_crt_check_revocation(cert_list[i],
@@ -1491,6 +1518,7 @@ gnutls_x509_crt_list_verify(const gnutls_x509_crt_t * cert_list,
                }
        }
 
+        gnutls_x509_trust_list_deinit(tlist, 0);
        return 0;
 }
 
@@ -1518,12 +1546,17 @@ gnutls_x509_crt_verify(gnutls_x509_crt_t cert,
                       unsigned CA_list_length, unsigned int flags,
                       unsigned int *verify)
 {
-       /* Verify certificate 
+       gnutls_x509_trust_list_t tlist;
+
+       gnutls_x509_trust_list_init(&tlist, 0);
+
+       /* Verify certificate
         */
-       *verify =
-           _gnutls_verify_crt_status(&cert, 1,
+       *verify = _gnutls_verify_crt_status(tlist, &cert, 1,
                                            CA_list, CA_list_length,
                                            flags, NULL, NULL);
+
+       gnutls_x509_trust_list_deinit(tlist, 0);
        return 0;
 }
 
@@ -1533,9 +1566,9 @@ gnutls_x509_crt_verify(gnutls_x509_crt_t cert,
  * @issuer: is the certificate of a possible issuer
  *
  * This function will check if the given CRL was issued by the given
- * issuer certificate.  
+ * issuer certificate.
  *
- * Returns: true (1) if the given CRL was issued by the given issuer, 
+ * Returns: true (1) if the given CRL was issued by the given issuer,
  * and false (0) if not.
  **/
 unsigned
index 050e95059e3b2197fe734cd88693c661ae055c10..a41cc5827a5e5b7ed07904463dcfc6d5e7e6edea 100644 (file)
@@ -495,23 +495,30 @@ gnutls_x509_crt_verify_data3(gnutls_x509_crt_t crt,
                             const gnutls_datum_t *signature,
                             unsigned int flags);
 
+int _gnutls_trust_list_get_issuer(gnutls_x509_trust_list_t list,
+                                 gnutls_x509_crt_t cert,
+                                 gnutls_x509_crt_t * issuer,
+                                 unsigned int flags);
+
 unsigned int
-_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
-                               int clist_size,
-                               const gnutls_x509_crt_t * trusted_cas,
-                               int tcas_size,
-                               unsigned int flags,
-                               const char *purpose,
-                               gnutls_verify_output_function func);
+_gnutls_verify_crt_status(gnutls_x509_trust_list_t tlist,
+                         const gnutls_x509_crt_t * certificate_list,
+                         int clist_size,
+                         const gnutls_x509_crt_t * trusted_cas,
+                         int tcas_size,
+                         unsigned int flags,
+                         const char *purpose,
+                         gnutls_verify_output_function func);
 
 #ifdef ENABLE_PKCS11
 unsigned int
-_gnutls_pkcs11_verify_crt_status(const char* url,
-                               const gnutls_x509_crt_t * certificate_list,
-                               unsigned clist_size,
-                               const char *purpose,
-                               unsigned int flags,
-                               gnutls_verify_output_function func);
+_gnutls_pkcs11_verify_crt_status(gnutls_x509_trust_list_t tlist,
+                                const char* url,
+                                const gnutls_x509_crt_t * certificate_list,
+                                unsigned clist_size,
+                                const char *purpose,
+                                unsigned int flags,
+                                gnutls_verify_output_function func);
 #endif
 
 int _gnutls_check_cert_sanity(gnutls_x509_crt_t cert);