verify-high.c 43 KB
Newer Older
1
/*
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
2 3
 * Copyright (C) 2011-2016 Free Software Foundation, Inc.
 * Copyright (C) 2015-2016 Red Hat, Inc.
4 5 6 7 8 9 10
 *
 * Author: Nikos Mavrogiannopoulos
 *
 * This file is part of GnuTLS.
 *
 * The GnuTLS is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
11
 * as published by the Free Software Foundation; either version 2.1 of
12 13 14 15 16 17 18
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
19
 * You should have received a copy of the GNU Lesser General Public License
20
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
21 22 23
 *
 */

24 25
#include "gnutls_int.h"
#include "errors.h"
26
#include <libtasn1.h>
27 28 29 30 31
#include <global.h>
#include <num.h>		/* MAX */
#include <tls-sig.h>
#include <str.h>
#include <datum.h>
32
#include <hash-pjw-bare.h>
33 34
#include "x509_int.h"
#include <common.h>
35
#include <gnutls/x509-ext.h>
36
#include "verify-high.h"
37

38
struct named_cert_st {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
39 40 41
	gnutls_x509_crt_t cert;
	uint8_t name[MAX_SERVER_NAME_SIZE];
	unsigned int name_size;
42 43 44
};

struct node_st {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
45 46 47
	/* The trusted certificates */
	gnutls_x509_crt_t *trusted_cas;
	unsigned int trusted_ca_size;
48

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
49 50
	struct named_cert_st *named_certs;
	unsigned int named_cert_size;
51

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
52 53 54
	/* The trusted CRLs */
	gnutls_x509_crl_t *crls;
	unsigned int crl_size;
55 56
};

57 58 59
struct gnutls_x509_trust_list_iter {
	unsigned int node_index;
	unsigned int ca_index;
60 61 62 63 64 65

#ifdef ENABLE_PKCS11
	gnutls_pkcs11_obj_t* pkcs11_list;
	unsigned int pkcs11_index;
	unsigned int pkcs11_size;
#endif
66 67
};

68
#define DEFAULT_SIZE 127
69 70 71

/**
 * gnutls_x509_trust_list_init:
72
 * @list: A pointer to the type to be initialized
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
73
 * @size: The size of the internal hash table. Use (0) for default size.
74 75 76
 *
 * This function will initialize an X.509 trust list structure.
 *
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
77
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
78
 *   negative error value.
79
 *
80
 * Since: 3.0.0
81 82
 **/
int
83
gnutls_x509_trust_list_init(gnutls_x509_trust_list_t * list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
84
			    unsigned int size)
85
{
86
	gnutls_x509_trust_list_t tmp;
87

88
	FAIL_IF_LIB_ERROR;
89

90
	tmp =
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
91
	    gnutls_calloc(1, sizeof(struct gnutls_x509_trust_list_st));
92

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
93 94
	if (!tmp)
		return GNUTLS_E_MEMORY_ERROR;
95

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
96 97 98
	if (size == 0)
		size = DEFAULT_SIZE;
	tmp->size = size;
99

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
100 101 102 103 104 105
	tmp->node = gnutls_calloc(1, tmp->size * sizeof(tmp->node[0]));
	if (tmp->node == NULL) {
		gnutls_assert();
		gnutls_free(tmp);
		return GNUTLS_E_MEMORY_ERROR;
	}
106

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
107
	*list = tmp;
108

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
109
	return 0;		/* success */
110 111 112 113
}

/**
 * gnutls_x509_trust_list_deinit:
114
 * @list: The list to be deinitialized
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
115
 * @all: if non-zero it will deinitialize all the certificates and CRLs contained in the structure.
116
 *
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
117 118 119 120
 * This function will deinitialize a trust list. Note that the
 * @all flag should be typically non-zero unless you have specified
 * your certificates using gnutls_x509_trust_list_add_cas() and you
 * want to prevent them from being deinitialized by this function.
121
 *
122
 * Since: 3.0.0
123 124
 **/
void
125
gnutls_x509_trust_list_deinit(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
126
			      unsigned int all)
