os/ossrv/ssl/libcrypto/src/crypto/x509v3/pcy_tree.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
/* pcy_tree.c */
sl@0
     2
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
sl@0
     3
 * project 2004.
sl@0
     4
 */
sl@0
     5
/* ====================================================================
sl@0
     6
 * Copyright (c) 2004 The OpenSSL Project.  All rights reserved.
sl@0
     7
 *
sl@0
     8
 * Redistribution and use in source and binary forms, with or without
sl@0
     9
 * modification, are permitted provided that the following conditions
sl@0
    10
 * are met:
sl@0
    11
 *
sl@0
    12
 * 1. Redistributions of source code must retain the above copyright
sl@0
    13
 *    notice, this list of conditions and the following disclaimer. 
sl@0
    14
 *
sl@0
    15
 * 2. Redistributions in binary form must reproduce the above copyright
sl@0
    16
 *    notice, this list of conditions and the following disclaimer in
sl@0
    17
 *    the documentation and/or other materials provided with the
sl@0
    18
 *    distribution.
sl@0
    19
 *
sl@0
    20
 * 3. All advertising materials mentioning features or use of this
sl@0
    21
 *    software must display the following acknowledgment:
sl@0
    22
 *    "This product includes software developed by the OpenSSL Project
sl@0
    23
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
sl@0
    24
 *
sl@0
    25
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
sl@0
    26
 *    endorse or promote products derived from this software without
sl@0
    27
 *    prior written permission. For written permission, please contact
sl@0
    28
 *    licensing@OpenSSL.org.
sl@0
    29
 *
sl@0
    30
 * 5. Products derived from this software may not be called "OpenSSL"
sl@0
    31
 *    nor may "OpenSSL" appear in their names without prior written
sl@0
    32
 *    permission of the OpenSSL Project.
sl@0
    33
 *
sl@0
    34
 * 6. Redistributions of any form whatsoever must retain the following
sl@0
    35
 *    acknowledgment:
sl@0
    36
 *    "This product includes software developed by the OpenSSL Project
sl@0
    37
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
sl@0
    38
 *
sl@0
    39
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
sl@0
    40
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0
    41
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
sl@0
    42
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
sl@0
    43
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
sl@0
    44
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
sl@0
    45
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
sl@0
    46
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0
    47
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
sl@0
    48
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
sl@0
    49
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
sl@0
    50
 * OF THE POSSIBILITY OF SUCH DAMAGE.
sl@0
    51
 * ====================================================================
sl@0
    52
 *
sl@0
    53
 * This product includes cryptographic software written by Eric Young
sl@0
    54
 * (eay@cryptsoft.com).  This product includes software written by Tim
sl@0
    55
 * Hudson (tjh@cryptsoft.com).
sl@0
    56
 *
sl@0
    57
 */
sl@0
    58
sl@0
    59
#include "cryptlib.h"
sl@0
    60
#include <openssl/x509.h>
sl@0
    61
#include <openssl/x509v3.h>
sl@0
    62
sl@0
    63
#include "pcy_int.h"
sl@0
    64
sl@0
    65
/* Initialize policy tree. Return values:
sl@0
    66
 *  0 Some internal error occured.
sl@0
    67
 * -1 Inconsistent or invalid extensions in certificates.
sl@0
    68
 *  1 Tree initialized OK.
sl@0
    69
 *  2 Policy tree is empty.
sl@0
    70
 *  5 Tree OK and requireExplicitPolicy true.
sl@0
    71
 *  6 Tree empty and requireExplicitPolicy true.
sl@0
    72
 */
sl@0
    73
sl@0
    74
static int tree_init(X509_POLICY_TREE **ptree, STACK_OF(X509) *certs,
sl@0
    75
			unsigned int flags)
