]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
x509: rework issuer callback
authorDaiki Ueno <ueno@gnu.org>
Wed, 11 Nov 2020 18:15:13 +0000 (19:15 +0100)
committerDaiki Ueno <ueno@gnu.org>
Thu, 19 Nov 2020 14:38:02 +0000 (15:38 +0100)
The previous issuer callback API had a drawback: the callback is
supposed to add CA to the trust list by itself.  This was error-prone,
because the callback must check the new CA is trusted by the already
added CA.  This instead moves the responsibility to the library.

This also rewrites the chain amendment logic in a side-effect free
manner.  The application can assume that the trust information stored
on gnutls_x509_trust_list_t shouldn't change after the verification.

The missingissuer test has been extended to cover all the possible
patterns exhaustively.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/cert-cred.c
lib/includes/gnutls/x509.h
lib/x509/verify-high.c
lib/x509/verify.c
src/cli.c
tests/missingissuer.c
tests/missingissuer_aia.c
tests/test-chains-issuer-aia.h
tests/test-chains-issuer.h

index 96f554408478b4f4b2b1696b1d96935c987ce3d0..6208ba72aec5d7ecfbe734e160795697ff1fec1c 100644 (file)
@@ -890,13 +890,21 @@ void
  * 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);
+ * The callback's function prototype is defined in <gnutls/x509.h> as:
+ *
+ *   int (*callback)(gnutls_x509_trust_list_t list,
+ *                   const gnutls_x509_crt_t cert,
+ *                   gnutls_x509_crt_t **issuers,
+ *                   unsigned int *issuers_size);
  *
  * If the callback function is provided then gnutls will call it, in the
  * certificate verification procedure.
+ *
+ * On a successful call, the callback shall allocate the 'issuers' array with
+ * gnutls_x509_crt_list_import2(). The ownership of both the array and the
+ * elements is transferred to the caller and thus the application does not need
+ * to maintain the memory after the call.
+ *
  * 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.
index 001aeb77db5f7280b19c71ad4270d0256defc401..5f54e888bc01044451301af7878ea8aa6882eec5 100644 (file)
@@ -1702,8 +1702,10 @@ 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);
+typedef int gnutls_x509_trust_list_getissuer_function(gnutls_x509_trust_list_t list,
+                                                     const gnutls_x509_crt_t cert,
+                                                     gnutls_x509_crt_t **issuers,
+                                                     unsigned int *issuers_size);
 
 void gnutls_x509_trust_list_set_getissuer_function(gnutls_x509_trust_list_t tlist,
                                gnutls_x509_trust_list_getissuer_function *func);
index 9c4f292f058dd91519cef41cc20d64ee656cc722..588e7ee0dc4eec944e9ef93593e47c171ee82681 100644 (file)
@@ -851,6 +851,67 @@ static int shorten_clist(gnutls_x509_trust_list_t list,
        return clist_size;
 }
 
+/* Takes a subject certificate, retrieves a chain from its issuers in
+ * @certificate_list, using the issuer callback set for @list.
+ *
+ * Returns the new size of the list or a negative number on error.
+ */
+static int
+retrieve_issuers(gnutls_x509_trust_list_t list,
+                gnutls_x509_crt_t subject,
+                gnutls_x509_crt_t *certificate_list,
+                unsigned int clist_size_max)
+{
+       gnutls_x509_crt_t *issuers;
+       unsigned int issuers_size;
+       unsigned int i;
+       int ret;
+
+       if (!list->issuer_callback) {
+               return 0;
+       }
+
+       _gnutls_cert_log("calling issuer callback on", subject);
+
+       ret = list->issuer_callback(list, subject, &issuers, &issuers_size);
+       if (ret < 0) {
+               return gnutls_assert_val(ret);
+       }
+
+       /* Ignore empty list */
+       if (!issuers_size) {
+               ret = 0;
+               goto cleanup;
+       }
+
+       if (issuers_size > clist_size_max) {
+               _gnutls_debug_log("too many issuers returned; skipping\n");
+               ret = 0;
+               goto cleanup;
+       }
+
+       for (i = 0; i < issuers_size; i++) {
+               if (!gnutls_x509_crt_check_issuer(subject, issuers[i])) {
+                       _gnutls_cert_log("unrelated certificate; skipping",
+                                        issuers[i]);
+                       break;
+               }
+               subject = issuers[i];
+       }
+
+       ret = i;
+
+       memcpy(certificate_list, issuers, ret * sizeof(gnutls_x509_crt_t));
+
+ cleanup:
+       for (i = ret; i < issuers_size; i++) {
+               gnutls_x509_crt_deinit(issuers[i]);
+       }
+       gnutls_free(issuers);
+
+       return ret;
+}
+
 int _gnutls_trust_list_get_issuer(gnutls_x509_trust_list_t list,
                                  gnutls_x509_crt_t cert,
                                  gnutls_x509_crt_t * issuer,
@@ -1248,18 +1309,20 @@ gnutls_x509_trust_list_verify_crt(gnutls_x509_trust_list_t list,
  **/
 int
 gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
-                                 gnutls_x509_crt_t * cert_list,
-                                 unsigned int cert_list_size,
-                                 gnutls_typed_vdata_st *data,
-                                 unsigned int elements,
-                                 unsigned int flags,
-                                 unsigned int *voutput,
-                                 gnutls_verify_output_function func)
+                                  gnutls_x509_crt_t * cert_list,
+                                  unsigned int cert_list_size,
+                                  gnutls_typed_vdata_st *data,
+                                  unsigned int elements,
+                                  unsigned int flags,
+                                  unsigned int *voutput,
+                                  gnutls_verify_output_function func)
 {
-       int ret;
+       int ret = 0;
        unsigned int i;
        size_t hash;
        gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH];
+       gnutls_x509_crt_t retrieved[DEFAULT_MAX_VERIFY_DEPTH];
+       unsigned int retrieved_size = 0;
        const char *hostname = NULL, *purpose = NULL, *email = NULL;
        unsigned hostname_size = 0;
        unsigned have_set_name = 0;
@@ -1310,13 +1373,56 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
                }
        }
 
-       if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN) &&
-           cert_list_size <= DEFAULT_MAX_VERIFY_DEPTH) {
-               for (i = 0; i < cert_list_size; i++) {
-                       sorted[i] = cert_list[i];
+       memcpy(sorted, cert_list, cert_list_size * sizeof(gnutls_x509_crt_t));
+       cert_list = sorted;
+
+       for (i = 0; i < cert_list_size &&
+                    cert_list_size <= DEFAULT_MAX_VERIFY_DEPTH; i++) {
+               if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN)) {
+                       unsigned int sorted_size;
+
+                       sorted_size = _gnutls_sort_clist(&cert_list[i],
+                                                        cert_list_size - i);
+                       i += sorted_size - 1;
+               }
+
+               if (i == cert_list_size - 1) {
+                       gnutls_x509_crt_t issuer;
+
+                       /* If it is the last certificate and its issuer is
+                        * known, don't need to run issuer callback. */
+                       if (_gnutls_trust_list_get_issuer(list,
+                                                         cert_list[i],
+                                                         &issuer,
+                                                         0) == 0) {
+                               break;
+                       }
+               } else if (gnutls_x509_crt_check_issuer(cert_list[i],
+                                                       cert_list[i + 1])) {
+                       /* There is no gap between this and the next
+                        * certificate. */
+                       continue;
+               }
+
+               ret = retrieve_issuers(list,
+                                      cert_list[i],
+                                      &retrieved[retrieved_size],
+                                      DEFAULT_MAX_VERIFY_DEPTH -
+                                      MAX(retrieved_size,
+                                          cert_list_size));
+               if (ret < 0) {
+                       break;
+               } else if (ret > 0) {
+                       memmove(&cert_list[i + 1 + ret],
+                               &cert_list[i + 1],
+                               (cert_list_size - i - 1) *
+                               sizeof(gnutls_x509_crt_t));
+                       memcpy(&cert_list[i + 1],
+                              &retrieved[retrieved_size],
+                              ret * sizeof(gnutls_x509_crt_t));
+                       retrieved_size += ret;
+                       cert_list_size += ret;
                }
-               cert_list = sorted;
-               cert_list_size = _gnutls_sort_clist(cert_list, cert_list_size);
        }
 
        cert_list_size = shorten_clist(list, cert_list, cert_list_size);
@@ -1336,7 +1442,8 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
                *voutput = 0;
                *voutput |= GNUTLS_CERT_REVOKED;
                *voutput |= GNUTLS_CERT_INVALID;
-               return 0;
+               ret = 0;
+               goto cleanup;
        }
 
        *voutput =
@@ -1428,8 +1535,10 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
 
        /* CRL checks follow */
 
-       if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS))
-               return 0;
+       if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) {
+               ret = 0;
+               goto cleanup;
+       }
 
        /* Check revocation of individual certificates.
         * start with the last one that we already have its hash
@@ -1443,7 +1552,8 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
        if (ret == 1) {         /* revoked */
                *voutput |= GNUTLS_CERT_REVOKED;
                *voutput |= GNUTLS_CERT_INVALID;
-               return 0;
+               ret = 0;
+               goto cleanup;
        }
 
        for (i = 0; i < cert_list_size - 1; i++) {
@@ -1462,11 +1572,16 @@ gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list,
                } else if (ret == 1) {  /* revoked */
                        *voutput |= GNUTLS_CERT_REVOKED;
                        *voutput |= GNUTLS_CERT_INVALID;
-                       return 0;
+                       ret = 0;
+                       goto cleanup;
                }
        }
 