127
{
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
128 129 130 131 132
	unsigned int i, j;

	if (!list)
		return;

133 134 135 136 137
	for (j = 0; j < list->blacklisted_size; j++) {
		gnutls_x509_crt_deinit(list->blacklisted[j]);
	}
	gnutls_free(list->blacklisted);

138 139 140 141 142
	for (j = 0; j < list->keep_certs_size; j++) {
		gnutls_x509_crt_deinit(list->keep_certs[j]);
	}
	gnutls_free(list->keep_certs);

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
143
	for (i = 0; i < list->size; i++) {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
144
		if (all) {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
145 146 147 148
			for (j = 0; j < list->node[i].trusted_ca_size; j++) {
				gnutls_x509_crt_deinit(list->node[i].
						       trusted_cas[j]);
			}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
149
		}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
150 151
		gnutls_free(list->node[i].trusted_cas);

152

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
153
		if (all) {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
154 155 156 157
			for (j = 0; j < list->node[i].crl_size; j++) {
				gnutls_x509_crl_deinit(list->node[i].
						       crls[j]);
			}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
158
		}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
159 160
		gnutls_free(list->node[i].crls);

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
161
		if (all) {
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
162 163 164 165 166
			for (j = 0; j < list->node[i].named_cert_size; j++) {
				gnutls_x509_crt_deinit(list->node[i].
						       named_certs[j].
						       cert);
			}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
167
		}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
168 169 170
		gnutls_free(list->node[i].named_certs);
	}

171
	gnutls_free(list->x509_rdn_sequence.data);
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
172
	gnutls_free(list->node);
173
	gnutls_free(list->pkcs11_token);
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
174
	gnutls_free(list);
175 176
}

177 178 179 180 181 182 183 184 185 186 187 188
static int
add_new_ca_to_rdn_seq(gnutls_x509_trust_list_t list,
		       gnutls_x509_crt_t ca)
{
	gnutls_datum_t tmp;
	size_t newsize;
	unsigned char *newdata, *p;

	/* Add DN of the last added CAs to the RDN sequence
	 * This will be sent to clients when a certificate
	 * request message is sent.
	 */
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
189 190
	tmp.data = ca->raw_dn.data;
	tmp.size = ca->raw_dn.size;
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216

	newsize = list->x509_rdn_sequence.size + 2 + tmp.size;
	if (newsize < list->x509_rdn_sequence.size) {
		gnutls_assert();
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
	}

	newdata =
	    gnutls_realloc_fast(list->x509_rdn_sequence.data,
				newsize);
	if (newdata == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	p = newdata + list->x509_rdn_sequence.size;
	_gnutls_write_uint16(tmp.size, p);
	if (tmp.data != NULL)
		memcpy(p + 2, tmp.data, tmp.size);

	list->x509_rdn_sequence.size = newsize;
	list->x509_rdn_sequence.data = newdata;

	return 0;
}

217 218
#ifdef ENABLE_PKCS11
/* Keeps the provided certificate in a structure that will be
219
 * deallocated on deinit. This is to handle get_issuer() with
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
 * pkcs11 trust modules when the GNUTLS_TL_GET_COPY flag isn't
 * given. It is not thread safe. */
static int
trust_list_add_compat(gnutls_x509_trust_list_t list,
			       gnutls_x509_crt_t cert)
{
	list->keep_certs =
		    gnutls_realloc_fast(list->keep_certs,
					(list->keep_certs_size +
					 1) *
					sizeof(list->keep_certs[0]));
	if (list->keep_certs == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	list->keep_certs[list->keep_certs_size] = cert;
	list->keep_certs_size++;

	return 0;
}
#endif

243 244
/**
 * gnutls_x509_trust_list_add_cas:
245
 * @list: The list
246 247
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
248
 * @flags: flags from %gnutls_trust_list_flags_t
249 250
 *
 * This function will add the given certificate authorities
251 252
 * to the trusted list. The CAs in @clist must not be deinitialized
 * during the lifetime of @list.
253
 *
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
254
 * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then
255 256
 * this function will ensure that no duplicates will be
 * present in the final trust list.
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
257
 *
258 259 260 261 262 263 264 265 266 267
 * If the flag %GNUTLS_TL_NO_DUPLICATE_KEY is specified, then
 * this function will ensure that no certificates with the
 * same key are present in the final trust list.
 *
 * If either %GNUTLS_TL_NO_DUPLICATE_KEY or %GNUTLS_TL_NO_DUPLICATES
 * are given, gnutls_x509_trust_list_deinit() must be called with parameter
 * @all being 1.
 *
 * Returns: The number of added elements is returned; that includes
 *          duplicate entries.
268
 *
269
 * Since: 3.0.0
270 271
 **/
int
272
gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
273
			       const gnutls_x509_crt_t * clist,
274
			       unsigned clist_size, unsigned int flags)
275
{
276
	unsigned i, j;
277
	size_t hash;
278
	int ret;
279
	unsigned exists;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
280 281

	for (i = 0; i < clist_size; i++) {
282
		exists = 0;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
283 284 285 286 287
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

288
		/* avoid duplicates */
289
		if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) {
290
			for (j=0;j<list->node[hash].trusted_ca_size;j++) {
291
				if (flags & GNUTLS_TL_NO_DUPLICATES)
292
					ret = gnutls_x509_crt_equals(list->node[hash].trusted_cas[j], clist[i]);
293 294 295
				else
					ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1);
				if (ret != 0) {
296 297 298 299 300 301
					exists = 1;
					break;
				}
			}

			if (exists != 0) {
302 303
				gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]);
				list->node[hash].trusted_cas[j] = clist[i];
304 305 306 307
				continue;
			}
		}

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
308 309 310 311 312 313 314 315 316 317 318
		list->node[hash].trusted_cas =
		    gnutls_realloc_fast(list->node[hash].trusted_cas,
					(list->node[hash].trusted_ca_size +
					 1) *
					sizeof(list->node[hash].
					       trusted_cas[0]));
		if (list->node[hash].trusted_cas == NULL) {
			gnutls_assert();
			return i;
		}