sl@0
    76
	{
sl@0
    77
	X509_POLICY_TREE *tree;
sl@0
    78
	X509_POLICY_LEVEL *level;
sl@0
    79
	const X509_POLICY_CACHE *cache;
sl@0
    80
	X509_POLICY_DATA *data = NULL;
sl@0
    81
	X509 *x;
sl@0
    82
	int ret = 1;
sl@0
    83
	int i, n;
sl@0
    84
	int explicit_policy;
sl@0
    85
	int any_skip;
sl@0
    86
	int map_skip;
sl@0
    87
	*ptree = NULL;
sl@0
    88
	n = sk_X509_num(certs);
sl@0
    89
sl@0
    90
	/* Disable policy mapping for now... */
sl@0
    91
	flags |= X509_V_FLAG_INHIBIT_MAP;
sl@0
    92
sl@0
    93
	if (flags & X509_V_FLAG_EXPLICIT_POLICY)
sl@0
    94
		explicit_policy = 0;
sl@0
    95
	else
sl@0
    96
		explicit_policy = n + 1;
sl@0
    97
sl@0
    98
	if (flags & X509_V_FLAG_INHIBIT_ANY)
sl@0
    99
		any_skip = 0;
sl@0
   100
	else
sl@0
   101
		any_skip = n + 1;
sl@0
   102
sl@0
   103
	if (flags & X509_V_FLAG_INHIBIT_MAP)
sl@0
   104
		map_skip = 0;
sl@0
   105
	else
sl@0
   106
		map_skip = n + 1;
sl@0
   107
sl@0
   108
	/* Can't do anything with just a trust anchor */
sl@0
   109
	if (n == 1)
sl@0
   110
		return 1;
sl@0
   111
	/* First setup policy cache in all certificates apart from the
sl@0
   112
	 * trust anchor. Note any bad cache results on the way. Also can
sl@0
   113
	 * calculate explicit_policy value at this point.
sl@0
   114
	 */
sl@0
   115
	for (i = n - 2; i >= 0; i--)
sl@0
   116
		{
sl@0
   117
		x = sk_X509_value(certs, i);
sl@0
   118
		X509_check_purpose(x, -1, -1);
sl@0
   119
		cache = policy_cache_set(x);
sl@0
   120
		/* If cache NULL something bad happened: return immediately */
sl@0
   121
		if (cache == NULL)
sl@0
   122
			return 0;
sl@0
   123
		/* If inconsistent extensions keep a note of it but continue */
sl@0
   124
		if (x->ex_flags & EXFLAG_INVALID_POLICY)
sl@0
   125
			ret = -1;
sl@0
   126
		/* Otherwise if we have no data (hence no CertificatePolicies)
sl@0
   127
		 * and haven't already set an inconsistent code note it.
sl@0
   128
		 */
sl@0
   129
		else if ((ret == 1) && !cache->data)
sl@0
   130
			ret = 2;
sl@0
   131
		if (explicit_policy > 0)
sl@0
   132
			{
sl@0
   133
			explicit_policy--;
sl@0
   134
			if (!(x->ex_flags & EXFLAG_SS)
sl@0
   135
				&& (cache->explicit_skip != -1)
sl@0
   136
				&& (cache->explicit_skip < explicit_policy))
sl@0
   137
				explicit_policy = cache->explicit_skip;
sl@0
   138
			}
sl@0
   139
		}
sl@0
   140
sl@0
   141
	if (ret != 1)
sl@0
   142
		{
sl@0
   143
		if (ret == 2 && !explicit_policy)
sl@0
   144
			return 6;
sl@0
   145
		return ret;
sl@0
   146
		}
sl@0
   147
sl@0
   148
sl@0
   149
	/* If we get this far initialize the tree */
sl@0
   150
sl@0
   151
	tree = OPENSSL_malloc(sizeof(X509_POLICY_TREE));
sl@0
   152
sl@0
   153
	if (!tree)
sl@0
   154
		return 0;
sl@0
   155
sl@0
   156
	tree->flags = 0;
sl@0
   157
	tree->levels = OPENSSL_malloc(sizeof(X509_POLICY_LEVEL) * n);
sl@0
   158
#ifdef SYMBIAN	
sl@0
   159
	if (!tree->levels)
sl@0
   160
		return 0;
sl@0
   161
#endif
sl@0
   162
	tree->nlevel = 0;
sl@0
   163
	tree->extra_data = NULL;
sl@0
   164
	tree->auth_policies = NULL;
sl@0
   165
	tree->user_policies = NULL;
sl@0
   166
sl@0
   167
	if (!tree)
sl@0
   168
		{
sl@0
   169
		OPENSSL_free(tree);
sl@0
   170
		return 0;
sl@0
   171
		}
sl@0
   172
sl@0
   173
	memset(tree->levels, 0, n * sizeof(X509_POLICY_LEVEL));
sl@0
   174
sl@0
   175
	tree->nlevel = n;
sl@0
   176
sl@0
   177
	level = tree->levels;
sl@0
   178
sl@0
   179
	/* Root data: initialize to anyPolicy */
sl@0
   180
sl@0
   181
	data = policy_data_new(NULL, OBJ_nid2obj(NID_any_policy), 0);
sl@0
   182
sl@0
   183
	if (!data || !level_add_node(level, data, NULL, tree))
sl@0
   184
		goto bad_tree;
sl@0
   185
sl@0
   186
	for (i = n - 2; i >= 0; i--)
sl@0
   187
		{
sl@0
   188
		level++;
sl@0
   189
		x = sk_X509_value(certs, i);
sl@0
   190
		cache = policy_cache_set(x);
sl@0
   191
sl@0
   192
		CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
sl@0
   193
		level->cert = x;
sl@0
   194
sl@0
   195
		if (!cache->anyPolicy)
sl@0
   196
				level->flags |= X509_V_FLAG_INHIBIT_ANY;
sl@0
   197
sl@0
   198
		/* Determine inhibit any and inhibit map flags */
sl@0
   199
		if (any_skip == 0)
sl@0
   200
			{
sl@0
   201
			/* Any matching allowed if certificate is self
sl@0
   202
			 * issued and not the last in the chain.
sl@0
   203
			 */
sl@0
   204
			if (!(x->ex_flags & EXFLAG_SS) || (i == 0))
sl@0
   205
				level->flags |= X509_V_FLAG_INHIBIT_ANY;
sl@0
   206
			}
sl@0
   207
		else
sl@0
   208
			{
sl@0
   209
			any_skip--;
sl@0
   210
			if ((cache->any_skip > 0)
sl@0
   211
				&& (cache->any_skip < any_skip))
sl@0
   212
				any_skip = cache->any_skip;
sl@0
   213
			}
sl@0
   214
sl@0
   215
		if (map_skip == 0)
sl@0
   216
			level->flags |= X509_V_FLAG_INHIBIT_MAP;
sl@0
   217
		else
sl@0
   218
			{
sl@0
   219
			map_skip--;
sl@0
   220
			if ((cache->map_skip > 0)
sl@0
   221
				&& (cache->map_skip < map_skip))
sl@0
   222
				map_skip = cache->map_skip;
sl@0
   223
			}
sl@0
   224
sl@0
   225
sl@0
   226
		}
sl@0
   227
sl@0
   228
	*ptree = tree;
sl@0
   229
sl@0
   230
	if (explicit_policy)
sl@0
   231
		return 1;
sl@0
   232
	else
sl@0
   233
		return 5;
sl@0
   234
sl@0
   235
	bad_tree:
sl@0
   236
sl@0
   237
	X509_policy_tree_free(tree);
sl@0
   238
sl@0
   239
	return 0;
sl@0
   240
sl@0
   241
	}