-       return 0;
+ cleanup:
+       for (i = 0; i < retrieved_size; i++) {
+               gnutls_x509_crt_deinit(retrieved[i]);
+       }
+       return ret;
 }
 
 /**
index ee9bdd57f5db136d0663e91bbec313a4a7a33bec..b8af47c6b16c2d145c47bb2b2cb64883adde27d6 100644 (file)
@@ -647,25 +647,6 @@ static unsigned verify_crt(gnutls_x509_trust_list_t tlist,
        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);
index a451dc3bddde55f02959b1442eb12ade15238ad2..2384a0cab346fdcdf11f034f94b30cf1fec3c96f 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -126,7 +126,9 @@ static int cert_verify_ocsp(gnutls_session_t session);
 static const char *host_from_url(const char *url, unsigned int *port, const char **path);
 static size_t get_data(void *buf, size_t size, size_t nmemb, void *userp);
 static int getissuer_callback(const gnutls_x509_trust_list_t tlist,
-               const gnutls_x509_crt_t cert);
+                             const gnutls_x509_crt_t cert,
+                             gnutls_x509_crt_t **issuers,
+                             unsigned int *issuers_size);
 
 #define MAX_CRT 6
 static unsigned int x509_crt_size;
@@ -2240,7 +2242,9 @@ static size_t get_data(void *buf, size_t size, size_t nmemb, void *userp)
 /* Returns 0 on ok, and -1 on error */
 static int
 getissuer_callback(const gnutls_x509_trust_list_t tlist,
-                               const gnutls_x509_crt_t cert)
+                  const gnutls_x509_crt_t cert,
+                  gnutls_x509_crt_t **issuers,
+                  unsigned int *issuers_size)
 {
        gnutls_datum_t ud;
        int ret;
@@ -2331,18 +2335,13 @@ getissuer_callback(const gnutls_x509_trust_list_t tlist,
                ret = -1;
                goto cleanup;
        }
-       ret = gnutls_x509_crt_import(issuer, &resp, GNUTLS_X509_FMT_DER);
+       ret = gnutls_x509_crt_list_import2(issuers, issuers_size, &resp,
+                                          GNUTLS_X509_FMT_DER, 0);
        if (ret < 0) {
                fprintf(stderr, "Decoding error: %s\n", gnutls_strerror(ret));
                ret = -1;
                goto cleanup;
        }
-       ret = gnutls_x509_trust_list_add_cas(tlist, &issuer, 1, 0);
-       if (ret < 0) {
-               fprintf(stderr, "Memory error\n");
-               ret = -1;
-               goto cleanup;
-       }
 
        ret = 0;
 
index 49fef8f7b323247c42e0321e10807d2c8f93e714..f21e2b6b0cb349c1f0c4f4927df34220360ca1de 100644 (file)
@@ -36,7 +36,7 @@
 #include "utils.h"
 #include "test-chains-issuer.h"
 
-#define DEFAULT_THEN 1256803113
+#define DEFAULT_THEN 1605514504
 static time_t then = DEFAULT_THEN;
 
 /* GnuTLS internally calls time() to find out the current time when
@@ -56,34 +56,37 @@ static void tls_log_func(int level, const char *str)
        fprintf(stderr, "|<%d>| %s", level, str);
 }
 
+struct getissuer_data {
+       const char **insert;
+       unsigned int count;
+};
+
 static int getissuer_callback(gnutls_x509_trust_list_t tlist,
-                             const gnutls_x509_crt_t crt)
+                             const gnutls_x509_crt_t crt,
+                             gnutls_x509_crt_t **issuers,
+                             unsigned int *issuers_size)
 {
-       gnutls_x509_crt_t issuer;
        gnutls_datum_t tmp;
        int ret;
+       unsigned int i;
+       struct getissuer_data *data;
 
-       ret = gnutls_x509_crt_init(&issuer);
-       if (ret < 0) {
-               fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
+       data = gnutls_x509_trust_list_get_ptr(tlist);
+
+       tmp.data = (unsigned char *)data->insert[data->count];
+       if (!tmp.data) {
+               fprintf(stderr, "getissuer_callback is called more times than expected\n");
                return -1;
        }
 
-       tmp.data = (unsigned char *)missing_cert_insert;
-       tmp.size = strlen(missing_cert_insert);
+       tmp.size = strlen(data->insert[data->count]);
 
-       ret = gnutls_x509_crt_import(issuer, &tmp, GNUTLS_X509_FMT_PEM);
-       if (ret < 0) {
-               fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
-               gnutls_x509_crt_deinit(issuer);
-               return -1;
-       }
+       data->count++;
 
-       /* This transfers the ownership of `issuer` to `tlist`. */
-       ret = gnutls_x509_trust_list_add_cas(tlist, &issuer, 1, 0);
+       ret = gnutls_x509_crt_list_import2(issuers, issuers_size, &tmp,
+                                          GNUTLS_X509_FMT_PEM, 0);
        if (ret < 0) {
                fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
-               gnutls_x509_crt_deinit(issuer);
                return -1;
        }
 
@@ -94,14 +97,16 @@ static int getissuer_callback(gnutls_x509_trust_list_t tlist,
                                tmp.size, tmp.data);
        gnutls_free(tmp.data);
 
-       assert(gnutls_x509_crt_print(issuer, GNUTLS_CRT_PRINT_ONELINE, &tmp) >= 0);
+       for (i = 0; i < *issuers_size; i++) {
+               assert(gnutls_x509_crt_print((*issuers)[i], GNUTLS_CRT_PRINT_ONELINE, &tmp) >= 0);
 
-       if (debug)
-               printf("\t Appended issuer certificate is: %.*s\n",
-                               tmp.size, tmp.data);
-       gnutls_free(tmp.data);
-       return 0;
+               if (debug)
+                       printf("\t Appended issuer certificate is: %.*s\n",
+                              tmp.size, tmp.data);
+               gnutls_free(tmp.data);
+       }
 
+       return 0;
 }
 
 void doit(void)
@@ -113,7 +118,7 @@ void doit(void)
        gnutls_x509_crt_t certs[MAX_CHAIN];
        gnutls_x509_crt_t ca;
        gnutls_datum_t tmp;