319 320 321 322 323 324 325 326 327 328 329 330
		if (gnutls_x509_crt_get_version(clist[i]) >= 3 &&
		    gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) {
			gnutls_datum_t dn;
			gnutls_assert();
			if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) {
				_gnutls_audit_log(NULL,
					  "There was a non-CA certificate in the trusted list: %s.\n",
					  dn.data);
				gnutls_free(dn.data);
			}
		}

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
331 332 333
		list->node[hash].trusted_cas[list->node[hash].
					     trusted_ca_size] = clist[i];
		list->node[hash].trusted_ca_size++;
334 335 336 337 338

		if (flags & GNUTLS_TL_USE_IN_TLS) {
			ret = add_new_ca_to_rdn_seq(list, clist[i]);
			if (ret < 0) {
				gnutls_assert();
339
				return i+1;
340 341
			}
		}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
342 343 344
	}

	return i;
345 346
}

347 348
static int
advance_iter(gnutls_x509_trust_list_t list,
349
	     gnutls_x509_trust_list_iter_t iter)
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367
{
	if (iter->node_index < list->size) {
		++iter->ca_index;

		/* skip entries */
		while (iter->node_index < list->size &&
		       iter->ca_index >= list->node[iter->node_index].trusted_ca_size) {
			++iter->node_index;
			iter->ca_index = 0;
		}

		if (iter->node_index < list->size)
			return 0;
	}

#ifdef ENABLE_PKCS11
	if (list->pkcs11_token != NULL) {
		if (iter->pkcs11_list == NULL) {
368
			int ret = gnutls_pkcs11_obj_list_import_url2(&iter->pkcs11_list, &iter->pkcs11_size,
369
			    list->pkcs11_token, (GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|GNUTLS_PKCS11_OBJ_FLAG_CRT|GNUTLS_PKCS11_OBJ_FLAG_MARK_CA|GNUTLS_PKCS11_OBJ_FLAG_MARK_TRUSTED), 0);
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
			if (ret < 0)
				return gnutls_assert_val(ret);

			if (iter->pkcs11_size > 0)
				return 0;
		} else if (iter->pkcs11_index < iter->pkcs11_size) {
			++iter->pkcs11_index;
			if (iter->pkcs11_index < iter->pkcs11_size)
				return 0;
		}
	}
#endif

	return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
}

386 387
/**
 * gnutls_x509_trust_list_iter_get_ca:
388
 * @list: The list
389 390 391 392 393 394 395 396 397 398
 * @iter: A pointer to an iterator (initially the iterator should be %NULL)
 * @crt: where the certificate will be copied
 *
 * This function obtains a certificate in the trust list and advances the
 * iterator to the next certificate. The certificate returned in @crt must be
 * deallocated with gnutls_x509_crt_deinit().
 *
 * When past the last element is accessed %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
 * is returned and the iterator is reset.
 *
399 400 401 402 403
 * The iterator is deinitialized and reset to %NULL automatically by this
 * function after iterating through all elements until
 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned. If the iteration is
 * aborted early, it must be manually deinitialized using
 * gnutls_x509_trust_list_iter_deinit().
404 405 406 407 408 409 410 411
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.4.0
 **/
int
gnutls_x509_trust_list_iter_get_ca(gnutls_x509_trust_list_t list,
412 413
				   gnutls_x509_trust_list_iter_t *iter,
				   gnutls_x509_crt_t *crt)
