Add verify callback functions to lookup a STACK of matching certs or CRLs
based on subject name.

New thread safe functions to retrieve matching STACK from X509_STORE.

Cache some IDP components.
diff --git a/crypto/asn1/x_crl.c b/crypto/asn1/x_crl.c
index 8943b84..f8ad1f3 100644
--- a/crypto/asn1/x_crl.c
+++ b/crypto/asn1/x_crl.c
@@ -64,6 +64,7 @@
 
 static int X509_REVOKED_cmp(const X509_REVOKED * const *a,
 				const X509_REVOKED * const *b);
+static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp);
 
 ASN1_SEQUENCE(X509_REVOKED) = {
 	ASN1_SIMPLE(X509_REVOKED,serialNumber, ASN1_INTEGER),
@@ -116,6 +117,8 @@
 		case ASN1_OP_NEW_POST:
 		crl->idp = NULL;
 		crl->akid = NULL;
+		crl->flags = 0;
+		crl->idp_flags = 0;
 		break;
 
 		case ASN1_OP_D2I_POST:
@@ -124,6 +127,9 @@
 #endif
 		crl->idp = X509_CRL_get_ext_d2i(crl,
 				NID_issuing_distribution_point, NULL, NULL);
+		if (crl->idp)
+			setup_idp(crl, crl->idp);
+
 		crl->akid = X509_CRL_get_ext_d2i(crl,
 				NID_authority_key_identifier, NULL, NULL);	
 		break;
@@ -138,6 +144,46 @@
 	return 1;
 	}
 
+/* Convert IDP into a more convenient form */
+
+static void setup_idp(X509_CRL *crl, ISSUING_DIST_POINT *idp)
+	{
+	int idp_only = 0;
+	/* Set various flags according to IDP */
+	crl->idp_flags |= IDP_PRESENT;
+	if (idp->onlyuser > 0)
+		{
+		idp_only++;
+		crl->idp_flags |= IDP_ONLYUSER;
+		}
+	if (idp->onlyCA > 0)
+		{
+		idp_only++;
+		crl->idp_flags |= IDP_ONLYCA;
+		}
+	if (idp->onlyattr > 0)
+		{
+		idp_only++;
+		crl->idp_flags |= IDP_ONLYATTR;
+		}
+
+	if (idp_only > 1)
+		crl->idp_flags |= IDP_INVALID;
+
+	if (idp->indirectCRL > 0)
+		crl->idp_flags |= IDP_INDIRECT;
+
+	if (idp->onlysomereasons)
+		{
+		crl->idp_flags |= IDP_REASONS;
+		if (idp->onlysomereasons->length > 0)
+			crl->idp_reasons = idp->onlysomereasons->data[0];
+		if (idp->onlysomereasons->length > 1)
+			crl->idp_reasons |=
+				(idp->onlysomereasons->data[1] << 8);
+		}
+	}
+
 ASN1_SEQUENCE_ref(X509_CRL, crl_cb, CRYPTO_LOCK_X509_CRL) = {
 	ASN1_SIMPLE(X509_CRL, crl, X509_CRL_INFO),
 	ASN1_SIMPLE(X509_CRL, sig_alg, X509_ALGOR),
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
index 31bc753..de93bf9 100644
--- a/crypto/x509/x509.h
+++ b/crypto/x509/x509.h
@@ -454,6 +454,9 @@
 	/* Copies of various extensions */
 	AUTHORITY_KEYID *akid;
 	ISSUING_DIST_POINT *idp;
+	/* Convenient breakdown of IDP */
+	int idp_flags;
+	int idp_reasons;
 #ifndef OPENSSL_NO_SHA
 	unsigned char sha1_hash[SHA_DIGEST_LENGTH];
 #endif
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index fbb1497..35a8e35 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -414,14 +414,15 @@
 		}
 	}
 