-       size_t j;
+       size_t i, j;
 
        /* The overloading of time() seems to work in linux (ELF?)
         * systems only. Disable it on windows.
@@ -134,103 +139,127 @@ void doit(void)
        if (debug)
                gnutls_global_set_log_level(4711);
 
-       for (j = 0; j < MAX_CHAIN; j++) {
-               if (debug > 2)
-                       printf("\tAdding certificate %d...", (int)j);
+       for (i = 0; chains[i].chain; i++) {
+               struct getissuer_data data;
 
-               ret = gnutls_x509_crt_init(&certs[j]);
-               if (ret < 0) {
-                       fprintf(stderr,
-                                       "gnutls_x509_crt_init[%d]: %s\n",
-                                       (int)j, gnutls_strerror(ret));
-                       exit(1);
-               }
+               printf("[%d]: Chain '%s'...\n", (int)i, chains[i].name);
 
-               tmp.data = (unsigned char *)missing_issuer_chain[j];
-               tmp.size = strlen(missing_issuer_chain[j]);
+               for (j = 0; chains[i].chain[j]; j++) {
+                       if (debug > 2)
+                               printf("\tAdding certificate %d...", (int)j);
 
-               ret =
-                       gnutls_x509_crt_import(certs[j], &tmp,
-                                       GNUTLS_X509_FMT_PEM);
-               if (debug > 2)
-                       printf("done\n");
-               if (ret < 0) {
-                       fprintf(stderr,
+                       ret = gnutls_x509_crt_init(&certs[j]);
+                       if (ret < 0) {
+                               fprintf(stderr,
+                                       "gnutls_x509_crt_init[%d]: %s\n",
+                                       (int)j, gnutls_strerror(ret));
+                               exit(1);
+                       }
+
+                       tmp.data = (unsigned char *)chains[i].chain[j];
+                       tmp.size = strlen(chains[i].chain[j]);
+
+                       ret =
+                               gnutls_x509_crt_import(certs[j], &tmp,
+                                                      GNUTLS_X509_FMT_PEM);
+                       if (debug > 2)
+                               printf("done\n");
+                       if (ret < 0) {
+                               fprintf(stderr,
                                        "gnutls_x509_crt_import[%d]: %s\n",
                                        (int)j,
                                        gnutls_strerror(ret));
-                       exit(1);
+                               exit(1);
+                       }
+
+                       gnutls_x509_crt_print(certs[j],
+                                             GNUTLS_CRT_PRINT_ONELINE, &tmp);
+                       if (debug)
+                               printf("\tCertificate %d: %.*s\n", (int)j,
+                                      tmp.size, tmp.data);
+                       gnutls_free(tmp.data);
                }
 
-               gnutls_x509_crt_print(certs[j],
-                               GNUTLS_CRT_PRINT_ONELINE, &tmp);
-               if (debug)
-                       printf("\tCertificate %d: %.*s\n", (int)j,
-                                       tmp.size, tmp.data);
-               gnutls_free(tmp.data);
-       }
-
-       if (debug > 2)
-               printf("\tAdding CA certificate...");
+               if (debug > 2)
+                       printf("\tAdding CA certificate...");
 
-       ret = gnutls_x509_crt_init(&ca);
-       if (ret < 0) {
-               fprintf(stderr, "gnutls_x509_crt_init: %s\n",
+               ret = gnutls_x509_crt_init(&ca);
+               if (ret < 0) {
+                       fprintf(stderr, "gnutls_x509_crt_init: %s\n",
                                gnutls_strerror(ret));
-               exit(1);
-       }
+                       exit(1);
+               }
 
-       tmp.data = (unsigned char *)missing_issuer_chain[MAX_CHAIN-1];
-       tmp.size = strlen(missing_issuer_chain[MAX_CHAIN-1]);
+               tmp.data = (unsigned char *)*chains[i].ca;
+               tmp.size = strlen(*chains[i].ca);
 
-       ret = gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM);
-       if (ret < 0) {
-               fprintf(stderr, "gnutls_x509_crt_import: %s\n",
+               ret = gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM);
+               if (ret < 0) {
+                       fprintf(stderr, "gnutls_x509_crt_import: %s\n",
                                gnutls_strerror(ret));
-               exit(1);
-       }
+                       exit(1);
+               }
 
-       if (debug > 2)
-               printf("done\n");
+               if (debug > 2)
+                       printf("done\n");
 
-       gnutls_x509_crt_print(ca, GNUTLS_CRT_PRINT_ONELINE, &tmp);
-       if (debug)
-               printf("\tCA Certificate: %.*s\n", tmp.size, tmp.data);
-       gnutls_free(tmp.data);
+               gnutls_x509_crt_print(ca, GNUTLS_CRT_PRINT_ONELINE, &tmp);
+               if (debug)
+                       printf("\tCA Certificate: %.*s\n", tmp.size, tmp.data);
+               gnutls_free(tmp.data);
 
-       if (debug)
-               printf("\tVerifying...");
+               if (debug)
+                       printf("\tVerifying...");
 
-       gnutls_x509_trust_list_init(&tl, 0);
+               gnutls_x509_trust_list_init(&tl, 0);
 
-       ret = gnutls_x509_trust_list_add_cas(tl, &ca, 1, 0);
-       if (ret != 1) {
-               fail("gnutls_x509_trust_list_add_trust_mem\n");
-               exit(1);
-       }
+               ret = gnutls_x509_trust_list_add_cas(tl, &ca, 1, 0);
+               if (ret != 1) {
+                       fail("gnutls_x509_trust_list_add_trust_mem\n");
+                       exit(1);
+               }
 
-       gnutls_x509_trust_list_set_getissuer_function(tl, getissuer_callback);
+               data.count = 0;
+               data.insert = chains[i].insert;
 
-       ret = gnutls_x509_trust_list_verify_crt(tl, certs, MAX_CHAIN,
-                       0,
-                       &verify_status,
-                       NULL);
-       if (ret < 0) {
-               fprintf(stderr,
-                               "gnutls_x509_crt_list_verify: %s\n", gnutls_strerror(ret));
-               exit(1);
-       }
+               gnutls_x509_trust_list_set_ptr(tl, &data);
+               gnutls_x509_trust_list_set_getissuer_function(tl, getissuer_callback);
 
-       if (debug)
-               printf("\tCleanup...");
+               ret = gnutls_x509_trust_list_verify_crt(tl, certs, j,
+                                                       chains[i].verify_flags,
+                                                       &verify_status,
+                                                       NULL);
+               if (ret < 0) {
+                       fprintf(stderr,
+                               "gnutls_x509_trust_list_verify_crt: %s\n", gnutls_strerror(ret));
+                       exit(1);
+               }
 
-       gnutls_x509_trust_list_deinit(tl, 1);
+               if (verify_status != chains[i].expected_verify_result) {
+                       gnutls_datum_t out1, out2;
+                       gnutls_certificate_verification_status_print
+                               (verify_status, GNUTLS_CRT_X509, &out1, 0);
+                       gnutls_certificate_verification_status_print
+                               (chains[i].expected_verify_result,
+                                GNUTLS_CRT_X509, &out2, 0);
+                       fail("chain[%s]:\nverify_status: %d: %s\nexpected: %d: %s\n", chains[i].name, verify_status, out1.data, chains[i].expected_verify_result, out2.data);
+                       gnutls_free(out1.data);
+                       gnutls_free(out2.data);
+
+               } else if (debug)
+                       printf("done\n");
 
-       for (j = 0; j < MAX_CHAIN; j++)
-               gnutls_x509_crt_deinit(certs[j]);
+               if (debug)
+                       printf("\tCleanup...");
 
-       if (debug)
-               printf("done\n\n\n");
+               gnutls_x509_trust_list_deinit(tl, 0);
+               gnutls_x509_crt_deinit(ca);
+               for (j = 0; chains[i].chain[j]; j++)
+                       gnutls_x509_crt_deinit(certs[j]);
+
+               if (debug)
+                       printf("done\n\n\n");
+       }
 
        gnutls_global_deinit();
 
index 24f71ec96813b4fbaf58f271e864649670f3c7f1..1e68305f1fe86dca70202c5bb9a46a16fa4ccc12 100644 (file)
@@ -36,7 +36,7 @@
 #include "utils.h"
 #include "test-chains-issuer-aia.h"
 
-#define DEFAULT_THEN 1256803113
+#define DEFAULT_THEN 1605443778
 static time_t then = DEFAULT_THEN;
 
 /* GnuTLS internally calls time() to find out the current time when
@@ -57,12 +57,14 @@ static void tls_log_func(int level, const char *str)
 }
 
 static int getissuer_callback(gnutls_x509_trust_list_t tlist,
-                             const gnutls_x509_crt_t crt)
+                             const gnutls_x509_crt_t crt,
+                             gnutls_x509_crt_t **issuers,
+                             unsigned int *issuers_size)
 {
        int ret;
-       gnutls_x509_crt_t issuer;
        gnutls_datum_t aia;
        gnutls_datum_t tmp;
+       unsigned int i;
 
        assert(gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &tmp) >= 0);
 
@@ -71,12 +73,6 @@ static int getissuer_callback(gnutls_x509_trust_list_t tlist,
                                tmp.size, tmp.data);
        gnutls_free(tmp.data);
 
-       ret = gnutls_x509_crt_init(&issuer);
-       if (ret < 0) {
-               fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
-               return -1;
-       }
-
        ret = gnutls_x509_crt_get_authority_info_access(crt, 1,
                        GNUTLS_IA_CAISSUERS_URI, &aia, NULL);
        if (ret < 0) {
@@ -93,27 +89,22 @@ static int getissuer_callback(gnutls_x509_trust_list_t tlist,
        tmp.data = (unsigned char *)missing_cert_aia_insert;
        tmp.size = strlen(missing_cert_aia_insert);
 
-       ret = gnutls_x509_crt_import(issuer, &tmp, GNUTLS_X509_FMT_PEM);
+       ret = gnutls_x509_crt_list_import2(issuers, issuers_size, &tmp,
+                                          GNUTLS_X509_FMT_PEM, 0);
        if (ret < 0) {
                fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
-               gnutls_x509_crt_deinit(issuer);
                return -1;
        }
 
-       /* This transfers the ownership of `issuer` to `tlist`. */
-       ret = gnutls_x509_trust_list_add_cas(tlist, &issuer, 1, 0);
-       if (ret < 0) {
-               fprintf(stderr, "error: %s\n", gnutls_strerror(ret));
-               gnutls_x509_crt_deinit(issuer);
-               return -1;
-       }
+       for (i = 0; i < *issuers_size; i++) {
+               assert(gnutls_x509_crt_print(*issuers[i], GNUTLS_CRT_PRINT_ONELINE, &tmp) >= 0);
 
-       assert(gnutls_x509_crt_print(issuer, GNUTLS_CRT_PRINT_ONELINE, &tmp) >= 0);
+               if (debug)
+                       printf("\t Appended missing certificate is: %.*s\n",
+                              tmp.size, tmp.data);
+               gnutls_free(tmp.data);
+       }
 
-       if (debug)
-               printf("\t Appended missing certificate is: %.*s\n",
-                               tmp.size, tmp.data);
-       gnutls_free(tmp.data);
        return 0;
 }
 
@@ -138,7 +129,6 @@ void doit(void)
        ret = global_init();
        if (ret != 0) {
                fail("%d: %s\n", ret, gnutls_strerror(ret));
-               exit(1);
        }
 
        gnutls_global_set_time_function(mytime);
@@ -193,8 +183,8 @@ void doit(void)
                exit(1);
        }
 
-       tmp.data = (unsigned char *)missing_cert_aia[MAX_CHAIN-1];
-       tmp.size = strlen(missing_cert_aia[MAX_CHAIN-1]);
+       tmp.data = (unsigned char *)missing_cert_aia_ca[0];
+       tmp.size = strlen(missing_cert_aia_ca[0]);
 
        ret = gnutls_x509_crt_import(ca, &tmp, GNUTLS_X509_FMT_PEM);
        if (ret < 0) {
@@ -219,7 +209,6 @@ void doit(void)
        ret = gnutls_x509_trust_list_add_cas(tl, &ca, 1, 0);
        if (ret != 1) {
                fail("gnutls_x509_trust_list_add_trust_mem\n");
-               exit(1);
        }
 
        gnutls_x509_trust_list_set_getissuer_function(tl, getissuer_callback);
@@ -229,9 +218,15 @@ void doit(void)
                        &verify_status,
                        NULL);
        if (ret < 0) {
-               fprintf(stderr,
-                               "gnutls_x509_crt_list_verify: %s\n", gnutls_strerror(ret));
-               exit(1);
+               fail("gnutls_x509_crt_list_verify: %s\n", gnutls_strerror(ret));
+       }
+       if (verify_status) {
+               gnutls_datum_t out;
+
+               gnutls_certificate_verification_status_print
+                       (verify_status, GNUTLS_CRT_X509, &out, 0);
+               fail("verification failed: %s\n", out.data);
+               gnutls_free(out.data);
        }
 
        if (debug)