414 415 416
{
	int ret;

417
	/* initialize iterator */
418 419 420 421 422 423 424 425
	if (*iter == NULL) {
		*iter = gnutls_malloc(sizeof (struct gnutls_x509_trust_list_iter));
		if (*iter == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		(*iter)->node_index = 0;
		(*iter)->ca_index = 0;

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
#ifdef ENABLE_PKCS11
		(*iter)->pkcs11_list = NULL;
		(*iter)->pkcs11_size = 0;
		(*iter)->pkcs11_index = 0;
#endif

		/* Advance iterator to the first valid entry */
		if (list->node[0].trusted_ca_size == 0) {
			ret = advance_iter(list, *iter);
			if (ret != 0) {
				gnutls_x509_trust_list_iter_deinit(*iter);
				*iter = NULL;

				*crt = NULL;
				return gnutls_assert_val(ret);
			}
		}
	}
444

445 446 447 448 449
	/* obtain the certificate at the current iterator position */
	if ((*iter)->node_index < list->size) {
		ret = gnutls_x509_crt_init(crt);
		if (ret < 0)
			return gnutls_assert_val(ret);
450

451
		ret = _gnutls_x509_crt_cpy(*crt, list->node[(*iter)->node_index].trusted_cas[(*iter)->ca_index]);
452 453 454 455 456 457 458 459 460 461 462 463 464 465 466
		if (ret < 0) {
			gnutls_x509_crt_deinit(*crt);
			return gnutls_assert_val(ret);
		}
	}
#ifdef ENABLE_PKCS11
	else if ( (*iter)->pkcs11_index < (*iter)->pkcs11_size) {
		ret = gnutls_x509_crt_init(crt);
		if (ret < 0)
			return gnutls_assert_val(ret);

		ret = gnutls_x509_crt_import_pkcs11(*crt, (*iter)->pkcs11_list[(*iter)->pkcs11_index]);
		if (ret < 0) {
			gnutls_x509_crt_deinit(*crt);
			return gnutls_assert_val(ret);
467 468
		}
	}
469
#endif
470

471 472 473 474
	else {
		/* iterator is at end */
		gnutls_x509_trust_list_iter_deinit(*iter);
		*iter = NULL;
475

476 477 478 479 480 481 482 483 484 485 486
		*crt = NULL;
		return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
	}

	/* Move iterator to the next position.
	 * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned if the iterator
	 * has been moved to the end position. That is okay, we return the
	 * certificate that we read and when this function is called again we
	 * report GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE to our caller. */
	ret = advance_iter(list, *iter);
	if (ret	< 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
487
		gnutls_x509_crt_deinit(*crt);
488 489
		*crt = NULL;

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
		return gnutls_assert_val(ret);
	}

	return 0;
}

/**
 * gnutls_x509_trust_list_iter_deinit:
 * @iter: The iterator structure to be deinitialized
 *
 * This function will deinitialize an iterator structure.
 *
 * Since: 3.4.0
 **/
void gnutls_x509_trust_list_iter_deinit(gnutls_x509_trust_list_iter_t iter)
{
	if (!iter)
		return;

509 510 511 512 513 514 515 516 517
#ifdef ENABLE_PKCS11
	if (iter->pkcs11_size > 0) {
		unsigned i;
		for (i = 0; i < iter->pkcs11_size; ++i)
			gnutls_pkcs11_obj_deinit(iter->pkcs11_list[i]);
		gnutls_free(iter->pkcs11_list);
	}
#endif

518 519 520
	gnutls_free(iter);
}

521 522 523 524 525 526 527 528 529 530
static gnutls_x509_crt_t crt_cpy(gnutls_x509_crt_t src)
{
gnutls_x509_crt_t dst;
int ret;

	ret = gnutls_x509_crt_init(&dst);
	if (ret < 0) {
		gnutls_assert();
		return NULL;
	}
531

532
	ret = _gnutls_x509_crt_cpy(dst, src);
533
	if (ret < 0) {
534
		gnutls_x509_crt_deinit(dst);
535 536 537
		gnutls_assert();
		return NULL;
	}
538

539 540 541
	return dst;
}

542 543
/**
 * gnutls_x509_trust_list_remove_cas:
544
 * @list: The list
545 546 547 548
 * @clist: A list of CAs
 * @clist_size: The length of the CA list
 *
 * This function will remove the given certificate authorities
549 550 551 552 553 554 555
 * from the trusted list.
 *
 * Note that this function can accept certificates and authorities
 * not yet known. In that case they will be kept in a separate
 * black list that will be used during certificate verification.
 * Unlike gnutls_x509_trust_list_add_cas() there is no deinitialization
 * restriction for  certificate list provided in this function.
556 557 558 559 560 561 562
 *
 * Returns: The number of removed elements is returned.
 *
 * Since: 3.1.10
 **/
int
gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
563
				  const gnutls_x509_crt_t * clist,
564
				  unsigned clist_size)