sl@0
   242
sl@0
   243
/* This corresponds to RFC3280 XXXX XXXXX:
sl@0
   244
 * link any data from CertificatePolicies onto matching parent
sl@0
   245
 * or anyPolicy if no match.
sl@0
   246
 */
sl@0
   247
sl@0
   248
static int tree_link_nodes(X509_POLICY_LEVEL *curr,
sl@0
   249
				const X509_POLICY_CACHE *cache)
sl@0
   250
	{
sl@0
   251
	int i;
sl@0
   252
	X509_POLICY_LEVEL *last;
sl@0
   253
	X509_POLICY_DATA *data;
sl@0
   254
	X509_POLICY_NODE *parent;
sl@0
   255
	last = curr - 1;
sl@0
   256
	for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++)
sl@0
   257
		{
sl@0
   258
		data = sk_X509_POLICY_DATA_value(cache->data, i);
sl@0
   259
		/* If a node is mapped any it doesn't have a corresponding
sl@0
   260
		 * CertificatePolicies entry. 
sl@0
   261
		 * However such an identical node would be created
sl@0
   262
		 * if anyPolicy matching is enabled because there would be
sl@0
   263
		 * no match with the parent valid_policy_set. So we create
sl@0
   264
		 * link because then it will have the mapping flags
sl@0
   265
		 * right and we can prune it later.
sl@0
   266
		 */
sl@0
   267
		if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
sl@0
   268
			&& !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
sl@0
   269
			continue;
sl@0
   270
		/* Look for matching node in parent */
sl@0
   271
		parent = level_find_node(last, data->valid_policy);
sl@0
   272
		/* If no match link to anyPolicy */
sl@0
   273
		if (!parent)
sl@0
   274
			parent = last->anyPolicy;
sl@0
   275
		if (parent && !level_add_node(curr, data, parent, NULL))
sl@0
   276
				return 0;
sl@0
   277
		}