index ca75fd3b7cff6595472b52a290bffb5fe50926c5..1377bb034d818b75a3566d9ed3c7bbfcd0886ec8 100644 (file)
@@ -98,6 +98,36 @@ static const char *missing_cert_aia_insert = {
        "-----END CERTIFICATE-----\n"
 };
 
+static const char *missing_cert_aia_ca[] = {
+       "-----BEGIN CERTIFICATE-----\n"
+       "MIIElDCCA3ygAwIBAgIQAf2j627KdciIQ4tyS8+8kTANBgkqhkiG9w0BAQsFADBh\n"
+       "MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
+       "d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD\n"
+       "QTAeFw0xMzAzMDgxMjAwMDBaFw0yMzAzMDgxMjAwMDBaME0xCzAJBgNVBAYTAlVT\n"
+       "MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxJzAlBgNVBAMTHkRpZ2lDZXJ0IFNIQTIg\n"
+       "U2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n"
+       "ANyuWJBNwcQwFZA1W248ghX1LFy949v/cUP6ZCWA1O4Yok3wZtAKc24RmDYXZK83\n"
+       "nf36QYSvx6+M/hpzTc8zl5CilodTgyu5pnVILR1WN3vaMTIa16yrBvSqXUu3R0bd\n"
+       "KpPDkC55gIDvEwRqFDu1m5K+wgdlTvza/P96rtxcflUxDOg5B6TXvi/TC2rSsd9f\n"
+       "/ld0Uzs1gN2ujkSYs58O09rg1/RrKatEp0tYhG2SS4HD2nOLEpdIkARFdRrdNzGX\n"
+       "kujNVA075ME/OV4uuPNcfhCOhkEAjUVmR7ChZc6gqikJTvOX6+guqw9ypzAO+sf0\n"
+       "/RR3w6RbKFfCs/mC/bdFWJsCAwEAAaOCAVowggFWMBIGA1UdEwEB/wQIMAYBAf8C\n"
+       "AQAwDgYDVR0PAQH/BAQDAgGGMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY\n"
+       "aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6\n"
+       "Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RDQS5jcmwwN6A1\n"
+       "oDOGMWh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEdsb2JhbFJvb3RD\n"
+       "QS5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8v\n"
+       "d3d3LmRpZ2ljZXJ0LmNvbS9DUFMwHQYDVR0OBBYEFA+AYRyCMWHVLyjnjUY4tCzh\n"
+       "xtniMB8GA1UdIwQYMBaAFAPeUDVW0Uy7ZvCj4hsbw5eyPdFVMA0GCSqGSIb3DQEB\n"
+       "CwUAA4IBAQAjPt9L0jFCpbZ+QlwaRMxp0Wi0XUvgBCFsS+JtzLHgl4+mUwnNqipl\n"
+       "5TlPHoOlblyYoiQm5vuh7ZPHLgLGTUq/sELfeNqzqPlt/yGFUzZgTHbO7Djc1lGA\n"
+       "8MXW5dRNJ2Srm8c+cftIl7gzbckTB+6WohsYFfZcTEDts8Ls/3HB40f/1LkAtDdC\n"
+       "2iDJ6m6K7hQGrn2iWZiIqBtvLfTyyRRfJs8sjX7tN8Cp1Tm5gr8ZDOo0rwAhaPit\n"
+       "c+LJMto4JQtV05od8GiG7S5BNO98pVAdvzr508EIDObtHopYJeS4d60tbvVS3bR0\n"
+       "j6tJLp07kzQoH3jOlOrHvdPJbRzeXDLz\n"
+       "-----END CERTIFICATE-----\n",
+};
+
 #if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
 #  pragma GCC diagnostic pop
 #endif
index 730a31fed40a66ceedd3fef6631d4b8ef6621fe0..543e2d71fb2dc262b8078677f79c7d709c6d79b3 100644 (file)
@@ -2,7 +2,8 @@
  * Copyright (C) 2008-2014 Free Software Foundation, Inc.
  * Copyright (C) 2017 Red Hat, Inc.
  *
- * Authors: Simon Josefsson, Nikos Mavrogiannopoulos, Martin Ukrop
+ * Authors: Simon Josefsson, Nikos Mavrogiannopoulos, Martin Ukrop,
+ *   Sahana Prasad, Daiki Ueno
  *
  * This file is part of GnuTLS.
  *
 #ifndef GNUTLS_TESTS_TEST_CHAINS_ISSUER_H
 #define GNUTLS_TESTS_TEST_CHAINS_ISSUER_H
 
-/* *INDENT-OFF* */
-
 #define MAX_CHAIN 6
 