565
{
566 567
	int r = 0;
	unsigned j, i;
568
	size_t hash;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
569 570 571 572 573 574 575 576

	for (i = 0; i < clist_size; i++) {
		hash =
		    hash_pjw_bare(clist[i]->raw_dn.data,
				  clist[i]->raw_dn.size);
		hash %= list->size;

		for (j = 0; j < list->node[hash].trusted_ca_size; j++) {
577
			if (gnutls_x509_crt_equals
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
578 579
			    (clist[i],
			     list->node[hash].trusted_cas[j]) != 0) {
580

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
581 582 583 584 585 586 587 588 589 590
				gnutls_x509_crt_deinit(list->node[hash].
						       trusted_cas[j]);
				list->node[hash].trusted_cas[j] =
				    list->node[hash].trusted_cas[list->
								 node
								 [hash].
								 trusted_ca_size
								 - 1];
				list->node[hash].trusted_ca_size--;
				r++;
591
				break;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
592 593
			}
		}
594

595
		/* Add the CA (or plain) certificate to the black list as well.
596
		 * This will prevent a subordinate CA from being valid, and
597 598 599 600 601 602 603 604 605 606 607 608
		 * ensure that a server certificate will also get rejected.
		 */
		list->blacklisted =
		    gnutls_realloc_fast(list->blacklisted,
				(list->blacklisted_size + 1) *
				sizeof(list->blacklisted[0]));
		if (list->blacklisted == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		list->blacklisted[list->blacklisted_size] = crt_cpy(clist[i]);
		if (list->blacklisted[list->blacklisted_size] != NULL)
			list->blacklisted_size++;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
609 610 611
	}

	return r;
612 613
}

614 615
/**
 * gnutls_x509_trust_list_add_named_crt:
616
 * @list: The list
617 618 619 620 621 622 623 624
 * @cert: A certificate
 * @name: An identifier for the certificate
 * @name_size: The size of the identifier
 * @flags: should be 0.
 *
 * This function will add the given certificate to the trusted
 * list and associate it with a name. The certificate will not be
 * be used for verification with gnutls_x509_trust_list_verify_crt()
625 626 627
 * but with gnutls_x509_trust_list_verify_named_crt() or
 * gnutls_x509_trust_list_verify_crt2() - the latter only since
 * GnuTLS 3.4.0 and if a hostname is provided.
628 629 630 631 632
 *
 * In principle this function can be used to set individual "server"
 * certificates that are trusted by the user for that specific server
 * but for no other purposes.
 *
633 634
 * The certificate @cert must not be deinitialized during the lifetime
 * of the @list.
635
 *
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
636
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
637 638
 *   negative error value.
 *
639
 * Since: 3.0.0
640 641
 **/
int
642
gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
643 644 645
				     gnutls_x509_crt_t cert,
				     const void *name, size_t name_size,
				     unsigned int flags)
646
{
647
	size_t hash;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676

	if (name_size >= MAX_SERVER_NAME_SIZE)
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

	hash =
	    hash_pjw_bare(cert->raw_issuer_dn.data,
			  cert->raw_issuer_dn.size);
	hash %= list->size;

	list->node[hash].named_certs =
	    gnutls_realloc_fast(list->node[hash].named_certs,
				(list->node[hash].named_cert_size +
				 1) *
				sizeof(list->node[hash].named_certs[0]));
	if (list->node[hash].named_certs == NULL)
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

	list->node[hash].named_certs[list->node[hash].named_cert_size].
	    cert = cert;
	memcpy(list->node[hash].
	       named_certs[list->node[hash].named_cert_size].name, name,
	       name_size);
	list->node[hash].named_certs[list->node[hash].
				     named_cert_size].name_size =
	    name_size;

	list->node[hash].named_cert_size++;

	return 0;
677 678
}