sl@0
   278
	return 1;
sl@0
   279
	}
sl@0
   280
sl@0
   281
/* This corresponds to RFC3280 XXXX XXXXX:
sl@0
   282
 * Create new data for any unmatched policies in the parent and link
sl@0
   283
 * to anyPolicy.
sl@0
   284
 */
sl@0
   285
sl@0
   286
static int tree_link_any(X509_POLICY_LEVEL *curr,
sl@0
   287
			const X509_POLICY_CACHE *cache,
sl@0
   288
			X509_POLICY_TREE *tree)
sl@0
   289
	{
sl@0
   290
	int i;
sl@0
   291
	X509_POLICY_DATA *data;
sl@0
   292
	X509_POLICY_NODE *node;
sl@0
   293
	X509_POLICY_LEVEL *last;
sl@0
   294
sl@0
   295
	last = curr - 1;
sl@0
   296
sl@0
   297
	for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
sl@0
   298
		{
sl@0
   299
		node = sk_X509_POLICY_NODE_value(last->nodes, i);
sl@0
   300
sl@0
   301
		/* Skip any node with any children: we only want unmathced
sl@0
   302
		 * nodes.
sl@0
   303
		 *
sl@0
   304
		 * Note: need something better for policy mapping
sl@0
   305
		 * because each node may have multiple children 
sl@0
   306
		 */
sl@0
   307
		if (node->nchild)
sl@0
   308
			continue;
sl@0
   309
		/* Create a new node with qualifiers from anyPolicy and
sl@0
   310
		 * id from unmatched node.
sl@0
   311
		 */
sl@0
   312
		data = policy_data_new(NULL, node->data->valid_policy, 
sl@0
   313
						node_critical(node));
sl@0
   314
sl@0
   315
		if (data == NULL)
sl@0
   316
			return 0;
sl@0
   317
		data->qualifier_set = curr->anyPolicy->data->qualifier_set;
sl@0
   318
		data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
sl@0
   319
		if (!level_add_node(curr, data, node, tree))
sl@0
   320
			{
sl@0
   321
			policy_data_free(data);
sl@0
   322
			return 0;
sl@0
   323
			}
sl@0
   324
		}
sl@0
   325
	/* Finally add link to anyPolicy */
sl@0
   326
	if (last->anyPolicy)
sl@0
   327
		{
sl@0
   328
		if (!level_add_node(curr, cache->anyPolicy,
sl@0
   329
						last->anyPolicy, NULL))
sl@0
   330
			return 0;
sl@0
   331
		}
sl@0
   332
	return 1;
sl@0
   333
	}
sl@0
   334
sl@0
   335
/* Prune the tree: delete any child mapped child data on the current level
sl@0
   336
 * then proceed up the tree deleting any data with no children. If we ever
sl@0
   337
 * have no data on a level we can halt because the tree will be empty.
sl@0
   338
 */
sl@0
   339
sl@0
   340