-int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
-	     X509_NAME *name)
+static int x509_object_idx_cnt(STACK_OF(X509_OBJECT) *h, int type,
+	     X509_NAME *name, int *pnmatch)
 	{
 	X509_OBJECT stmp;
 	X509 x509_s;
 	X509_CINF cinf_s;
 	X509_CRL crl_s;
 	X509_CRL_INFO crl_info_s;
+	int idx;
 
 	stmp.type=type;
 	switch (type)
@@ -441,7 +442,29 @@
 		return -1;
 		}
 
-	return sk_X509_OBJECT_find(h,&stmp);
+	idx = sk_X509_OBJECT_find(h,&stmp);
+	if (idx >= 0 && pnmatch)
+		{
+		int tidx;
+		const X509_OBJECT *tobj, *pstmp;
+		*pnmatch = 1;
+		pstmp = &stmp;
+		for (tidx = idx + 1; tidx < sk_X509_OBJECT_num(h); tidx++)
+			{
+			tobj = sk_X509_OBJECT_value(h, tidx);
+			if (!x509_object_cmp(&tobj, &pstmp))
+				break;
+			*pnmatch++;
+			}
+		}
+	return idx;
+	}
+
+
+int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
+	     X509_NAME *name)
+	{
+	return x509_object_idx_cnt(h, type, name, NULL);
 	}
 
 X509_OBJECT *X509_OBJECT_retrieve_by_subject(STACK_OF(X509_OBJECT) *h, int type,
@@ -453,6 +476,72 @@
 	return sk_X509_OBJECT_value(h, idx);
 }
 
+STACK_OF(X509)* X509_STORE_get_certs(X509_STORE *st, X509_NAME *nm)
+	{
+	int i, idx, cnt;
+	STACK_OF(X509) *sk;
+	X509 *x;
+	X509_OBJECT *obj;
+	sk = sk_X509_new_null();
+	CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
+	idx = x509_object_idx_cnt(st->objs, X509_LU_X509, nm, &cnt);
+	if (idx < 0)
+		{
+		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+		sk_X509_free(sk);
+		return NULL;
+		}
+	for (i = 0; i < cnt; i++, idx++)
+		{
+		obj = sk_X509_OBJECT_value(st->objs, i);
+		x = obj->data.x509;
+		CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
+		if (!sk_X509_push(sk, x))
+			{
+			CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+			X509_free(x);
+			sk_X509_pop_free(sk, X509_free);
+			return NULL;
+			}
+		}
+	CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+	return sk;
+
+	}
+
+STACK_OF(X509_CRL)* X509_STORE_get_crls(X509_STORE *st, X509_NAME *nm)
+	{
+	int i, idx, cnt;
+	STACK_OF(X509_CRL) *sk;
+	X509_CRL *x;
+	X509_OBJECT *obj;
+	sk = sk_X509_CRL_new_null();
+	CRYPTO_r_lock(CRYPTO_LOCK_X509_STORE);
+	idx = x509_object_idx_cnt(st->objs, X509_LU_CRL, nm, &cnt);
+	if (idx < 0)
+		{
+		CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+		sk_X509_CRL_free(sk);
+		return NULL;
+		}
+	for (i = 0; i < cnt; i++, idx++)
+		{
+		obj = sk_X509_OBJECT_value(st->objs, i);
+		x = obj->data.crl;
+		CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509_CRL);
+		if (!sk_X509_CRL_push(sk, x))
+			{
+			CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+			X509_CRL_free(x);
+			sk_X509_CRL_pop_free(sk, X509_CRL_free);
+			return NULL;
+			}
+		}
+	CRYPTO_r_unlock(CRYPTO_LOCK_X509_STORE);
+	return sk;
+
+	}
+
 X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x)
 {
 	int idx, i;
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index e2109a4..51db631 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -79,6 +79,8 @@
 static int check_cert(X509_STORE_CTX *ctx);
 static int check_policy(X509_STORE_CTX *ctx);
 static int internal_verify(X509_STORE_CTX *ctx);
+static STACK_OF(X509) * lookup_certs(X509_STORE_CTX *ctx, X509_NAME *nm);
+static STACK_OF(X509_CRL) * lookup_crls(X509_STORE_CTX *ctx, X509_NAME *nm);
 const char *X509_version="X.509" OPENSSL_VERSION_PTEXT;
 
 
@@ -669,7 +671,7 @@
 		if (check_crl_time(ctx, crl, 0))
 			{
 			*pcrl = crl;
-			CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509);
+			CRYPTO_add(&crl->references, 1, CRYPTO_LOCK_X509_CRL);
 			return 1;
 			}
 		best_crl = crl;