679 680
/**
 * gnutls_x509_trust_list_add_crls:
681
 * @list: The list
682 683
 * @crl_list: A list of CRLs
 * @crl_size: The length of the CRL list
684
 * @flags: flags from %gnutls_trust_list_flags_t
685 686 687
 * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL
 *
 * This function will add the given certificate revocation lists
688 689
 * to the trusted list. The CRLs in @crl_list must not be deinitialized
 * during the lifetime of @list.
690 691
 *
 * This function must be called after gnutls_x509_trust_list_add_cas()
692
 * to allow verifying the CRLs for validity. If the flag %GNUTLS_TL_NO_DUPLICATES
693 694 695 696
 * is given, then the final CRL list will not contain duplicate entries.
 *
 * If the flag %GNUTLS_TL_NO_DUPLICATES is given, gnutls_x509_trust_list_deinit() must be
 * called with parameter @all being 1.
697
 *
698 699
 * If flag %GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added,
 * and if verification fails, they will be skipped.
700
 *
701 702
 * Returns: The number of added elements is returned; that includes
 *          duplicate entries.
703
 *
704
 * Since: 3.0
705 706
 **/
int
707
gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
708
				const gnutls_x509_crl_t * crl_list,
709
				unsigned crl_size, unsigned int flags,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
710
				unsigned int verification_flags)
711
{
712 713
	int ret;
	unsigned x, i, j = 0;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
714
	unsigned int vret = 0;
715
	size_t hash;
716
	gnutls_x509_crl_t *tmp;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739

	/* Probably we can optimize things such as removing duplicates
	 * etc.
	 */
	if (crl_size == 0 || crl_list == NULL)
		return 0;

	for (i = 0; i < crl_size; i++) {
		hash =
		    hash_pjw_bare(crl_list[i]->raw_issuer_dn.data,
				  crl_list[i]->raw_issuer_dn.size);
		hash %= list->size;

		if (flags & GNUTLS_TL_VERIFY_CRL) {

			ret =
			    gnutls_x509_crl_verify(crl_list[i],
						   list->node[hash].
						   trusted_cas,
						   list->node[hash].
						   trusted_ca_size,
						   verification_flags,
						   &vret);
740 741
			if (ret < 0 || vret != 0) {
				_gnutls_debug_log("CRL verification failed, not adding it\n");
742 743
				if (flags & GNUTLS_TL_NO_DUPLICATES)
					gnutls_x509_crl_deinit(crl_list[i]);
744 745
				if (flags & GNUTLS_TL_FAIL_ON_INVALID_CRL)
					return gnutls_assert_val(GNUTLS_E_CRL_VERIFICATION_ERROR);
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
746
				continue;
747 748 749 750 751 752 753 754 755 756 757 758
			}
		}

		/* If the CRL added overrides a previous one, then overwrite
		 * the old one */
		if (flags & GNUTLS_TL_NO_DUPLICATES) {
			for (x=0;x<list->node[hash].crl_size;x++) {
				if (crl_list[i]->raw_issuer_dn.size == list->node[hash].crls[x]->raw_issuer_dn.size &&
				    memcmp(crl_list[i]->raw_issuer_dn.data, list->node[hash].crls[x]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size) == 0) {
					if (gnutls_x509_crl_get_this_update(crl_list[i]) >=
					    gnutls_x509_crl_get_this_update(list->node[hash].crls[x])) {

759 760 761
						gnutls_x509_crl_deinit(list->node[hash].crls[x]);
						list->node[hash].crls[x] = crl_list[i];
						goto next;
762 763 764
					} else {
						/* The new is older, discard it */
						gnutls_x509_crl_deinit(crl_list[i]);
765
						goto next;
766 767 768
					}
				}
			}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
769 770
		}

771 772
		tmp =
		    gnutls_realloc(list->node[hash].crls,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
773 774 775
					(list->node[hash].crl_size +
					 1) *
					sizeof(list->node[hash].
776
					       crls[0]));
777 778
		if (tmp == NULL) {
			ret = i;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
779
			gnutls_assert();
780 781 782 783
			if (flags & GNUTLS_TL_NO_DUPLICATES)
				while (i < crl_size)
					gnutls_x509_crl_deinit(crl_list[i++]);
			return ret;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
784
		}
785 786
		list->node[hash].crls = tmp;

Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
787 788 789 790

		list->node[hash].crls[list->node[hash].crl_size] =
		    crl_list[i];
		list->node[hash].crl_size++;
791 792

 next:
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
793 794 795 796
		j++;
	}

	return j;
797 798
}

799 800 801 802 803
/* Takes a certificate list and shortens it if there are
 * intermedia certificates already trusted by us.
 *
 * Returns the new size of the list or a negative number on error.
 */
804
static int shorten_clist(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
805 806
			 gnutls_x509_crt_t * certificate_list,
			 unsigned int clist_size)