static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
sl@0
   341
	{
sl@0
   342
	X509_POLICY_NODE *node;
sl@0
   343
	int i;
sl@0
   344
	for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
sl@0
   345
		{
sl@0
   346
		node = sk_X509_POLICY_NODE_value(curr->nodes, i);
sl@0
   347
		/* Delete any mapped data: see RFC3280 XXXX */
sl@0
   348
		if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
sl@0
   349
			{
sl@0
   350
			node->parent->nchild--;
sl@0
   351
			OPENSSL_free(node);
sl@0
   352
			(void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
sl@0
   353
			}
sl@0
   354
		}
sl@0
   355
sl@0
   356
	for(;;)	{
sl@0
   357
		--curr;
sl@0
   358
		for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
sl@0
   359
			{
sl@0
   360
			node = sk_X509_POLICY_NODE_value(curr->nodes, i);
sl@0
   361
			if (node->nchild == 0)
sl@0
   362
				{
sl@0
   363
				node->parent->nchild--;
sl@0
   364
				OPENSSL_free(node);
sl@0
   365
				(void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
sl@0
   366
				}
sl@0
   367
			}
sl@0
   368
		if (curr->anyPolicy && !curr->anyPolicy->nchild)
sl@0
   369
			{
sl@0
   370
			if (curr->anyPolicy->parent)
sl@0
   371
				curr->anyPolicy->parent->nchild--;
sl@0
   372
			OPENSSL_free(curr->anyPolicy);
sl@0
   373
			curr->anyPolicy = NULL;
sl@0
   374
			}
sl@0
   375
		if (curr == tree->levels)
sl@0
   376
			{
sl@0
   377
			/* If we zapped anyPolicy at top then tree is empty */
sl@0
   378
			if (!curr->anyPolicy)
sl@0
   379
					return 2;
sl@0
   380
			return 1;
sl@0
   381
			}
sl@0
   382
		}
sl@0
   383
sl@0
   384
	return 1;
sl@0
   385
sl@0
   386
	}
sl@0
   387
sl@0
   388
static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes,
sl@0
   389
						 X509_POLICY_NODE *pcy)
sl@0
   390
	{
sl@0
   391
	if (!*pnodes)
sl@0
   392
		{
sl@0
   393
		*pnodes = policy_node_cmp_new();
sl@0
   394
		if (!*pnodes)
sl@0
   395
			return 0;
sl@0
   396
		}
sl@0
   397
	else if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1)
sl@0
   398
		return 1;
sl@0
   399
sl@0
   400
	if (!sk_X509_POLICY_NODE_push(*pnodes, pcy))
sl@0
   401
		return 0;
sl@0
   402
sl@0
   403
	return 1;
sl@0
   404
sl@0
   405
	}
sl@0
   406
sl@0
   407
/* Calculate the authority set based on policy tree.
sl@0
   408
 * The 'pnodes' parameter is used as a store for the set of policy nodes
sl@0
   409
 * used to calculate the user set. If the authority set is not anyPolicy
sl@0
   410
 * then pnodes will just point to the authority set. If however the authority
sl@0
   411
 * set is anyPolicy then the set of valid policies (other than anyPolicy)
sl@0
   412
 * is store in pnodes. The return value of '2' is used in this case to indicate
sl@0
   413
 * that pnodes should be freed.
sl@0
   414
 */
sl@0
   415
sl@0
   416
static int tree_calculate_authority_set(X509_POLICY_TREE *tree,
sl@0
   417
					STACK_OF(X509_POLICY_NODE) **pnodes)