@@ -874,6 +876,16 @@
 	return 1;
 	}
 
+static STACK_OF(X509) * lookup_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
+	{
+	return X509_STORE_get_certs(ctx->ctx, nm);
+	}
+
+static STACK_OF(X509_CRL) * lookup_crls(X509_STORE_CTX *ctx, X509_NAME *nm)
+	{
+	return X509_STORE_get_crls(ctx->ctx, nm);
+	}
+
 static int check_policy(X509_STORE_CTX *ctx)
 	{
 	int ret;
@@ -1461,6 +1473,16 @@
 	else
 		ctx->cert_crl = cert_crl;
 
+	if (store && store->lookup_certs)
+		ctx->lookup_certs = store->lookup_certs;
+	else
+		ctx->lookup_certs = lookup_certs;
+
+	if (store && store->lookup_crls)
+		ctx->lookup_crls = store->lookup_crls;
+	else
+		ctx->lookup_crls = lookup_crls;
+
 	ctx->check_policy = check_policy;
 
 
diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h
index 3f16330..3c550e1 100644
--- a/crypto/x509/x509_vfy.h
+++ b/crypto/x509/x509_vfy.h
@@ -198,6 +198,8 @@
 	int (*get_crl)(X509_STORE_CTX *ctx, X509_CRL **crl, X509 *x); /* retrieve CRL */
 	int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
 	int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
+	STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
+	STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
 	int (*cleanup)(X509_STORE_CTX *ctx);
 
 	CRYPTO_EX_DATA ex_data;
@@ -246,6 +248,8 @@
 	int (*check_crl)(X509_STORE_CTX *ctx, X509_CRL *crl); /* Check CRL validity */
 	int (*cert_crl)(X509_STORE_CTX *ctx, X509_CRL *crl, X509 *x); /* Check certificate against CRL */
 	int (*check_policy)(X509_STORE_CTX *ctx);
+	STACK_OF(X509) * (*lookup_certs)(X509_STORE_CTX *ctx, X509_NAME *nm);
+	STACK_OF(X509_CRL) * (*lookup_crls)(X509_STORE_CTX *ctx, X509_NAME *nm);
 	int (*cleanup)(X509_STORE_CTX *ctx);
 
 	/* The following is built up */
@@ -383,6 +387,8 @@
 X509_STORE *X509_STORE_new(void );
 void X509_STORE_free(X509_STORE *v);
 
+STACK_OF(X509)* X509_STORE_get_certs(X509_STORE *st, X509_NAME *nm);
+STACK_OF(X509_CRL)* X509_STORE_get_crls(X509_STORE *st, X509_NAME *nm);
 int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
 int X509_STORE_set_purpose(X509_STORE *ctx, int purpose);
 int X509_STORE_set_trust(X509_STORE *ctx, int trust);
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
index 1e2f00a..da349e5 100644
--- a/crypto/x509v3/x509v3.h
+++ b/crypto/x509v3/x509v3.h
@@ -339,6 +339,22 @@
 	int onlyattr;
 	};
 
+/* Values in idp_flags field */
+/* IDP present */
+#define	IDP_PRESENT	0x1
+/* IDP values inconsistent */
+#define IDP_INVALID	0x2
+/* onlyuser true */
+#define	IDP_ONLYUSER	0x4
+/* onlyCA true */
+#define	IDP_ONLYCA	0x8
+/* onlyattr true */
+#define IDP_ONLYATTR	0x10
+/* indirectCRL true */
+#define IDP_INDIRECT	0x20
+/* onlysomereasons present */
+#define IDP_REASONS	0x40
+
 #define X509V3_conf_err(val) ERR_add_error_data(6, "section:", val->section, \
 ",name:", val->name, ",value:", val->value);