807
{
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
808
	unsigned int j, i;
809
	size_t hash;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839

	if (clist_size > 1) {
		/* Check if the last certificate in the path is self signed.
		 * In that case ignore it (a certificate is trusted only if it
		 * leads to a trusted party by us, not the server's).
		 *
		 * This prevents from verifying self signed certificates against
		 * themselves. This (although not bad) caused verification
		 * failures on some root self signed certificates that use the
		 * MD2 algorithm.
		 */
		if (gnutls_x509_crt_check_issuer
		    (certificate_list[clist_size - 1],
		     certificate_list[clist_size - 1]) != 0) {
			clist_size--;
		}
	}

	/* We want to shorten the chain by removing the cert that matches
	 * one of the certs we trust and all the certs after that i.e. if
	 * cert chain is A signed-by B signed-by C signed-by D (signed-by
	 * self-signed E but already removed above), and we trust B, remove
	 * B, C and D. */
	for (i = 1; i < clist_size; i++) {
		hash =
		    hash_pjw_bare(certificate_list[i]->raw_issuer_dn.data,
				  certificate_list[i]->raw_issuer_dn.size);
		hash %= list->size;

		for (j = 0; j < list->node[hash].trusted_ca_size; j++) {
840
			if (gnutls_x509_crt_equals
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
841 842 843 844 845 846 847 848 849 850 851
			    (certificate_list[i],
			     list->node[hash].trusted_cas[j]) != 0) {
				/* cut the list at the point of first the trusted certificate */
				clist_size = i + 1;
				break;
			}
		}
		/* clist_size may have been changed which gets out of loop */
	}

	return clist_size;
852 853
}

854 855
static
int trust_list_get_issuer(gnutls_x509_trust_list_t list,
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
856 857 858
				      gnutls_x509_crt_t cert,
				      gnutls_x509_crt_t * issuer,
				      unsigned int flags)
859
{
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
860 861
	int ret;
	unsigned int i;
862
	size_t hash;
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
863 864 865 866 867 868 869 870 871 872 873 874

	hash =
	    hash_pjw_bare(cert->raw_issuer_dn.data,
			  cert->raw_issuer_dn.size);
	hash %= list->size;

	for (i = 0; i < list->node[hash].trusted_ca_size; i++) {
		ret =
		    gnutls_x509_crt_check_issuer(cert,
						 list->node[hash].
						 trusted_cas[i]);
		if (ret != 0) {
875 876 877 878 879
			if (flags & GNUTLS_TL_GET_COPY) {
				*issuer = crt_cpy(list->node[hash].trusted_cas[i]);
			} else {
				*issuer = list->node[hash].trusted_cas[i];
			}
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
880 881 882 883 884
			return 0;
		}
	}

	return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
885
}
886

887 888 889
static
int trust_list_get_issuer_by_dn(gnutls_x509_trust_list_t list,
				      const gnutls_datum_t *dn,
890
				      const gnutls_datum_t *spki,
891 892 893 894
				      gnutls_x509_crt_t * issuer,
				      unsigned int flags)
{
	int ret;
895
	unsigned int i, j;
896
	size_t hash;
897 898
	uint8_t tmp[256];
	size_t tmp_size;
899

900 901 902 903 904
	if (dn) {
		hash =
		    hash_pjw_bare(dn->data,
				  dn->size);
		hash %= list->size;
905

906
		for (i = 0; i < list->node[hash].trusted_ca_size; i++) {
907 908 909 910 911 912 913 914 915 916 917 918 919 920
			ret = _gnutls_x509_compare_raw_dn(dn, &list->node[hash].trusted_cas[i]->raw_dn);
			if (ret != 0) {
				if (spki && spki->size > 0) {
					tmp_size = sizeof(tmp);

					ret = gnutls_x509_crt_get_subject_key_id(list->node[hash].trusted_cas[i], tmp, &tmp_size, NULL);
					if (ret < 0)
						continue;
					if (spki->size != tmp_size || memcmp(spki->data, tmp, spki->size) != 0)
						continue;
				}
				*issuer = crt_cpy(list->node[hash].trusted_cas[i]);
				return 0;
			}
921 922 923 924 925 926
		}
	} else if (spki) {
		/* search everything! */
		for (i = 0; i < list->size; i++) {
			for (j = 0; j < list->node[i].trusted_ca_size; j++) {
				tmp_size = sizeof(tmp);
927

928 929 930
				ret = gnutls_x509_crt_get_subject_key_id(list->node[i].trusted_cas[j], tmp, &tmp_size, NULL);
				if (ret < 0)
					continue;
931

932 933
				if (spki->size != tmp_size || memcmp(spki->data, tmp, spki->size) != 0)
					continue;
934

935 936
				*issuer = crt_cpy(list->node[i].trusted_cas[j]);
				return 0;
937
			}
938 939 940 941 942 943
		}
	}

	return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}