sl@0
   418
	{
sl@0
   419
	X509_POLICY_LEVEL *curr;
sl@0
   420
	X509_POLICY_NODE *node, *anyptr;
sl@0
   421
	STACK_OF(X509_POLICY_NODE) **addnodes;
sl@0
   422
	int i, j;
sl@0
   423
	curr = tree->levels + tree->nlevel - 1;
sl@0
   424
sl@0
   425
	/* If last level contains anyPolicy set is anyPolicy */
sl@0
   426
	if (curr->anyPolicy)
sl@0
   427
		{
sl@0
   428
		if (!tree_add_auth_node(&tree->auth_policies, curr->anyPolicy))
sl@0
   429
			return 0;
sl@0
   430
		addnodes = pnodes;
sl@0
   431
		}
sl@0
   432
	else
sl@0
   433
		/* Add policies to authority set */
sl@0
   434
		addnodes = &tree->auth_policies;
sl@0
   435
sl@0
   436
	curr = tree->levels;
sl@0
   437
	for (i = 1; i < tree->nlevel; i++)
sl@0
   438
		{
sl@0
   439
		/* If no anyPolicy node on this this level it can't
sl@0
   440
		 * appear on lower levels so end search.
sl@0
   441
		 */
sl@0
   442
		if (!(anyptr = curr->anyPolicy))
sl@0
   443
			break;
sl@0
   444
		curr++;
sl@0
   445
		for (j = 0; j < sk_X509_POLICY_NODE_num(curr->nodes); j++)
sl@0
   446
			{
sl@0
   447
			node = sk_X509_POLICY_NODE_value(curr->nodes, j);
sl@0
   448
			if ((node->parent == anyptr)
sl@0
   449
				&& !tree_add_auth_node(addnodes, node))
sl@0
   450
					return 0;
sl@0
   451
			}
sl@0
   452
		}
sl@0
   453
sl@0
   454
	if (addnodes == pnodes)
sl@0
   455
		return 2;
sl@0
   456
sl@0
   457
	*pnodes = tree->auth_policies;
sl@0
   458
sl@0
   459
	return 1;
sl@0
   460
	}
sl@0
   461
sl@0
   462
static int tree_calculate_user_set(X509_POLICY_TREE *tree,
sl@0
   463
				STACK_OF(ASN1_OBJECT) *policy_oids,
sl@0
   464
				STACK_OF(X509_POLICY_NODE) *auth_nodes)
sl@0
   465
	{
sl@0
   466
	int i;
sl@0
   467
	X509_POLICY_NODE *node;
sl@0
   468
	ASN1_OBJECT *oid;
sl@0
   469
sl@0
   470
	X509_POLICY_NODE *anyPolicy;
sl@0
   471
	X509_POLICY_DATA *extra;
sl@0
   472
sl@0
   473
	/* Check if anyPolicy present in authority constrained policy set:
sl@0
   474
	 * this will happen if it is a leaf node.
sl@0
   475
	 */
sl@0
   476
sl@0
   477
	if (sk_ASN1_OBJECT_num(policy_oids) <= 0)
sl@0
   478
		return 1;
sl@0
   479
sl@0
   480
	anyPolicy = tree->levels[tree->nlevel - 1].anyPolicy;
sl@0
   481
sl@0
   482
	for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
sl@0
   483
		{
sl@0
   484
		oid = sk_ASN1_OBJECT_value(policy_oids, i);
sl@0
   485
		if (OBJ_obj2nid(oid) == NID_any_policy)
sl@0
   486
			{
sl@0
   487
			tree->flags |= POLICY_FLAG_ANY_POLICY;
sl@0
   488
			return 1;
sl@0
   489
			}
sl@0
   490
		}
sl@0
   491
sl@0
   492
	for (i = 0; i < sk_ASN1_OBJECT_num(policy_oids); i++)
sl@0
   493
		{
sl@0
   494
		oid = sk_ASN1_OBJECT_value(policy_oids, i);
sl@0
   495
		node = tree_find_sk(auth_nodes, oid);
sl@0
   496
		if (!node)
sl@0
   497
			{
sl@0
   498
			if (!anyPolicy)
sl@0
   499
				continue;
sl@0
   500
			/* Create a new node with policy ID from user set
sl@0
   501
			 * and qualifiers from anyPolicy.
sl@0
   502
			 */
sl@0
   503
			extra = policy_data_new(NULL, oid,
sl@0
   504
						node_critical(anyPolicy));
sl@0
   505
			if (!extra)
sl@0
   506
				return 0;
sl@0
   507
			extra->qualifier_set = anyPolicy->data->qualifier_set;
sl@0
   508
			extra->flags = POLICY_DATA_FLAG_SHARED_QUALIFIERS
sl@0
   509
						| POLICY_DATA_FLAG_EXTRA_NODE;
sl@0
   510
			node = level_add_node(NULL, extra, anyPolicy->parent,
sl@0
   511
						tree);
sl@0
   512
			}
sl@0
   513
		if (!tree->user_policies)
sl@0
   514
			{
sl@0
   515
			tree->user_policies = sk_X509_POLICY_NODE_new_null();
sl@0
   516
			if (!tree->user_policies)
sl@0
   517
				return 1;
sl@0
   518
			}
sl@0
   519
		if (!sk_X509_POLICY_NODE_push(tree->user_policies, node))
sl@0
   520
			return 0;
sl@0
   521
		}
sl@0
   522
	return 1;
sl@0
   523
sl@0
   524
	}
