Support for policy mappings extension.

Delete X509_POLICY_REF code.

Fix handling of invalid policy extensions to return the correct error.

Add command line option to inhibit policy mappings.
diff --git a/CHANGES b/CHANGES
index 0d83a86..cede856 100644
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,11 @@
 
  Changes between 0.9.8i and 0.9.9  [xx XXX xxxx]
 
+  *) Add support for policy mappings extension.
+
+     This work was sponsored by Google.
+     [Steve Henson]
+
   *) Fixes to pathlength constraint, self issued certificate handling,
      policy processing to align with RFC3280 and PKITS tests.
 
diff --git a/apps/apps.c b/apps/apps.c
index 43eae05..1ef1b14 100644
--- a/apps/apps.c
+++ b/apps/apps.c
@@ -2235,6 +2235,8 @@
 		flags |= X509_V_FLAG_EXPLICIT_POLICY;
 	else if (!strcmp(arg, "-inhibit_any"))
 		flags |= X509_V_FLAG_INHIBIT_ANY;
+	else if (!strcmp(arg, "-inhibit_map"))
+		flags |= X509_V_FLAG_INHIBIT_MAP;
 	else if (!strcmp(arg, "-x509_strict"))
 		flags |= X509_V_FLAG_X509_STRICT;
 	else if (!strcmp(arg, "-policy_print"))
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index fe47dcb..05dcd8b 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -1122,7 +1122,8 @@
 				continue;
 			ctx->current_cert = x;
 			ctx->error = X509_V_ERR_INVALID_POLICY_EXTENSION;
-			ret = ctx->verify_cb(0, ctx);
+			if(!ctx->verify_cb(0, ctx))
+				return 0;
 			}
 		return 1;
 		}
diff --git a/crypto/x509v3/pcy_cache.c b/crypto/x509v3/pcy_cache.c
index c18beb8..78645c4 100644
--- a/crypto/x509v3/pcy_cache.c
+++ b/crypto/x509v3/pcy_cache.c
@@ -139,7 +139,6 @@
 		return 0;
 	cache->anyPolicy = NULL;
 	cache->data = NULL;
-	cache->maps = NULL;
 	cache->any_skip = -1;
 	cache->explicit_skip = -1;
 	cache->map_skip = -1;
diff --git a/crypto/x509v3/pcy_data.c b/crypto/x509v3/pcy_data.c
index 4711b1e..3d59f4d 100644
--- a/crypto/x509v3/pcy_data.c
+++ b/crypto/x509v3/pcy_data.c
@@ -82,17 +82,21 @@
  * another source.
  */
 
-X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, ASN1_OBJECT *id, int crit)
+X509_POLICY_DATA *policy_data_new(POLICYINFO *policy,
+					const ASN1_OBJECT *cid, int crit)
 	{
 	X509_POLICY_DATA *ret;
-	if (!policy && !id)
+	ASN1_OBJECT *id;
+	if (!policy && !cid)
 		return NULL;
-	if (id)
+	if (cid)
 		{
-		id = OBJ_dup(id);
+		id = OBJ_dup(cid);
 		if (!id)
 			return NULL;
 		}
+	else
+		id = NULL;
 	ret = OPENSSL_malloc(sizeof(X509_POLICY_DATA));
 	if (!ret)
 		return NULL;
diff --git a/crypto/x509v3/pcy_int.h b/crypto/x509v3/pcy_int.h
index 5d54549..e947f27 100644
--- a/crypto/x509v3/pcy_int.h
+++ b/crypto/x509v3/pcy_int.h
@@ -58,10 +58,8 @@
 
 
 typedef struct X509_POLICY_DATA_st X509_POLICY_DATA;
-typedef struct X509_POLICY_REF_st X509_POLICY_REF;
 
 DECLARE_STACK_OF(X509_POLICY_DATA)
-DECLARE_STACK_OF(X509_POLICY_REF)
 
 /* Internal structures */
 
@@ -110,16 +108,6 @@
 
 #define POLICY_DATA_FLAG_CRITICAL		0x10
 
-/* This structure is an entry from a table of mapped policies which
- * cross reference the policy it refers to.
- */
-
-struct X509_POLICY_REF_st
-	{
-	ASN1_OBJECT *subjectDomainPolicy;
-	const X509_POLICY_DATA *data;
-	};
-
 /* This structure is cached with a certificate */
 
 struct X509_POLICY_CACHE_st {
@@ -127,8 +115,6 @@
 	X509_POLICY_DATA *anyPolicy;
 	/* other policy data */
 	STACK_OF(X509_POLICY_DATA) *data;
-	/* If policyMappings extension present a table of mapped policies */
-	STACK_OF(X509_POLICY_REF) *maps;
 	/* If InhibitAnyPolicy present this is its value or -1 if absent. */
 	long any_skip;
 	/* If policyConstraints and requireExplicitPolicy present this is its
@@ -193,7 +179,7 @@
 
 /* Internal functions */
 
-X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, ASN1_OBJECT *id,
+X509_POLICY_DATA *policy_data_new(POLICYINFO *policy, const ASN1_OBJECT *id,
 								int crit);
 void policy_data_free(X509_POLICY_DATA *data);
 
@@ -209,15 +195,18 @@
 void policy_cache_free(X509_POLICY_CACHE *cache);
 
 X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
+					const X509_POLICY_NODE *parent,	
 					const ASN1_OBJECT *id);
 
 X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *sk,
 						const ASN1_OBJECT *id);
 
 X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