-static const char *missing_issuer_chain[] = {
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIDATCCAbmgAwIBAgIUQdvdegP8JFszFHLfV4+lrEdafzAwPQYJKoZIhvcNAQEK\n"
-       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n"
-       "AUAwDzENMAsGA1UEAxMEQ0EtNTAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n"
-       "NTk1OVowEzERMA8GA1UEAxMIc2VydmVyLTYwgZswEAYHKoZIzj0CAQYFK4EEACMD\n"
-       "gYYABAHZ3W5jpYq15WI7tVZxWCT3YtYMEj4xJSdO/ubHV0NnrlQ7+Q95R32qcA2w\n"
-       "4gyPif+M/Au4Towr/RA+b+qgMvD0fQFmNeWkNB/TSW2RNm7uHQU7N66tbrNWvjyS\n"
-       "BZeLB/V03ZWe+rO4cfrPiqtBv9N08k9uMNNCeMlatJNqj0BoFRxhBaN3MHUwDAYD\n"
-       "VR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwDwYDVR0PAQH/BAUDAweA\n"
-       "ADAdBgNVHQ4EFgQUMnSJQI2iHiVoxE1XSByQ9QFrG0owHwYDVR0jBBgwFoAUu9ao\n"
-       "G/58Y/+czHPyWo3C+vs9pFkwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgGh\n"
-       "GjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEBAAfhLT1jQsc9yk4k\n"
-       "myAAMIXYD1THMkasGZiIv2TLJSLeKc4Rvzvrb/iywwrMdaBHs5sJoyk7amMwemc7\n"
-       "WA2+A2uTeLeDG3ev4r5stNRLyL0HSOr7da+BshUiHJgeihp1Qglm0AUqV5X69i5t\n"
-       "5woB5KENnYfoAWaYmXa1EPRh2xb2XDI0uCHg1bPljg61/T2cJZ4VfkOvsKgFAI4p\n"
-       "lAKQCZSKbEY1oWDdDhVcSipYu2E88RXczvcnEQV3C3p6CGcf8xclZdZIwMAyXYAK\n"
-       "oNccbSIfDlN4iD+2bztCRWHD6hWL1NJsFqmv3Ts8eYU8z8J8NdhtCXr76lFkFmDx\n"
-       "+lfZEv4=\n"
-       "-----END CERTIFICATE-----\n",
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIDojCCAlqgAwIBAgIUHRb3xJ2ZGqqgdC/pBq/sDtAwvtowPQYJKoZIhvcNAQEK\n"
-       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n"
-       "AUAwDzENMAsGA1UEAxMEQ0EtNDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n"
-       "NTk1OVowDzENMAsGA1UEAxMEQ0EtNTCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n"
-       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n"
-       "AQoCggEBAMZqQ7I1HAxkxuwGQBch/jZTWLXRUtWBjlpREnp0wFt+quJOZkKNYrlL\n"
-       "9sngiRknsbEIfJMB2XfoK6m9SwRN/qoxewOrnK9YONG9dj0p30qiseshXIs6ZoMl\n"
-       "v9fZA77UraCtTbX6Xwk/+Or6SuSK2lyz0R5O14xBa5ubpm2Q8XTE9A1SAGx61ofC\n"
-       "Dzfvefp+m3QCy+3K+Yn05VKPxswznuVwM/oJDGzJJhD6/uNPpm5CZoPtcW14Eitu\n"
-       "ip51Ej1VE4lJRBHAtUSOrd3Hks6YasK7Uvu0HjpqW7PqaIhJIR7ofzbXX2vBwVj2\n"
-       "Qlwozk4cVCP7XO3VrVu/GCdSL+G3RAUCAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n"
-       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBS71qgb/nxj/5zMc/JajcL6+z2k\n"
-       "WTAfBgNVHSMEGDAWgBQPB7C8f3nco30et23Lhw7QMTaLYzA9BgkqhkiG9w0BAQow\n"
-       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n"
-       "QAOCAQEAl90uQvD0lne4jseHNfu8XCIZmCSxaNhF3SD73TwlGERbRjtIKz34Y6hC\n"
-       "z5bZ4tCGnkKAtdHLIGwOnaLSXDvzmUSkQmJmG0QMaDGsVpVXEZD/7+yyIxOcV1iK\n"
-       "XveeQysCKsDEfdrfn1mACQj8eC4lL9KJcHptHdTSLfa58MV2Qe5smCIByXxendO5\n"
-       "UQHZy5UrzWAdtO7y75vXeXynsXAqcE4TTNjdFiCnn6Q5/pVyW14kepfjaOzQFP7H\n"
-       "QlnHtgQDRAlQuB1aGseb6jn2Joy33itpBthvtgBosZIqsMyPoX5YzjqZUSjfPZOP\n"
-       "/aOd/5HR4ZPDWfHdIWbXogYX0ndhNg==\n"
-       "-----END CERTIFICATE-----\n",
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIDojCCAlqgAwIBAgIUGybZZ1e/iFUKafPdh8xUbh7YVnwwPQYJKoZIhvcNAQEK\n"
-       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n"
-       "AUAwDzENMAsGA1UEAxMEQ0EtMzAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n"
-       "NTk1OVowDzENMAsGA1UEAxMEQ0EtNDCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n"
-       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n"
-       "AQoCggEBAM0vsCM3XxZVHmxOdY2ndCoUHnrlLameRZcEupa77oAXBw9J2ysTIY1v\n"
-       "uP7GbBru4JnBhdem1xL37z0/a5O9+5Rw4SNHNw8Z2jPtWSJd+XwfBshQnX66IvSv\n"
-       "M0etutgO/lZwFq7E4yGI7LS1sGWvVhmjMLT1Yb3j/b8SXeSHyp9J0NdJ1spjjekg\n"
-       "bdiMUOo6Tt1gnZsgLdH6Cbmw4sm/+EGjsPOYdBI0kHW5qqLnIzW/io0NMnRsDBEk\n"
-       "HgXNEMhXZL/qEQfrcSCxjlqB126aALHIvN5TKBrssfE6zn9m96A9qCRJuKGP9NPm\n"
-       "4AFkV1yylCUTUkIRkbqPlI4i1vf8jfcCAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n"
-       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBQPB7C8f3nco30et23Lhw7QMTaL\n"
-       "YzAfBgNVHSMEGDAWgBRjNOT1/2J+aAVCl/aO+EQke/8oETA9BgkqhkiG9w0BAQow\n"
-       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n"
-       "QAOCAQEAsKDivFD4DflylFdG4zijGrtq/zfSKTiNWxZsLKbMwLoG+Km3dy0HWfUq\n"
-       "TUETPEfQlpXc2Tg1tGxFepAPavVeMIy/MV3SsmjRA3f+PNWjaZUxa9+Jd1y6ONwK\n"
-       "wQ7s/JNNk/SZt4bKjX9GrTscZmOVtrwpZ6uQBHITScsr4V431G6wojZ09iEG0yFQ\n"
-       "ZD8ECn2ZOPVQXIswa75NelcGKup838HoDIjQ3vIvrx8rqf5HRg4t9mXzjECzXHVy\n"
-       "8wDamoE3fLAZZX2RxOWnHfjI8qB83qYyR5kN002EFJ/e060SPia1rTHyLqLngRtq\n"
-       "xgR9bRjZf++h/dg6L87b26J5KdDafw==\n"
-       "-----END CERTIFICATE-----\n",
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIDojCCAlqgAwIBAgIUVd3TT33d1fy/8INiIKhudYmRE5swPQYJKoZIhvcNAQEK\n"
-       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n"
-       "AUAwDzENMAsGA1UEAxMEQ0EtMTAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n"
-       "NTk1OVowDzENMAsGA1UEAxMEQ0EtMjCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n"
-       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n"
-       "AQoCggEBANN3n02MYdl70xAq39SUtcMcNR9Zpe6m4SkHcL/1T4YEpWxqqez1tDW3\n"
-       "1My9Std/sE1e63Q+XJdZhKz1v2KM48iMMeEtJRtriSMxp3KyHQwOxV5L/C5yudYG\n"
-       "3DW0XwrIFL5uXn0z27vYTJ+63RFD4K6Np3ROa2EnHuTcb1pAlrGK1erUzuD8gg7m\n"
-       "mIwxfS7KSeUSmZiXVACNVGmAekClRIf1kMjMqNL6eQ2laNcg7W7RCaIghk58E4Ej\n"
-       "/dyNWTgUUoHla8X4Za/JNXDVHdj5VKIfK8xQkc6aN8Ip5rm9J94yLay27QZdHPQn\n"
-       "AlHEW6IAyRgj/lo+yk1RUigjko62t+0CAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n"
-       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBTVuTCwy3TqMVX2Bvdj/wcoYSTG\n"
-       "/zAfBgNVHSMEGDAWgBS/OulsZ80Bb9MpqM/M1lCC8bO2AzA9BgkqhkiG9w0BAQow\n"
-       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n"
-       "QAOCAQEAfi/KKbJUsdvS/XDqR6T8VHNhX8lMOGdzHltjBdXdxsWlr2mRolILhyZf\n"
-       "1/wf58b1OE4AlxbwH+S/vWrQ2KVwBfWxtTJXqAMSvHIF3Tq8bIghvhK8CmZG/I49\n"
-       "FTYE+42MFBr6f5SNp9Q+ZUcjSK5DO7yNiyKDFfNffFGxHmnmGj2LhgyrvYA/aNyB\n"
-       "2ichlfihcKkExGBN44ODoK+8/W8oiMt541AvPyJxTJjxWjeJ42EBXO+J5k8wRuCu\n"
-       "nXCW5OjnEIExXGKZLlieH4t8kUyHlrTlHO7spiqA/QM7GUtBQfJTLdPFmvHU3Jtw\n"
-       "qGN2PrhXyLoaUfIpNbWO9Jmj2GYaWg==\n"
-       "-----END CERTIFICATE-----\n",
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIICxjCCAiegAwIBAgIUKnsCQlR0jpxEnpzqxbi+Y2rqwpMwCgYIKoZIzj0EAwQw\n"
-       "DzENMAsGA1UEAxMEQ0EtMDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIzNTk1\n"
-       "OVowDzENMAsGA1UEAxMEQ0EtMTCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglghkgB\n"
-       "ZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCCAQoC\n"
-       "ggEBAOqrWIctrZ7mabfoFuMsT/B2kK4vWAGX32SGQdoDKdy+O0jGJN8/vGnbaOWN\n"
-       "k6sR/eNx+13LahbiLl3dzyecdJ6BeDBokjiRXtDzZN3IdrR6KZ5NjqcMiVBgztoq\n"
-       "gkOglhcixU2cMlSFYCozfvf3i4YElJzSP4XdJbLaPcsHmywny52s06vf64SbNhQy\n"
-       "GucRYO0VqRUVCNpvPyyGlkODlDQuzNsd5nIQZ5WR1bQLTYsVoHVfpLx+Su7BAV05\n"
-       "D5XiGQVGw7kkp4VKHrMhQ0VY+34xmahQvnoqfPEBG9jjfy6psI0oa52JS3FBWF8u\n"
-       "psUiFD2iqQy+efQX44gAdrrnkt0CAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB/zAP\n"
-       "BgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBS/OulsZ80Bb9MpqM/M1lCC8bO2AzAf\n"
-       "BgNVHSMEGDAWgBRBWngghShY2X+P7m45LPH1V4p5czAKBggqhkjOPQQDBAOBjAAw\n"
-       "gYgCQgHnvF1Dq32xBBEME4UlVsVeOflvGw5Sr/hVhbUZ1KfAQIV2ZuBuvJNMBrj8\n"
-       "Pzi/nhRuV8vH5xabyQb9RYVcJ8oilQJCAdduIVVvL6DmUBOJfz1znsxPA5JCBBY2\n"
-       "pAOhFZBrNXE2zZrgttgR6TG4Obst1fQzL3RsmqAYAuWSpKPNz6Hdq+kl\n"
-       "-----END CERTIFICATE-----\n",
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIB7TCCAU6gAwIBAgIUWmldb3tGP48wFh5P/cmVytYv5JcwCgYIKoZIzj0EAwQw\n"
-       "DzENMAsGA1UEAxMEQ0EtMDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIzNTk1\n"
-       "OVowDzENMAsGA1UEAxMEQ0EtMDCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAarU\n"
-       "aZXDJBYLdRdjV43Nq+slYxPPn877UBJ63K6GQF1poMaSFFJ7qSXi4lJngh7ueCVq\n"
-       "mJvNH54KbqkPryfCKjUbAZnIQa/8zpPbrZ4iAP6d+Mb6qIkX8j3BP1f6Ap0WTmQk\n"
-       "s5QHCkJFGNqqljut/RQgnbTUbQcGHCNmUx4g0BZv03+Qo0MwQTAPBgNVHRMBAf8E\n"
-       "BTADAQH/MA8GA1UdDwEB/wQFAwMHBgAwHQYDVR0OBBYEFEFaeCCFKFjZf4/ubjks\n"
-       "8fVXinlzMAoGCCqGSM49BAMEA4GMADCBiAJCAcmtP2IVnOTF2wHhfUn13qsUpqyc\n"
-       "3kCI1ueg75NgR7xgpL9JQ1CnPaUbCp+5ROKf5IHn8f1jjZIu45WpiWhnZDkkAkIA\n"
-       "pCTZn7t7memhMJUqrHGywx2gR9fgID/REZUZdVe9KcTzWvwSrbffDMCcf10SpM6C\n"
-       "/YXiDLiWNiK+WV8Z557eWKI=\n"
+#define SERVER_CERT "-----BEGIN CERTIFICATE-----\n"                    \
+       "MIIDATCCAbmgAwIBAgIUQdvdegP8JFszFHLfV4+lrEdafzAwPQYJKoZIhvcNAQEK\n" \
+       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n" \
+       "AUAwDzENMAsGA1UEAxMEQ0EtNTAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n" \
+       "NTk1OVowEzERMA8GA1UEAxMIc2VydmVyLTYwgZswEAYHKoZIzj0CAQYFK4EEACMD\n" \
+       "gYYABAHZ3W5jpYq15WI7tVZxWCT3YtYMEj4xJSdO/ubHV0NnrlQ7+Q95R32qcA2w\n" \
+       "4gyPif+M/Au4Towr/RA+b+qgMvD0fQFmNeWkNB/TSW2RNm7uHQU7N66tbrNWvjyS\n" \
+       "BZeLB/V03ZWe+rO4cfrPiqtBv9N08k9uMNNCeMlatJNqj0BoFRxhBaN3MHUwDAYD\n" \
+       "VR0TAQH/BAIwADAUBgNVHREEDTALgglsb2NhbGhvc3QwDwYDVR0PAQH/BAUDAweA\n" \
+       "ADAdBgNVHQ4EFgQUMnSJQI2iHiVoxE1XSByQ9QFrG0owHwYDVR0jBBgwFoAUu9ao\n" \
+       "G/58Y/+czHPyWo3C+vs9pFkwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgGh\n" \
+       "GjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEBAAfhLT1jQsc9yk4k\n" \
+       "myAAMIXYD1THMkasGZiIv2TLJSLeKc4Rvzvrb/iywwrMdaBHs5sJoyk7amMwemc7\n" \
+       "WA2+A2uTeLeDG3ev4r5stNRLyL0HSOr7da+BshUiHJgeihp1Qglm0AUqV5X69i5t\n" \
+       "5woB5KENnYfoAWaYmXa1EPRh2xb2XDI0uCHg1bPljg61/T2cJZ4VfkOvsKgFAI4p\n" \
+       "lAKQCZSKbEY1oWDdDhVcSipYu2E88RXczvcnEQV3C3p6CGcf8xclZdZIwMAyXYAK\n" \
+       "oNccbSIfDlN4iD+2bztCRWHD6hWL1NJsFqmv3Ts8eYU8z8J8NdhtCXr76lFkFmDx\n" \
+       "+lfZEv4=\n"                                                    \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_5 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIDojCCAlqgAwIBAgIUHRb3xJ2ZGqqgdC/pBq/sDtAwvtowPQYJKoZIhvcNAQEK\n" \
+       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n" \
+       "AUAwDzENMAsGA1UEAxMEQ0EtNDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n" \
+       "NTk1OVowDzENMAsGA1UEAxMEQ0EtNTCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n" \
+       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n" \
+       "AQoCggEBAMZqQ7I1HAxkxuwGQBch/jZTWLXRUtWBjlpREnp0wFt+quJOZkKNYrlL\n" \
+       "9sngiRknsbEIfJMB2XfoK6m9SwRN/qoxewOrnK9YONG9dj0p30qiseshXIs6ZoMl\n" \
+       "v9fZA77UraCtTbX6Xwk/+Or6SuSK2lyz0R5O14xBa5ubpm2Q8XTE9A1SAGx61ofC\n" \
+       "Dzfvefp+m3QCy+3K+Yn05VKPxswznuVwM/oJDGzJJhD6/uNPpm5CZoPtcW14Eitu\n" \
+       "ip51Ej1VE4lJRBHAtUSOrd3Hks6YasK7Uvu0HjpqW7PqaIhJIR7ofzbXX2vBwVj2\n" \
+       "Qlwozk4cVCP7XO3VrVu/GCdSL+G3RAUCAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n" \
+       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBS71qgb/nxj/5zMc/JajcL6+z2k\n" \
+       "WTAfBgNVHSMEGDAWgBQPB7C8f3nco30et23Lhw7QMTaLYzA9BgkqhkiG9w0BAQow\n" \
+       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n" \
+       "QAOCAQEAl90uQvD0lne4jseHNfu8XCIZmCSxaNhF3SD73TwlGERbRjtIKz34Y6hC\n" \
+       "z5bZ4tCGnkKAtdHLIGwOnaLSXDvzmUSkQmJmG0QMaDGsVpVXEZD/7+yyIxOcV1iK\n" \
+       "XveeQysCKsDEfdrfn1mACQj8eC4lL9KJcHptHdTSLfa58MV2Qe5smCIByXxendO5\n" \
+       "UQHZy5UrzWAdtO7y75vXeXynsXAqcE4TTNjdFiCnn6Q5/pVyW14kepfjaOzQFP7H\n" \
+       "QlnHtgQDRAlQuB1aGseb6jn2Joy33itpBthvtgBosZIqsMyPoX5YzjqZUSjfPZOP\n" \
+       "/aOd/5HR4ZPDWfHdIWbXogYX0ndhNg==\n"                            \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_4 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIDojCCAlqgAwIBAgIUGybZZ1e/iFUKafPdh8xUbh7YVnwwPQYJKoZIhvcNAQEK\n" \
+       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n" \
+       "AUAwDzENMAsGA1UEAxMEQ0EtMzAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n" \
+       "NTk1OVowDzENMAsGA1UEAxMEQ0EtNDCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n" \
+       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n" \
+       "AQoCggEBAM0vsCM3XxZVHmxOdY2ndCoUHnrlLameRZcEupa77oAXBw9J2ysTIY1v\n" \
+       "uP7GbBru4JnBhdem1xL37z0/a5O9+5Rw4SNHNw8Z2jPtWSJd+XwfBshQnX66IvSv\n" \
+       "M0etutgO/lZwFq7E4yGI7LS1sGWvVhmjMLT1Yb3j/b8SXeSHyp9J0NdJ1spjjekg\n" \
+       "bdiMUOo6Tt1gnZsgLdH6Cbmw4sm/+EGjsPOYdBI0kHW5qqLnIzW/io0NMnRsDBEk\n" \
+       "HgXNEMhXZL/qEQfrcSCxjlqB126aALHIvN5TKBrssfE6zn9m96A9qCRJuKGP9NPm\n" \
+       "4AFkV1yylCUTUkIRkbqPlI4i1vf8jfcCAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n" \
+       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBQPB7C8f3nco30et23Lhw7QMTaL\n" \
+       "YzAfBgNVHSMEGDAWgBRjNOT1/2J+aAVCl/aO+EQke/8oETA9BgkqhkiG9w0BAQow\n" \
+       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n" \
+       "QAOCAQEAsKDivFD4DflylFdG4zijGrtq/zfSKTiNWxZsLKbMwLoG+Km3dy0HWfUq\n" \
+       "TUETPEfQlpXc2Tg1tGxFepAPavVeMIy/MV3SsmjRA3f+PNWjaZUxa9+Jd1y6ONwK\n" \
+       "wQ7s/JNNk/SZt4bKjX9GrTscZmOVtrwpZ6uQBHITScsr4V431G6wojZ09iEG0yFQ\n" \
+       "ZD8ECn2ZOPVQXIswa75NelcGKup838HoDIjQ3vIvrx8rqf5HRg4t9mXzjECzXHVy\n" \
+       "8wDamoE3fLAZZX2RxOWnHfjI8qB83qYyR5kN002EFJ/e060SPia1rTHyLqLngRtq\n" \
+       "xgR9bRjZf++h/dg6L87b26J5KdDafw==\n"                            \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_3 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIDojCCAlqgAwIBAgIUHRkWa8ZOaRrqjxigoEhxJHMLM2UwPQYJKoZIhvcNAQEK\n" \
+       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n" \
+       "AUAwDzENMAsGA1UEAxMEQ0EtMjAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n" \
+       "NTk1OVowDzENMAsGA1UEAxMEQ0EtMzCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n" \
+       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n" \
+       "AQoCggEBAMNSjDqpdcx+02E2vKRB78Z6rYRTuYHeXZGIsVz3LXHxplNYtSlM0MN4\n" \
+       "cj0mHj2Rctxk7o6vsQm37ayvO4mquvgPiwtivq+qPv98ZTIuVYkPE4NEPru7Uec+\n" \
+       "HQO3faRym4VAzpH+CllMraeaSjQLfAKqXw60UHF+b+ovJXKWbb+keahXT6lWxuxY\n" \
+       "pm5vbcDg0Ez++9TJcA0MiPKtk4SMgnmr+2vXAE0tE5PRX9NS7AWPyEg82q+ph2kj\n" \
+       "zu5VWoqZp/EwMI6VfLJeemY726LyyOpIqBGWwsUXPn5NdxLla58zHDFggd7/Z/l9\n" \
+       "aBfozSdrqW3sWeYzgGxeZmnc5Vm/r6ECAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n" \
+       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBRjNOT1/2J+aAVCl/aO+EQke/8o\n" \
+       "ETAfBgNVHSMEGDAWgBTVuTCwy3TqMVX2Bvdj/wcoYSTG/zA9BgkqhkiG9w0BAQow\n" \
+       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n" \
+       "QAOCAQEAbIw3qtl/QAMJ7OmBPqSMtZv9TaLxfUh7FrqfsKjXBQGVX6/7heO+wCwJ\n" \
+       "/1vi2yFUc7uoB3ivEKzUQvtP7Nu6WMM64pAfYadGIk4TYV+tgXF4FJ8FHjTek+Lv\n" \
+       "jTu7jvLbRSHkBQFimWorPfgf15nlXSCBtejEwvDLXlptLbKEa3q7VFXDzCyeiKGb\n" \
+       "IHRozrAP5qiyIjYFJevXrZ/7bWDwMcJrB0uSQN9TD2mJjNXTCHu3GYnEmnu7KRpb\n" \
+       "M3OdswIyjIFYvwlYGe2+GbigSaMZY9KCHR7vkJ1JGdxfh+CADcbL4fwj3kOpyEoe\n" \
+       "TTqtWQ93AfQnd2Vm3/SAr/+jSuMbSA==\n"                            \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_2 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIDojCCAlqgAwIBAgIUVd3TT33d1fy/8INiIKhudYmRE5swPQYJKoZIhvcNAQEK\n" \
+       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n" \
+       "AUAwDzENMAsGA1UEAxMEQ0EtMTAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n" \
+       "NTk1OVowDzENMAsGA1UEAxMEQ0EtMjCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n" \
+       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n" \
+       "AQoCggEBANN3n02MYdl70xAq39SUtcMcNR9Zpe6m4SkHcL/1T4YEpWxqqez1tDW3\n" \
+       "1My9Std/sE1e63Q+XJdZhKz1v2KM48iMMeEtJRtriSMxp3KyHQwOxV5L/C5yudYG\n" \
+       "3DW0XwrIFL5uXn0z27vYTJ+63RFD4K6Np3ROa2EnHuTcb1pAlrGK1erUzuD8gg7m\n" \
+       "mIwxfS7KSeUSmZiXVACNVGmAekClRIf1kMjMqNL6eQ2laNcg7W7RCaIghk58E4Ej\n" \
+       "/dyNWTgUUoHla8X4Za/JNXDVHdj5VKIfK8xQkc6aN8Ip5rm9J94yLay27QZdHPQn\n" \
+       "AlHEW6IAyRgj/lo+yk1RUigjko62t+0CAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n" \
+       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBTVuTCwy3TqMVX2Bvdj/wcoYSTG\n" \
+       "/zAfBgNVHSMEGDAWgBS/OulsZ80Bb9MpqM/M1lCC8bO2AzA9BgkqhkiG9w0BAQow\n" \
+       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n" \
+       "QAOCAQEAfi/KKbJUsdvS/XDqR6T8VHNhX8lMOGdzHltjBdXdxsWlr2mRolILhyZf\n" \
+       "1/wf58b1OE4AlxbwH+S/vWrQ2KVwBfWxtTJXqAMSvHIF3Tq8bIghvhK8CmZG/I49\n" \
+       "FTYE+42MFBr6f5SNp9Q+ZUcjSK5DO7yNiyKDFfNffFGxHmnmGj2LhgyrvYA/aNyB\n" \
+       "2ichlfihcKkExGBN44ODoK+8/W8oiMt541AvPyJxTJjxWjeJ42EBXO+J5k8wRuCu\n" \
+       "nXCW5OjnEIExXGKZLlieH4t8kUyHlrTlHO7spiqA/QM7GUtBQfJTLdPFmvHU3Jtw\n" \
+       "qGN2PrhXyLoaUfIpNbWO9Jmj2GYaWg==\n"                            \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_1 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIICxjCCAiegAwIBAgIUKnsCQlR0jpxEnpzqxbi+Y2rqwpMwCgYIKoZIzj0EAwQw\n" \
+       "DzENMAsGA1UEAxMEQ0EtMDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIzNTk1\n" \
+       "OVowDzENMAsGA1UEAxMEQ0EtMTCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglghkgB\n" \
+       "ZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCCAQoC\n" \
+       "ggEBAOqrWIctrZ7mabfoFuMsT/B2kK4vWAGX32SGQdoDKdy+O0jGJN8/vGnbaOWN\n" \
+       "k6sR/eNx+13LahbiLl3dzyecdJ6BeDBokjiRXtDzZN3IdrR6KZ5NjqcMiVBgztoq\n" \
+       "gkOglhcixU2cMlSFYCozfvf3i4YElJzSP4XdJbLaPcsHmywny52s06vf64SbNhQy\n" \
+       "GucRYO0VqRUVCNpvPyyGlkODlDQuzNsd5nIQZ5WR1bQLTYsVoHVfpLx+Su7BAV05\n" \
+       "D5XiGQVGw7kkp4VKHrMhQ0VY+34xmahQvnoqfPEBG9jjfy6psI0oa52JS3FBWF8u\n" \
+       "psUiFD2iqQy+efQX44gAdrrnkt0CAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB/zAP\n" \
+       "BgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBS/OulsZ80Bb9MpqM/M1lCC8bO2AzAf\n" \
+       "BgNVHSMEGDAWgBRBWngghShY2X+P7m45LPH1V4p5czAKBggqhkjOPQQDBAOBjAAw\n" \
+       "gYgCQgHnvF1Dq32xBBEME4UlVsVeOflvGw5Sr/hVhbUZ1KfAQIV2ZuBuvJNMBrj8\n" \
+       "Pzi/nhRuV8vH5xabyQb9RYVcJ8oilQJCAdduIVVvL6DmUBOJfz1znsxPA5JCBBY2\n" \
+       "pAOhFZBrNXE2zZrgttgR6TG4Obst1fQzL3RsmqAYAuWSpKPNz6Hdq+kl\n"    \
+       "-----END CERTIFICATE-----\n"
+
+#define CA_CERT_0 "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIB7TCCAU6gAwIBAgIUWmldb3tGP48wFh5P/cmVytYv5JcwCgYIKoZIzj0EAwQw\n" \
+       "DzENMAsGA1UEAxMEQ0EtMDAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIzNTk1\n" \
+       "OVowDzENMAsGA1UEAxMEQ0EtMDCBmzAQBgcqhkjOPQIBBgUrgQQAIwOBhgAEAarU\n" \
+       "aZXDJBYLdRdjV43Nq+slYxPPn877UBJ63K6GQF1poMaSFFJ7qSXi4lJngh7ueCVq\n" \
+       "mJvNH54KbqkPryfCKjUbAZnIQa/8zpPbrZ4iAP6d+Mb6qIkX8j3BP1f6Ap0WTmQk\n" \
+       "s5QHCkJFGNqqljut/RQgnbTUbQcGHCNmUx4g0BZv03+Qo0MwQTAPBgNVHRMBAf8E\n" \
+       "BTADAQH/MA8GA1UdDwEB/wQFAwMHBgAwHQYDVR0OBBYEFEFaeCCFKFjZf4/ubjks\n" \
+       "8fVXinlzMAoGCCqGSM49BAMEA4GMADCBiAJCAcmtP2IVnOTF2wHhfUn13qsUpqyc\n" \
+       "3kCI1ueg75NgR7xgpL9JQ1CnPaUbCp+5ROKf5IHn8f1jjZIu45WpiWhnZDkkAkIA\n" \
+       "pCTZn7t7memhMJUqrHGywx2gR9fgID/REZUZdVe9KcTzWvwSrbffDMCcf10SpM6C\n" \
+       "/YXiDLiWNiK+WV8Z557eWKI=\n"                                    \
        "-----END CERTIFICATE-----\n"
-};
 