sl@0
   525
sl@0
   526
static int tree_evaluate(X509_POLICY_TREE *tree)
sl@0
   527
	{
sl@0
   528
	int ret, i;
sl@0
   529
	X509_POLICY_LEVEL *curr = tree->levels + 1;
sl@0
   530
	const X509_POLICY_CACHE *cache;
sl@0
   531
sl@0
   532
	for(i = 1; i < tree->nlevel; i++, curr++)
sl@0
   533
		{
sl@0
   534
		cache = policy_cache_set(curr->cert);
sl@0
   535
		if (!tree_link_nodes(curr, cache))
sl@0
   536
			return 0;
sl@0
   537
sl@0
   538
		if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
sl@0
   539
			&& !tree_link_any(curr, cache, tree))
sl@0
   540
			return 0;
sl@0
   541
		ret = tree_prune(tree, curr);
sl@0
   542
		if (ret != 1)
sl@0
   543
			return ret;
sl@0
   544
		}
sl@0
   545
sl@0
   546
	return 1;
sl@0
   547
sl@0
   548
	}
sl@0
   549
sl@0
   550
static void exnode_free(X509_POLICY_NODE *node)
sl@0
   551
	{
sl@0
   552
	if (node->data && (node->data->flags & POLICY_DATA_FLAG_EXTRA_NODE))
sl@0
   553
		OPENSSL_free(node);
sl@0
   554
	}
sl@0
   555
sl@0
   556
sl@0
   557
EXPORT_C void X509_policy_tree_free(X509_POLICY_TREE *tree)
sl@0
   558
	{
sl@0
   559
	X509_POLICY_LEVEL *curr;
sl@0
   560
	int i;
sl@0
   561
sl@0
   562
	if (!tree)
sl@0
   563
		return;
sl@0
   564
sl@0
   565
	sk_X509_POLICY_NODE_free(tree->auth_policies);
sl@0
   566
	sk_X509_POLICY_NODE_pop_free(tree->user_policies, exnode_free);
sl@0
   567
sl@0
   568
	for(i = 0, curr = tree->levels; i < tree->nlevel; i++, curr++)
sl@0
   569
		{
sl@0
   570
		if (curr->cert)
sl@0
   571
			X509_free(curr->cert);
sl@0
   572
		if (curr->nodes)
sl@0
   573
			sk_X509_POLICY_NODE_pop_free(curr->nodes,
sl@0
   574
						policy_node_free);
sl@0
   575
		if (curr->anyPolicy)
sl@0
   576
			policy_node_free(curr->anyPolicy);
sl@0
   577
		}
sl@0
   578
sl@0
   579
	if (tree->extra_data)
sl@0
   580
		sk_X509_POLICY_DATA_pop_free(tree->extra_data,
sl@0
   581
						policy_data_free);
sl@0
   582
sl@0
   583
	OPENSSL_free(tree->levels);
sl@0
   584
	OPENSSL_free(tree);
sl@0
   585
sl@0
   586
	}
sl@0
   587
sl@0
   588
/* Application policy checking function.
sl@0
   589
 * Return codes:
sl@0
   590
 *  0 	Internal Error.
sl@0
   591
 *  1   Successful.
sl@0
   592
 * -1   One or more certificates contain invalid or inconsistent extensions
sl@0
   593
 * -2	User constrained policy set empty and requireExplicit true.
sl@0
   594
 */
sl@0
   595
sl@0
   596