-			X509_POLICY_DATA *data,
+			const X509_POLICY_DATA *data,
 			X509_POLICY_NODE *parent,
 			X509_POLICY_TREE *tree);
 void policy_node_free(X509_POLICY_NODE *node);
+int policy_node_match(const X509_POLICY_LEVEL *lvl,
+		      const X509_POLICY_NODE *node, const ASN1_OBJECT *oid);
 
 const X509_POLICY_CACHE *policy_cache_set(X509 *x);
diff --git a/crypto/x509v3/pcy_map.c b/crypto/x509v3/pcy_map.c
index 35221e8..11dbe0a 100644
--- a/crypto/x509v3/pcy_map.c
+++ b/crypto/x509v3/pcy_map.c
@@ -62,31 +62,6 @@
 
 #include "pcy_int.h"
 
-static int ref_cmp(const X509_POLICY_REF * const *a,
-			const X509_POLICY_REF * const *b)
-	{
-	return OBJ_cmp((*a)->subjectDomainPolicy, (*b)->subjectDomainPolicy);
-	}
-
-static void policy_map_free(X509_POLICY_REF *map)
-	{
-	if (map->subjectDomainPolicy)
-		ASN1_OBJECT_free(map->subjectDomainPolicy);
-	OPENSSL_free(map);
-	}
-
-static X509_POLICY_REF *policy_map_find(X509_POLICY_CACHE *cache, ASN1_OBJECT *id)
-	{
-	X509_POLICY_REF tmp;
-	int idx;
-	tmp.subjectDomainPolicy = id;
-
-	idx = sk_X509_POLICY_REF_find(cache->maps, &tmp);
-	if (idx == -1)
-		return NULL;
-	return sk_X509_POLICY_REF_value(cache->maps, idx);
-	}
-
 /* Set policy mapping entries in cache.
  * Note: this modifies the passed POLICY_MAPPINGS structure
  */
@@ -94,7 +69,6 @@
 int policy_cache_set_mapping(X509 *x, POLICY_MAPPINGS *maps)
 	{
 	POLICY_MAPPING *map;
-	X509_POLICY_REF *ref = NULL;
 	X509_POLICY_DATA *data;
 	X509_POLICY_CACHE *cache = x->policy_cache;
 	int i;
@@ -104,7 +78,6 @@
 		ret = -1;
 		goto bad_mapping;
 		}
-	cache->maps = sk_X509_POLICY_REF_new(ref_cmp);
 	for (i = 0; i < sk_POLICY_MAPPING_num(maps); i++)
 		{
 		map = sk_POLICY_MAPPING_value(maps, i);
@@ -116,13 +89,6 @@
 			goto bad_mapping;
 			}
 
-		/* If we've already mapped from this OID bad mapping */
-		if (policy_map_find(cache, map->subjectDomainPolicy) != NULL)
-			{
-			ret = -1;
-			goto bad_mapping;
-			}
-
 		/* Attempt to find matching policy data */
 		data = policy_cache_find_data(cache, map->issuerDomainPolicy);
 		/* If we don't have anyPolicy can't map */
@@ -138,7 +104,7 @@
 			if (!data)
 				goto bad_mapping;
 			data->qualifier_set = cache->anyPolicy->qualifier_set;
