#include "intprops.h"
#include "minmax.h"
+#include <assert.h>
#include <string.h>
#define MAX_NC_CHECKS (1 << 20)
return ret;
}
-static int name_constraints_node_list_concat(
- gnutls_x509_name_constraints_t nc,
- struct name_constraints_node_list_st *nodes,
- const struct name_constraints_node_list_st *nodes2)
+static int
+name_constraints_node_list_union(gnutls_x509_name_constraints_t nc,
+ struct name_constraints_node_list_st *nodes,
+ struct name_constraints_node_list_st *nodes2)
{
int ret;
+ size_t i = 0, j = 0;
+ struct name_constraints_node_st *nc1;
+ const struct name_constraints_node_st *nc2;
+ enum name_constraint_relation rel;
+ struct name_constraints_node_list_st result = { 0 };
+
+ if (nodes2->size == 0) /* nothing to do */
+ return GNUTLS_E_SUCCESS;
+
+ ret = ensure_sorted(nodes);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ ret = ensure_sorted(nodes2);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* traverse both lists in a single pass and merge them w/o duplicates */
+ while (i < nodes->size || j < nodes2->size) {
+ nc1 = (i < nodes->size) ? nodes->sorted_view[i] : NULL;
+ nc2 = (j < nodes2->size) ? nodes2->sorted_view[j] : NULL;
- for (size_t i = 0; i < nodes2->size; i++) {
- ret = name_constraints_node_add_copy(nc, nodes,
- nodes2->data[i]);
+ rel = compare_name_constraint_nodes(nc1, nc2);
+ switch (rel) {
+ case NC_SORTS_BEFORE:
+ assert(nc1 != NULL); /* comparator-guaranteed */
+ ret = name_constraints_node_list_add(&result, nc1);
+ i++;
+ break;
+ case NC_SORTS_AFTER:
+ assert(nc2 != NULL); /* comparator-guaranteed */
+ ret = name_constraints_node_add_copy(nc, &result, nc2);
+ j++;
+ break;
+ case NC_INCLUDES: /* nc1 is broader, shallow-copy it */
+ assert(nc1 != NULL && nc2 != NULL); /* comparator */
+ ret = name_constraints_node_list_add(&result, nc1);
+ i++;
+ j++;
+ break;
+ case NC_INCLUDED_BY: /* nc2 is broader, deep-copy it */
+ assert(nc1 != NULL && nc2 != NULL); /* comparator */
+ ret = name_constraints_node_add_copy(nc, &result, nc2);
+ i++;
+ j++;
+ break;
+ case NC_EQUAL:
+ assert(nc1 != NULL && nc2 != NULL); /* loop condition */
+ ret = name_constraints_node_list_add(&result, nc1);
+ i++;
+ j++;
+ break;
+ }
if (ret < 0) {
- return gnutls_assert_val(ret);
+ gnutls_assert();
+ goto cleanup;
}
}
- return 0;
+ gnutls_free(nodes->data);
+ gnutls_free(nodes->sorted_view);
+ nodes->data = result.data;
+ nodes->sorted_view = NULL;
+ nodes->size = result.size;
+ nodes->capacity = result.capacity;
+ nodes->dirty = true;
+ /* since we know it's sorted, populate sorted_view almost for free */
+ nodes->sorted_view = gnutls_calloc(
+ nodes->size, sizeof(struct name_constraints_node_st *));
+ if (!nodes->sorted_view)
+ return GNUTLS_E_SUCCESS; /* we tried, no harm done */
+ memcpy(nodes->sorted_view, nodes->data,
+ nodes->size * sizeof(struct name_constraints_node_st *));
+ nodes->dirty = false;
+
+ result.data = NULL;
+ return GNUTLS_E_SUCCESS;
+cleanup:
+ name_constraints_node_list_clear(&result);
+ return gnutls_assert_val(ret);
}
/**
* @nc2: The name constraints to be merged with
*
* This function will merge the provided name constraints structures
- * as per RFC5280 p6.1.4. That is, the excluded constraints will be appended,
+ * as per RFC5280 p6.1.4. That is, the excluded constraints will be unioned,
* and permitted will be intersected. The intersection assumes that @nc
* is the root CA constraints.
*
return ret;
}
- ret = name_constraints_node_list_concat(nc, &nc->excluded,
- &nc2->excluded);
+ ret = name_constraints_node_list_union(nc, &nc->excluded,
+ &nc2->excluded);
if (ret < 0) {
gnutls_assert();
return ret;