EXPORT_C int X509_policy_check(X509_POLICY_TREE **ptree, int *pexplicit_policy,
sl@0
   597
			STACK_OF(X509) *certs,
sl@0
   598
			STACK_OF(ASN1_OBJECT) *policy_oids,
sl@0
   599
			unsigned int flags)
sl@0
   600
	{
sl@0
   601
	int ret;
sl@0
   602
	X509_POLICY_TREE *tree = NULL;
sl@0
   603
	STACK_OF(X509_POLICY_NODE) *nodes, *auth_nodes = NULL;
sl@0
   604
	*ptree = NULL;
sl@0
   605
sl@0
   606
	*pexplicit_policy = 0;
sl@0
   607
	ret = tree_init(&tree, certs, flags);
sl@0
   608
sl@0
   609
sl@0
   610
	switch (ret)
sl@0
   611
		{
sl@0
   612
sl@0
   613
		/* Tree empty requireExplicit False: OK */
sl@0
   614
		case 2:
sl@0
   615
		return 1;
sl@0
   616
sl@0
   617
		/* Some internal error */
sl@0
   618
		case 0:
sl@0
   619
		return 0;
sl@0
   620
sl@0
   621
		/* Tree empty requireExplicit True: Error */
sl@0
   622
sl@0
   623
		case 6:
sl@0
   624
		*pexplicit_policy = 1;
sl@0
   625
		return -2;
sl@0
   626
sl@0
   627
		/* Tree OK requireExplicit True: OK and continue */
sl@0
   628
		case 5:
sl@0
   629
		*pexplicit_policy = 1;
sl@0
   630
		break;
sl@0
   631
sl@0
   632
		/* Tree OK: continue */
sl@0
   633
sl@0
   634
		case 1:
sl@0
   635
		if (!tree)
sl@0
   636
			/*
sl@0
   637
			 * tree_init() returns success and a null tree
sl@0
   638
			 * if it's just looking at a trust anchor.
sl@0
   639
			 * I'm not sure that returning success here is
sl@0
   640
			 * correct, but I'm sure that reporting this
sl@0
   641
			 * as an internal error which our caller
sl@0
   642
			 * interprets as a malloc failure is wrong.
sl@0
   643
			 */
sl@0
   644
			return 1;
sl@0
   645
		break;
sl@0
   646
		}
sl@0
   647
	if (!tree) goto error;
sl@0
   648
	ret = tree_evaluate(tree);
sl@0
   649
sl@0
   650
	if (ret <= 0)
sl@0
   651
		goto error;
sl@0
   652
sl@0
   653
	/* Return value 2 means tree empty */
sl@0
   654
	if (ret == 2)
sl@0
   655
		{
sl@0
   656
		X509_policy_tree_free(tree);
sl@0
   657
		if (*pexplicit_policy)
sl@0
   658
			return -2;
sl@0
   659
		else
sl@0
   660
			return 1;
sl@0
   661
		}
sl@0
   662
sl@0
   663
	/* Tree is not empty: continue */
sl@0
   664
sl@0
   665
	ret = tree_calculate_authority_set(tree, &auth_nodes);
sl@0
   666
sl@0
   667
	if (!ret)
sl@0
   668
		goto error;
sl@0
   669
sl@0
   670
	if (!tree_calculate_user_set(tree, policy_oids, auth_nodes))
sl@0
   671
		goto error;
sl@0
   672
	
sl@0
   673
	if (ret == 2)
sl@0
   674
		sk_X509_POLICY_NODE_free(auth_nodes);
sl@0
   675
sl@0
   676
	if (tree)
sl@0
   677
		*ptree = tree;
sl@0
   678
sl@0
   679
	if (*pexplicit_policy)
sl@0
   680
		{
sl@0
   681
		nodes = X509_policy_tree_get0_user_policies(tree);
sl@0
   682
		if (sk_X509_POLICY_NODE_num(nodes) <= 0)
sl@0
   683
			return -2;
sl@0
   684
		}
sl@0
   685
sl@0
   686
	return 1;
sl@0
   687
sl@0
   688
	error:
sl@0
   689
sl@0
   690
	X509_policy_tree_free(tree);
sl@0
   691
sl@0
   692
	return 0;
sl@0
   693
sl@0
   694
	}
sl@0
   695