-			map->issuerDomainPolicy = NULL;
+			/*map->issuerDomainPolicy = NULL;*/
 			data->flags |= POLICY_DATA_FLAG_MAPPED_ANY;
 			data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
 			if (!sk_X509_POLICY_DATA_push(cache->data, data))
@@ -149,23 +115,10 @@
 			}
 		else
 			data->flags |= POLICY_DATA_FLAG_MAPPED;
-
 		if (!sk_ASN1_OBJECT_push(data->expected_policy_set, 
 						map->subjectDomainPolicy))
 			goto bad_mapping;
-		
-		ref = OPENSSL_malloc(sizeof(X509_POLICY_REF));
-		if (!ref)
-			goto bad_mapping;
-
-		ref->subjectDomainPolicy = map->subjectDomainPolicy;
 		map->subjectDomainPolicy = NULL;
-		ref->data = data;
-
-		if (!sk_X509_POLICY_REF_push(cache->maps, ref))
-			goto bad_mapping;
-
-		ref = NULL;
 
 		}
 
@@ -173,13 +126,6 @@
 	bad_mapping:
 	if (ret == -1)
 		x->ex_flags |= EXFLAG_INVALID_POLICY;
-	if (ref)
-		policy_map_free(ref);
-	if (ret <= 0)
-		{
-		sk_X509_POLICY_REF_pop_free(cache->maps, policy_map_free);
-		cache->maps = NULL;
-		}
 	sk_POLICY_MAPPING_pop_free(maps, POLICY_MAPPING_free);
 	return ret;
 
diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c
index dcc1554..8e19986 100644
--- a/crypto/x509v3/pcy_node.c
+++ b/crypto/x509v3/pcy_node.c
@@ -92,13 +92,25 @@
 	}
 
 X509_POLICY_NODE *level_find_node(const X509_POLICY_LEVEL *level,
+					const X509_POLICY_NODE *parent,	
 					const ASN1_OBJECT *id)
 	{
-	return tree_find_sk(level->nodes, id);
+	X509_POLICY_NODE *node;
+	int i;
+	for (i = 0; i < sk_X509_POLICY_NODE_num(level->nodes); i++)
+		{
+		node = sk_X509_POLICY_NODE_value(level->nodes, i);
+		if (node->parent == parent)
+			{
+			if (!OBJ_cmp(node->data->valid_policy, id))
+				return node;
+			}
+		}
+	return NULL;
 	}
 
 X509_POLICY_NODE *level_add_node(X509_POLICY_LEVEL *level,
-			X509_POLICY_DATA *data,
+			const X509_POLICY_DATA *data,
 			X509_POLICY_NODE *parent,
 			X509_POLICY_TREE *tree)
 	{
@@ -155,4 +167,31 @@
 	OPENSSL_free(node);
 	}
 
+/* See if a policy node matches a policy OID. If mapping enabled look through
+ * expected policy set otherwise just valid policy.
+ */
 
+int policy_node_match(const X509_POLICY_LEVEL *lvl,
+		      const X509_POLICY_NODE *node, const ASN1_OBJECT *oid)
+	{
+	int i;
+	ASN1_OBJECT *policy_oid;
+	const X509_POLICY_DATA *x = node->data;
+
+	if (	    (lvl->flags & X509_V_FLAG_INHIBIT_MAP)
+		|| !(x->flags & POLICY_DATA_FLAG_MAP_MASK))
+		{
+		if (!OBJ_cmp(x->valid_policy, oid))
+			return 1;
+		return 0;
+		}
+
+	for (i = 0; i < sk_ASN1_OBJECT_num(x->expected_policy_set); i++)
+		{
+		policy_oid = sk_ASN1_OBJECT_value(x->expected_policy_set, i);
+		if (!OBJ_cmp(policy_oid, oid))
+			return 1;
+		}
+	return 0;
+
+	}
diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c
index b1ce77b..e48d6ea 100644
--- a/crypto/x509v3/pcy_tree.c
+++ b/crypto/x509v3/pcy_tree.c
@@ -62,6 +62,75 @@
 
 #include "pcy_int.h"
 