-static const char *missing_cert_insert = {
-       "-----BEGIN CERTIFICATE-----\n"
-       "MIIDojCCAlqgAwIBAgIUHRkWa8ZOaRrqjxigoEhxJHMLM2UwPQYJKoZIhvcNAQEK\n"
-       "MDCgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMC\n"
-       "AUAwDzENMAsGA1UEAxMEQ0EtMjAgFw0yMDA0MjAxMTI2NDFaGA85OTk5MTIzMTIz\n"
-       "NTk1OVowDzENMAsGA1UEAxMEQ0EtMzCCAVIwPQYJKoZIhvcNAQEKMDCgDTALBglg\n"
-       "hkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogMCAUADggEPADCC\n"
-       "AQoCggEBAMNSjDqpdcx+02E2vKRB78Z6rYRTuYHeXZGIsVz3LXHxplNYtSlM0MN4\n"
-       "cj0mHj2Rctxk7o6vsQm37ayvO4mquvgPiwtivq+qPv98ZTIuVYkPE4NEPru7Uec+\n"
-       "HQO3faRym4VAzpH+CllMraeaSjQLfAKqXw60UHF+b+ovJXKWbb+keahXT6lWxuxY\n"
-       "pm5vbcDg0Ez++9TJcA0MiPKtk4SMgnmr+2vXAE0tE5PRX9NS7AWPyEg82q+ph2kj\n"
-       "zu5VWoqZp/EwMI6VfLJeemY726LyyOpIqBGWwsUXPn5NdxLla58zHDFggd7/Z/l9\n"
-       "aBfozSdrqW3sWeYzgGxeZmnc5Vm/r6ECAwEAAaNkMGIwDwYDVR0TAQH/BAUwAwEB\n"
-       "/zAPBgNVHQ8BAf8EBQMDB4QAMB0GA1UdDgQWBBRjNOT1/2J+aAVCl/aO+EQke/8o\n"
-       "ETAfBgNVHSMEGDAWgBTVuTCwy3TqMVX2Bvdj/wcoYSTG/zA9BgkqhkiG9w0BAQow\n"
-       "MKANMAsGCWCGSAFlAwQCAaEaMBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIB\n"
-       "QAOCAQEAbIw3qtl/QAMJ7OmBPqSMtZv9TaLxfUh7FrqfsKjXBQGVX6/7heO+wCwJ\n"
-       "/1vi2yFUc7uoB3ivEKzUQvtP7Nu6WMM64pAfYadGIk4TYV+tgXF4FJ8FHjTek+Lv\n"
-       "jTu7jvLbRSHkBQFimWorPfgf15nlXSCBtejEwvDLXlptLbKEa3q7VFXDzCyeiKGb\n"
-       "IHRozrAP5qiyIjYFJevXrZ/7bWDwMcJrB0uSQN9TD2mJjNXTCHu3GYnEmnu7KRpb\n"
-       "M3OdswIyjIFYvwlYGe2+GbigSaMZY9KCHR7vkJ1JGdxfh+CADcbL4fwj3kOpyEoe\n"
-       "TTqtWQ93AfQnd2Vm3/SAr/+jSuMbSA==\n"
+#define UNRELATED "-----BEGIN CERTIFICATE-----\n"                      \
+       "MIIEaDCCAqCgAwIBAgIMWXi5rBKSNwkPo4olMD0GCSqGSIb3DQEBCjAwoA0wCwYJ\n" \
+       "YIZIAWUDBAIDoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCA6IDAgFAMA8xDTAL\n" \
+       "BgNVBAMTBENBLTAwIBcNMTcwNzI2MTU0NzU2WhgPOTk5OTEyMzEyMzU5NTlaMA8x\n" \
+       "DTALBgNVBAMTBENBLTEwggGgMAsGCSqGSIb3DQEBCgOCAY8AMIIBigKCAYEA8Afg\n" \
+       "aY9tKN/1UwFdqmDTbxcxiGDQFTDKDFt4zLEy8HoqsiTLEycydVJeAEuw1WNrph1x\n" \
+       "nphDETOsiG429CEkIj4rpNaPSevQmfkUP+NFqKgf3egUInmXzSMnKuc3eiDXzSC9\n" \
+       "mcYzcs3O6kDruoTBcmujSQxdcPYdj08BkM2uD1PlHVeE1h66axt82I74q8ntT1Zx\n" \
+       "IM4TaLSao/Xdn1i5AYHwJj3DzjKlYDuLqkAiyQDI/NrRS007MYRLN4Ebu6bvkuzN\n" \
+       "6m7eXYPugV+lSkGSLTi0cbG0wkUqcR1X5JzBqHyXU0epoz3/PpVBwMUNHMun3s7z\n" \
+       "TQt5OJY97BeY6l/Wj259iBYj41UvEghT67smaM8zvwFb51+fCPLKPUXG4A2Ksx0k\n" \
+       "H+HIP2TIIQbuM4KAS3VmyFNoxzOXs89BdxJCQ+D83RZHSYn4t+76fiSzV+I4baGi\n" \
+       "DbPVU7cM5CrOcfTohP83jpOgM/LbPyptGu6S6GKMx93HVLP6LtnZE736dO5XAgMB\n" \
+       "AAGjZDBiMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcEADAdBgNVHQ4E\n" \
+       "FgQUNYOAzOqpk/LibJBsXlFFEiD3t4kwHwYDVR0jBBgwFoAULmo+wdwsHxfVzvUw\n" \
+       "NyVK9++NokUwPQYJKoZIhvcNAQEKMDCgDTALBglghkgBZQMEAgOhGjAYBgkqhkiG\n" \
+       "9w0BAQgwCwYJYIZIAWUDBAIDogMCAUADggGBAIXyJ4S/dWmkPV3kBUENfIXaLV57\n" \
+       "mGJjnR/EnUX4gVVxDfKDTNGq2Y1ksCeY1JmvjSHZVkX/D4p3BCHF8bHpLvS7Edts\n" \
+       "4NpoL3A4MBdupwDFtF/0Fo4VdZM4ztLL4gBCq2pnukCkbyELCPpe3d/yVujsJNrQ\n" \
+       "4faiJMwCjep+3q0ZiytlsN8M3bdGy8ocbzPAi2rMTvQ8I+2e5kLTJmatJ4Qbut25\n" \
+       "d1rfJ4ruMt2QOrSlYSENKkA3zjRAg4a2xvVPyOVZBEj48366b1uuji/sOQRckZ/w\n" \
+       "3eoeffRfWQXO2y0/K9TUqZM+6n10N32ZkR45I+XSQ13qS73l4QS4djay9z/bAMeb\n" \
+       "/zgaf6J790LULzDBEvhPZLNn4bBu/t7WVj2NI+frQvAHyQ9ZhBYkow84qF+//zK9\n" \
+       "d/VzQbBQOJFX9TWdWgUxklrWnXE0gmxzGBdq+cMQyHulVVbgShftCRJ8jn8e0Cl1\n" \
+       "dl+Cpj08yyLpT9/ZmL8ytgD3Iobw0wPHppb/jQ==\n"                    \
        "-----END CERTIFICATE-----\n"
+
+static const char *missing_middle_single[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_4,
+       CA_CERT_2,
+       CA_CERT_1,
+       NULL,
+};
+
+static const char *missing_middle_single_insert[] = {
+       CA_CERT_3,
+       NULL,
+};
+
+static const char *missing_middle_multiple[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_4,
+       CA_CERT_1,
+       NULL,
+};
+
+static const char *missing_middle_multiple_insert[] = {
+       CA_CERT_3 CA_CERT_2,
+       NULL,
 };
 
-#if defined __clang__ || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)
-#  pragma GCC diagnostic pop
-#endif
+static const char *missing_last_single[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_4,
+       CA_CERT_3,
+       CA_CERT_2,
+       NULL,
+};
+
+static const char *missing_last_single_insert[] = {
+       CA_CERT_1,
+       NULL,
+};
+
+static const char *missing_last_multiple[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_4,
+       CA_CERT_3,
+       NULL,
+};
+
+static const char *missing_last_multiple_insert[] = {
+       CA_CERT_2 CA_CERT_1,
+       NULL,
+};
 
-/* *INDENT-ON* */
+static const char *missing_skip_single[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_3,
+       CA_CERT_1,
+       NULL,
+};
+
+static const char *missing_skip_single_insert[] = {
+       CA_CERT_4,
+       CA_CERT_2,
+       NULL,
+};
+
+static const char *missing_skip_multiple[] = {
+       SERVER_CERT,
+       CA_CERT_5,
+       CA_CERT_3,
+       NULL,
+};
+
+static const char *missing_skip_multiple_insert[] = {
+       CA_CERT_4,
+       CA_CERT_2 CA_CERT_1,
+       NULL,
+};
+
+static const char *missing_middle_single_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_1,
+       CA_CERT_2,
+       CA_CERT_4,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_middle_multiple_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_1,
+       CA_CERT_4,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_last_single_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_2,
+       CA_CERT_3,
+       CA_CERT_4,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_last_multiple_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_3,
+       CA_CERT_4,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_skip_single_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_1,
+       CA_CERT_3,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_skip_multiple_unsorted[] = {
+       SERVER_CERT,
+       CA_CERT_3,
+       CA_CERT_5,
+       NULL,
+};
+
+static const char *missing_middle_unrelated_insert[] = {
+       UNRELATED,
+       NULL,
+};
+
+static const char *missing_middle_unrelated_extra_insert[] = {
+       /* valid CA certificate followed by an unrelated CA: should be accepted */
+       CA_CERT_3 UNRELATED,
+       NULL,
+};
+
+static const char *missing_ca[] = {
+       CA_CERT_0,
+       NULL,
+};
+
+static struct chains {
+       const char *name;
+       const char **chain;
+       const char **insert;
+       const char **ca;
+       unsigned int verify_flags;
+       unsigned int expected_verify_result;
+} chains[] = {
+       { "middle single - no sort", missing_middle_single, missing_middle_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "middle multiple - no sort", missing_middle_multiple, missing_middle_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "last single - no sort", missing_last_single, missing_last_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "last multiple - no sort", missing_last_multiple, missing_last_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "skip single - no sort", missing_skip_single, missing_skip_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "skip multiple - no sort", missing_skip_multiple, missing_skip_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, 0 },
+       { "middle single unsorted - no sort", missing_middle_single_unsorted, missing_middle_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "middle multiple unsorted - no sort", missing_middle_multiple_unsorted, missing_middle_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "last single unsorted - no sort", missing_last_single_unsorted, missing_last_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "last multiple unsorted - no sort", missing_last_multiple_unsorted, missing_last_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "skip single unsorted - no sort", missing_skip_single_unsorted, missing_skip_single_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "skip multiple unsorted - no sort", missing_skip_multiple_unsorted, missing_skip_multiple_insert, missing_ca, GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "middle single", missing_middle_single, missing_middle_single_insert, missing_ca, 0, 0 },
+       { "middle multiple", missing_middle_multiple, missing_middle_multiple_insert, missing_ca, 0, 0 },
+       { "last single", missing_last_single, missing_last_single_insert, missing_ca, 0, 0 },
+       { "last multiple", missing_last_multiple, missing_last_multiple_insert, missing_ca, 0, 0 },
+       { "skip single", missing_skip_single, missing_skip_single_insert, missing_ca, 0, 0 },
+       { "skip multiple", missing_skip_multiple, missing_skip_multiple_insert, missing_ca, 0, 0 },
+       { "middle single unsorted", missing_middle_single_unsorted, missing_middle_single_insert, missing_ca, 0, 0 },
+       { "middle multiple unsorted", missing_middle_multiple_unsorted, missing_middle_multiple_insert, missing_ca, 0, 0 },
+       { "last single unsorted", missing_last_single_unsorted, missing_last_single_insert, missing_ca, 0, 0 },
+       { "last multiple unsorted", missing_last_multiple_unsorted, missing_last_multiple_insert, missing_ca, 0, 0 },
+       { "skip single unsorted", missing_skip_single_unsorted, missing_skip_single_insert, missing_ca, 0, 0 },
+       { "skip multiple unsorted", missing_skip_multiple_unsorted, missing_skip_multiple_insert, missing_ca, 0, 0 },
+       { "unrelated", missing_middle_single, missing_middle_unrelated_insert, missing_ca, 0, GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND },
+       { "unrelated extra", missing_middle_single, missing_middle_unrelated_extra_insert, missing_ca, 0, 0 },
+       { NULL, NULL, NULL, NULL },
+};
 
 #endif /* GNUTLS_TESTS_TEST_CHAINS_ISSUER_H */