944 945
/**
 * gnutls_x509_trust_list_get_issuer:
946
 * @list: The list
947 948
 * @cert: is the certificate to find issuer for
 * @issuer: Will hold the issuer if any. Should be treated as constant.
949
 * @flags: flags from %gnutls_trust_list_flags_t (%GNUTLS_TL_GET_COPY is applicable)
950
 *
951 952 953
 * This function will find the issuer of the given certificate.
 * If the flag %GNUTLS_TL_GET_COPY is specified a copy of the issuer
 * will be returned which must be freed using gnutls_x509_crt_deinit().
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
954 955
 * In that case the provided @issuer must not be initialized.
 *
956
 * Note that the flag %GNUTLS_TL_GET_COPY is required for this function
Nikos Mavrogiannopoulos's avatar
Nikos Mavrogiannopoulos committed
957
 * to work with PKCS#11 trust lists in a thread-safe way.
958 959 960 961 962 963 964 965 966 967 968 969
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.0
 **/
int gnutls_x509_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;
970 971 972 973 974

	ret = trust_list_get_issuer(list, cert, issuer, flags);
	if (ret == 0) {
		return 0;
	}
975

976
#ifdef ENABLE_PKCS11
977 978
	if (ret < 0 && list->pkcs11_token) {
		gnutls_x509_crt_t crt;
979 980 981
		gnutls_datum_t der = {NULL, 0};
		/* use the token for verification */
		ret = gnutls_pkcs11_get_raw_issuer(list->pkcs11_token, cert, &der,
982
			GNUTLS_X509_FMT_DER, GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE);
983 984 985 986
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}
987

988 989 990 991 992 993 994 995 996 997 998 999
		ret = gnutls_x509_crt_init(&crt);
		if (ret < 0) {
			gnutls_free(der.data);
			return gnutls_assert_val(ret);
		}

		ret = gnutls_x509_crt_import(crt, &der, GNUTLS_X509_FMT_DER);
		gnutls_free(der.data);
		if (ret < 0) {
			gnutls_x509_crt_deinit(crt);
			return gnutls_assert_val(ret);
		}
1000

1001 1002 1003 1004 1005 1006 1007 1008
		if (flags & GNUTLS_TL_GET_COPY) {
			*issuer = crt;
			return 0;
		} else {
			/* we add this CA to the keep_cert list in order to make it
			 * persistent. It will be deallocated when the trust list is.
			 */
			ret = trust_list_add_compat(list, crt);
1009 1010 1011 1012
			if (ret < 0) {
				gnutls_x509_crt_deinit(crt);
				return gnutls_assert_val(ret);
			}
1013
			*issuer = crt;
1014
			return ret;
1015
		}
1016 1017
	}
#endif
1018
	return ret;
1019 1020
}

1021 1022
/**
 * gnutls_x509_trust_list_get_issuer_by_dn:
1023
 * @list: The list
1024
 * @dn: is the issuer's DN
1025
 * @issuer: Will hold the issuer if any. Should be deallocated after use.
1026 1027
 * @flags: Use zero
 *
1028
 * This function will find the issuer with the given name, and
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
 * return a copy of the issuer, which must be freed using gnutls_x509_crt_deinit().
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
 *   negative error value.
 *
 * Since: 3.4.0
 **/
int gnutls_x509_trust_list_get_issuer_by_dn(gnutls_x509_trust_list_t list,
				      const gnutls_datum_t *dn,
				      gnutls_x509_crt_t *issuer,
				      unsigned int flags)
{
	int ret;

1043
	ret = trust_list_get_issuer_by_dn(list, dn, NULL, issuer, flags);
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	if (ret == 0) {
		return 0;
	}

#ifdef ENABLE_PKCS11
	if (ret < 0 && list->pkcs11_token) {
		gnutls_x509_crt_t crt;
		gnutls_datum_t der = {NULL, 0};
		/* use the token for verification */
		ret = gnutls_pkcs11_get_raw_issuer_by_dn(list->pkcs11_token, dn, &der,
1054
			GNUTLS_X509_FMT_DER, GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE);
1055 1056 1057 1058 1059 1060 1061
		if (ret < 0) {
			gnutls_assert();
			return ret;
		}

		ret = gnutls_x509_crt_init(&crt);
		if (ret < 0) {
1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081