+/* Enable this to print out the complete policy tree at various point during
+ * evaluation.
+ */
+
+/*#define OPENSSL_POLICY_DEBUG*/
+
+#ifdef OPENSSL_POLICY_DEBUG
+
+static void expected_print(BIO *err, X509_POLICY_LEVEL *lev,
+				X509_POLICY_NODE *node, int indent)
+	{
+	if (	    (lev->flags & X509_V_FLAG_INHIBIT_MAP)
+		|| !(node->data->flags & POLICY_DATA_FLAG_MAP_MASK))
+		BIO_puts(err, "  Not Mapped\n");
+	else
+		{
+		int i;
+		STACK_OF(ASN1_OBJECT) *pset = node->data->expected_policy_set;
+		ASN1_OBJECT *oid;
+		BIO_puts(err, "  Expected: ");
+		for (i = 0; i < sk_ASN1_OBJECT_num(pset); i++)
+			{
+			oid = sk_ASN1_OBJECT_value(pset, i);
+			if (i)
+				BIO_puts(err, ", ");
+			i2a_ASN1_OBJECT(err, oid);
+			}
+		BIO_puts(err, "\n");
+		}
+	}
+
+static void tree_print(char *str, X509_POLICY_TREE *tree,
+			X509_POLICY_LEVEL *curr)
+	{
+	X509_POLICY_LEVEL *plev;
+	X509_POLICY_NODE *node;
+	int i;
+	BIO *err;
+	err = BIO_new_fp(stderr, BIO_NOCLOSE);
+	if (!curr)
+		curr = tree->levels + tree->nlevel;
+	else
+		curr++;
+	BIO_printf(err, "Level print after %s\n", str);
+	BIO_printf(err, "Printing Up to Level %ld\n", curr - tree->levels);
+	for (plev = tree->levels; plev != curr; plev++)
+		{
+		BIO_printf(err, "Level %ld, flags = %x\n",
+				plev - tree->levels, plev->flags);
+		for (i = 0; i < sk_X509_POLICY_NODE_num(plev->nodes); i++)
+			{
+			node = sk_X509_POLICY_NODE_value(plev->nodes, i);
+			X509_POLICY_NODE_print(err, node, 2);
+			expected_print(err, plev, node, 2);
+			BIO_printf(err, "  Flags: %x\n", node->data->flags);
+			}
+		if (plev->anyPolicy)
+			X509_POLICY_NODE_print(err, plev->anyPolicy, 2);
+		}
+
+	BIO_free(err);
+
+	}
+#else
+
+#define tree_print(a,b,c) /* */
+
+#endif
+
 /* Initialize policy tree. Return values:
  *  0 Some internal error occured.
  * -1 Inconsistent or invalid extensions in certificates.
@@ -87,8 +156,10 @@
 	*ptree = NULL;
 	n = sk_X509_num(certs);
 
+#if 0
 	/* Disable policy mapping for now... */
 	flags |= X509_V_FLAG_INHIBIT_MAP;
+#endif
 
 	if (flags & X509_V_FLAG_EXPLICIT_POLICY)
 		explicit_policy = 0;
@@ -184,7 +255,6 @@
 		level++;
 		x = sk_X509_value(certs, i);
 		cache = policy_cache_set(x);
-
 		CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
 		level->cert = x;
 
@@ -213,13 +283,13 @@
 			level->flags |= X509_V_FLAG_INHIBIT_MAP;
 		else
 			{
-			map_skip--;
+			if (!(x->ex_flags & EXFLAG_SI))
+				map_skip--;
 			if ((cache->map_skip >= 0)
 				&& (cache->map_skip < map_skip))
 				map_skip = cache->map_skip;
 			}
 
-
 		}
 
 	*ptree = tree;
@@ -237,7 +307,32 @@
 
 	}
 
-/* This corresponds to RFC3280 XXXX XXXXX:
+static int tree_link_matching_nodes(X509_POLICY_LEVEL *curr,
+				const X509_POLICY_DATA *data)
+	{
+	X509_POLICY_LEVEL *last = curr - 1;
+	X509_POLICY_NODE *node;
+	int i, matched = 0;
+	/* Iterate through all in nodes linking matches */
+	for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
+		{
+		node = sk_X509_POLICY_NODE_value(last->nodes, i);
+		if (policy_node_match(last, node, data->valid_policy))
+			{
+			if (!level_add_node(curr, data, node, NULL))
+				return 0;
+			matched = 1;
+			}
+		}
+	if (!matched && last->anyPolicy)
+		{
+		if (!level_add_node(curr, data, last->anyPolicy, NULL))
+			return 0;
+		}
+	return 1;
+	}
+
+/* This corresponds to RFC3280 6.1.3(d)(1):
  * link any data from CertificatePolicies onto matching parent
  * or anyPolicy if no match.
  */
@@ -248,7 +343,6 @@
 	int i;
 	X509_POLICY_LEVEL *last;
 	X509_POLICY_DATA *data;
-	X509_POLICY_NODE *parent;
 	last = curr - 1;
 	for (i = 0; i < sk_X509_POLICY_DATA_num(cache->data); i++)
 		{
@@ -261,40 +355,109 @@
 		 * link because then it will have the mapping flags
 		 * right and we can prune it later.
 		 */
+#if 0
 		if ((data->flags & POLICY_DATA_FLAG_MAPPED_ANY)
 			&& !(curr->flags & X509_V_FLAG_INHIBIT_ANY))
 			continue;
-		/* Look for matching node in parent */
-		parent = level_find_node(last, data->valid_policy);
-		/* If no match link to anyPolicy */
-		if (!parent)
-			parent = last->anyPolicy;
-		if (parent && !level_add_node(curr, data, parent, NULL))
+#endif
+		/* Look for matching nodes in previous level */
+		if (!tree_link_matching_nodes(curr, data))
 				return 0;
 		}
 	return 1;
 	}
 
-/* This corresponds to RFC3280 XXXX XXXXX:
+/* This corresponds to RFC3280 6.1.3(d)(2):
  * Create new data for any unmatched policies in the parent and link
  * to anyPolicy.
  */
 
+static int tree_add_unmatched(X509_POLICY_LEVEL *curr,
+			const X509_POLICY_CACHE *cache,
+			const ASN1_OBJECT *id,
+			X509_POLICY_NODE *node,
+			X509_POLICY_TREE *tree)
+	{
+	X509_POLICY_DATA *data;
+	if (id == NULL)
+		id = node->data->valid_policy;
+	/* Create a new node with qualifiers from anyPolicy and
+	 * id from unmatched node.
+	 */
+	data = policy_data_new(NULL, id, node_critical(node));
+
+	if (data == NULL)
+		return 0;
+	/* Curr may not have anyPolicy */
+	data->qualifier_set = cache->anyPolicy->qualifier_set;
+	data->flags |= POLICY_DATA_FLAG_SHARED_QUALIFIERS;
+	if (!level_add_node(curr, data, node, tree))
+		{
+		policy_data_free(data);
+		return 0;
+		}
+
+	return 1;
+	}
+
+static int tree_link_unmatched(X509_POLICY_LEVEL *curr,
+			const X509_POLICY_CACHE *cache,
+			X509_POLICY_NODE *node,
+			X509_POLICY_TREE *tree)
+	{
+	const X509_POLICY_LEVEL *last = curr - 1;
+	int i;
+
+	if (	    (last->flags & X509_V_FLAG_INHIBIT_MAP)
+		|| !(node->data->flags & POLICY_DATA_FLAG_MAPPED))
+		{
+		/* If no policy mapping: matched if one child present */
+		if (node->nchild)
+			return 1;
+		if (!tree_add_unmatched(curr, cache, NULL, node, tree))
+			return 0;
+		/* Add it */
+		}
+	else
+		{
+		/* If mapping: matched if one child per expected policy set */
+		STACK_OF(ASN1_OBJECT) *expset = node->data->expected_policy_set;
+		if (node->nchild == sk_ASN1_OBJECT_num(expset))
+			return 1;
+		/* Locate unmatched nodes */
+		for (i = 0; i < sk_ASN1_OBJECT_num(expset); i++)
+			{
+			ASN1_OBJECT *oid = sk_ASN1_OBJECT_value(expset, i);
+			if (level_find_node(curr, node, oid))
+				continue;
+			if (!tree_add_unmatched(curr, cache, oid, node, tree))
+				return 0;
+			}
+
+		}
+
+	return 1;
+
+	}
+
 static int tree_link_any(X509_POLICY_LEVEL *curr,
 			const X509_POLICY_CACHE *cache,
 			X509_POLICY_TREE *tree)
 	{
 	int i;
-	X509_POLICY_DATA *data;
+	/*X509_POLICY_DATA *data;*/
 	X509_POLICY_NODE *node;
-	X509_POLICY_LEVEL *last;
-
-	last = curr - 1;
+	X509_POLICY_LEVEL *last = curr - 1;
 
 	for (i = 0; i < sk_X509_POLICY_NODE_num(last->nodes); i++)
 		{
 		node = sk_X509_POLICY_NODE_value(last->nodes, i);
 
+		if (!tree_link_unmatched(curr, cache, node, tree))
+			return 0;
+
+#if 0
+
 		/* Skip any node with any children: we only want unmathced
 		 * nodes.
 		 *
@@ -303,6 +466,7 @@
 		 */
 		if (node->nchild)
 			continue;
+
 		/* Create a new node with qualifiers from anyPolicy and
 		 * id from unmatched node.
 		 */
@@ -319,6 +483,9 @@
 			policy_data_free(data);
 			return 0;
 			}
+
+#endif
+
 		}
 	/* Finally add link to anyPolicy */
 	if (last->anyPolicy)
@@ -337,30 +504,36 @@
 
 static int tree_prune(X509_POLICY_TREE *tree, X509_POLICY_LEVEL *curr)
 	{
+	STACK_OF(X509_POLICY_NODE) *nodes;
 	X509_POLICY_NODE *node;
 	int i;
-	for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
+	nodes = curr->nodes;
+	if (curr->flags & X509_V_FLAG_INHIBIT_MAP)
 		{
-		node = sk_X509_POLICY_NODE_value(curr->nodes, i);
-		/* Delete any mapped data: see RFC3280 XXXX */
-		if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
+		for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--)
 			{
-			node->parent->nchild--;
-			OPENSSL_free(node);
-			(void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
+			node = sk_X509_POLICY_NODE_value(nodes, i);
+			/* Delete any mapped data: see RFC3280 XXXX */
+			if (node->data->flags & POLICY_DATA_FLAG_MAP_MASK)
+				{
+				node->parent->nchild--;
+				OPENSSL_free(node);
+				(void)sk_X509_POLICY_NODE_delete(nodes,i);
+				}
 			}
 		}
 
 	for(;;)	{
 		--curr;
-		for (i = sk_X509_POLICY_NODE_num(curr->nodes) - 1; i >= 0; i--)
+		nodes = curr->nodes;
+		for (i = sk_X509_POLICY_NODE_num(nodes) - 1; i >= 0; i--)
 			{
-			node = sk_X509_POLICY_NODE_value(curr->nodes, i);
+			node = sk_X509_POLICY_NODE_value(nodes, i);
 			if (node->nchild == 0)
 				{
 				node->parent->nchild--;
 				OPENSSL_free(node);
-				(void)sk_X509_POLICY_NODE_delete(curr->nodes, i);
+				(void)sk_X509_POLICY_NODE_delete(nodes, i);
 				}
 			}
 		if (curr->anyPolicy && !curr->anyPolicy->nchild)
@@ -536,6 +709,7 @@
 		if (!(curr->flags & X509_V_FLAG_INHIBIT_ANY)
 			&& !tree_link_any(curr, cache, tree))
 			return 0;
+	tree_print("before tree_prune()", tree, curr);
 		ret = tree_prune(tree, curr);
 		if (ret != 1)
 			return ret;
@@ -604,7 +778,6 @@
 	*pexplicit_policy = 0;
 	ret = tree_init(&tree, certs, flags);
 
-
 	switch (ret)
 		{
 
@@ -613,6 +786,10 @@
 		return 1;
 
 		/* Some internal error */
+		case -1:
+		return -1;
+
+		/* Some internal error */
 		case 0:
 		return 0;
 
@@ -646,6 +823,8 @@
 	if (!tree) goto error;
 	ret = tree_evaluate(tree);
 
+	tree_print("tree_evaluate()", tree, NULL);
+
 	if (ret <= 0)
 		goto error;
 
diff --git a/crypto/x509v3/v3_cpols.c b/crypto/x509v3/v3_cpols.c
index a40f490..441ccea 100644
--- a/crypto/x509v3/v3_cpols.c
+++ b/crypto/x509v3/v3_cpols.c
@@ -446,4 +446,4 @@
 	else
 		BIO_printf(out, "%*sNo Qualifiers\n", indent + 2, "");
 	}
-	
+
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index 7bb6658..bdf7222 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -296,6 +296,7 @@
 		NID_policy_constraints,	/* 401 */
 		NID_proxyCertInfo,	/* 663 */
 		NID_name_constraints,	/* 666 */
+		NID_policy_mappings,	/* 747 */
 		NID_inhibit_any_policy	/* 748 */
 	};