New options to the -verify program which can be used for chain verification.
Extend the X509_PURPOSE structure to include shortnames for purposed and default
trust ids.

Still need some extendable trust checking code and integration with the SSL and
S/MIME code.
diff --git a/CHANGES b/CHANGES
index 493f7e6..5aaed4a 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,15 +7,21 @@
   *) Very preliminary certificate chain verify code. Currently just tests
      the untrusted certificates for consistency with the verify purpose
      (which is set when the X509_STORE_CTX structure is set up) and checks
-     the pathlength. Totally untested at present: needs some extra
-     functionality in the verify program first. There is a
-     NO_CHAIN_VERIFY compilation option to keep the old behaviour: this is
-     because when it is finally working it will reject chains with
-     invalid extensions whereas before it made no checks at all.
+     the pathlength. There is a NO_CHAIN_VERIFY compilation option to keep
+     the old behaviour: this is because when it is finally working it will
+     reject chains with invalid extensions whereas before it made no checks
+     at all.
+
+     Still needs some trust checking code.
 
      Also added X509_STORE_CTX_new() and X509_STORE_CTX_free() functions
      which should be used for version portability: especially since the
      verify structure is likely to change more often now.
+
+     Two new options to the verify program: -untrusted allows a set of
+     untrusted certificates to be passed in and -purpose which sets the
+     intended purpose of the certificate. If a purpose is set then the
+     new chain verify code is used to check extension consistency.
      [Steve Henson]
 
   *) Support for the authority information access extension.
diff --git a/apps/Makefile.ssl b/apps/Makefile.ssl
index 747cd84..439f50d 100644
--- a/apps/Makefile.ssl
+++ b/apps/Makefile.ssl
@@ -727,11 +727,12 @@
 verify.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 verify.o: ../include/openssl/blowfish.h ../include/openssl/bn.h
 verify.o: ../include/openssl/buffer.h ../include/openssl/cast.h
-verify.o: ../include/openssl/crypto.h ../include/openssl/des.h
-verify.o: ../include/openssl/dh.h ../include/openssl/dsa.h
-verify.o: ../include/openssl/e_os.h ../include/openssl/e_os2.h
-verify.o: ../include/openssl/err.h ../include/openssl/evp.h
-verify.o: ../include/openssl/idea.h ../include/openssl/md2.h
+verify.o: ../include/openssl/conf.h ../include/openssl/crypto.h
+verify.o: ../include/openssl/des.h ../include/openssl/dh.h
+verify.o: ../include/openssl/dsa.h ../include/openssl/e_os.h
+verify.o: ../include/openssl/e_os2.h ../include/openssl/err.h
+verify.o: ../include/openssl/evp.h ../include/openssl/idea.h
+verify.o: ../include/openssl/lhash.h ../include/openssl/md2.h
 verify.o: ../include/openssl/md5.h ../include/openssl/mdc2.h
 verify.o: ../include/openssl/objects.h ../include/openssl/opensslconf.h
 verify.o: ../include/openssl/opensslv.h ../include/openssl/pem.h
@@ -740,8 +741,8 @@
 verify.o: ../include/openssl/rc5.h ../include/openssl/ripemd.h
 verify.o: ../include/openssl/rsa.h ../include/openssl/safestack.h
 verify.o: ../include/openssl/sha.h ../include/openssl/stack.h
-verify.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h apps.h
-verify.o: progs.h
+verify.o: ../include/openssl/x509.h ../include/openssl/x509_vfy.h
+verify.o: ../include/openssl/x509v3.h apps.h progs.h
 version.o: ../include/openssl/asn1.h ../include/openssl/bio.h
 version.o: ../include/openssl/blowfish.h ../include/openssl/bn.h
 version.o: ../include/openssl/buffer.h ../include/openssl/cast.h
diff --git a/apps/pkcs12.c b/apps/pkcs12.c
index 5523622..9fb290d 100644
--- a/apps/pkcs12.c
+++ b/apps/pkcs12.c
@@ -287,13 +287,14 @@
 	PKCS8_PRIV_KEY_INFO *p8;
 	PKCS7 *authsafe;
 	X509 *ucert = NULL;
-	STACK_OF(X509) *certs;
+	STACK_OF(X509) *certs=NULL;
 	char *catmp;
 	int i;
 	unsigned char keyid[EVP_MAX_MD_SIZE];
 	unsigned int keyidlen = 0;
 	key = PEM_read_bio_PrivateKey(inkey ? inkey : in, NULL, NULL, NULL);
 	if (!inkey) (void) BIO_reset(in);
+	else BIO_free(inkey);
 	if (!key) {
 		BIO_printf (bio_err, "Error loading private key\n");
 		ERR_print_errors(bio_err);
@@ -364,7 +365,7 @@
 				PKCS12_add_friendlyname(bag, catmp, -1);
 		sk_push(bags, (char *)bag);
 	}
-
+	sk_X509_pop_free(certs, X509_free);
 	if (canames) sk_free(canames);
 
 	if(!noprompt &&
diff --git a/apps/verify.c b/apps/verify.c
index 4166b92..579d4ea 100644
--- a/apps/verify.c
+++ b/apps/verify.c
@@ -63,22 +63,29 @@
 #include <openssl/bio.h>
 #include <openssl/err.h>
 #include <openssl/x509.h>
+#include <openssl/x509v3.h>
 #include <openssl/pem.h>
 
 #undef PROG
 #define PROG	verify_main
 
 static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx);
-static int check(X509_STORE *ctx,char *file);
+static int check(X509_STORE *ctx,char *file, STACK_OF(X509)*other, int purpose);
+static STACK_OF(X509) *load_untrusted(char *file);
 static int v_verbose=0;
 
 int MAIN(int argc, char **argv)
 	{
 	int i,ret=1;
+	int purpose = -1;
 	char *CApath=NULL,*CAfile=NULL;
+	char *untfile = NULL;
+	STACK_OF(X509) *untrusted = NULL;
 	X509_STORE *cert_ctx=NULL;
 	X509_LOOKUP *lookup=NULL;
 
+	X509_PURPOSE_add_standard();
+	X509V3_add_standard_extensions();
 	cert_ctx=X509_STORE_new();
 	if (cert_ctx == NULL) goto end;
 	X509_STORE_set_verify_cb_func(cert_ctx,cb);
@@ -107,6 +114,24 @@
 				if (argc-- < 1) goto end;
 				CAfile= *(++argv);
 				}
+			else if (strcmp(*argv,"-purpose") == 0)
+				{
+				X509_PURPOSE *xptmp;
+				if (argc-- < 1) goto end;
+				i = X509_PURPOSE_get_by_sname(*(++argv));
+				if(i < 0)
+					{
+					BIO_printf(bio_err, "unrecognised purpose\n");
+					goto end;
+					}
+				xptmp = X509_PURPOSE_iget(i);
+				purpose = X509_PURPOSE_get_id(xptmp);
+				}
+			else if (strcmp(*argv,"-untrusted") == 0)
+				{
+				if (argc-- < 1) goto end;
+				untfile= *(++argv);
+				}
 			else if (strcmp(*argv,"-help") == 0)
 				goto end;
 			else if (strcmp(*argv,"-verbose") == 0)
@@ -144,26 +169,45 @@
 		}
 	} else X509_LOOKUP_add_dir(lookup,NULL,X509_FILETYPE_DEFAULT);
 
-
 	ERR_clear_error();
-	if (argc < 1) check(cert_ctx,NULL);
+
+	if(untfile) {
+		if(!(untrusted = load_untrusted(untfile))) {
+			BIO_printf(bio_err, "Error loading untrusted file %s\n", untfile);
+			ERR_print_errors(bio_err);
+			goto end;
+		}
+	}
+
+	if (argc < 1) check(cert_ctx, NULL, untrusted, purpose);
 	else
 		for (i=0; i<argc; i++)
-			check(cert_ctx,argv[i]);
+			check(cert_ctx,argv[i], untrusted, purpose);
 	ret=0;
 end:
-	if (ret == 1)
+	if (ret == 1) {
 		BIO_printf(bio_err,"usage: verify [-verbose] [-CApath path] [-CAfile file] cert1 cert2 ...\n");
+		BIO_printf(bio_err,"recognised usages:\n");
+		for(i = 0; i < X509_PURPOSE_get_count(); i++) {
+			X509_PURPOSE *ptmp;
+			ptmp = X509_PURPOSE_iget(i);
+			BIO_printf(bio_err, "\t%-10s\t%s\n", X509_PURPOSE_iget_sname(ptmp),
+								X509_PURPOSE_iget_name(ptmp));
+		}
+	}
 	if (cert_ctx != NULL) X509_STORE_free(cert_ctx);
+	sk_X509_pop_free(untrusted, X509_free);
+	X509V3_EXT_cleanup();
+	X509_PURPOSE_cleanup();
 	EXIT(ret);
 	}
 
-static int check(X509_STORE *ctx, char *file)
+static int check(X509_STORE *ctx, char *file, STACK_OF(X509) *uchain, int purpose)
 	{
 	X509 *x=NULL;
 	BIO *in=NULL;
 	int i=0,ret=0;
-	X509_STORE_CTX csc;
+	X509_STORE_CTX *csc;
 
 	in=BIO_new(BIO_s_file());
 	if (in == NULL)
@@ -193,9 +237,16 @@
 		}
 	fprintf(stdout,"%s: ",(file == NULL)?"stdin":file);
 
-	X509_STORE_CTX_init(&csc,ctx,x,NULL);
-	i=X509_verify_cert(&csc);
-	X509_STORE_CTX_cleanup(&csc);
+	csc = X509_STORE_CTX_new();
+	if (csc == NULL)
+		{
+		ERR_print_errors(bio_err);
+		goto end;
+		}
+	X509_STORE_CTX_init(csc,ctx,x,uchain);
+	if(purpose >= 0) X509_STORE_CTX_chain_purpose(csc, purpose);
+	i=X509_verify_cert(csc);
+	X509_STORE_CTX_free(csc);
 
 	ret=0;
 end:
@@ -212,6 +263,52 @@
 	return(ret);
 	}
 
+static STACK_OF(X509) *load_untrusted(char *certfile)
+{
+	STACK_OF(X509_INFO) *sk=NULL;
+	STACK_OF(X509) *stack=NULL, *ret=NULL;
+	BIO *in=NULL;
+	X509_INFO *xi;
+
+	if(!(stack = sk_X509_new_null())) {
+		BIO_printf(bio_err,"memory allocation failure\n");
+		goto end;
+	}
+
+	if(!(in=BIO_new_file(certfile, "r"))) {
+		BIO_printf(bio_err,"error opening the file, %s\n",certfile);
+		goto end;
+	}
+
+	/* This loads from a file, a stack of x509/crl/pkey sets */
+	if(!(sk=PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) {
+		BIO_printf(bio_err,"error reading the file, %s\n",certfile);
+		goto end;
+	}
+
+	/* scan over it and pull out the certs */
+	while (sk_X509_INFO_num(sk))
+		{
+		xi=sk_X509_INFO_shift(sk);
+		if (xi->x509 != NULL)
+			{
+			sk_X509_push(stack,xi->x509);
+			xi->x509=NULL;
+			}
+		X509_INFO_free(xi);
+		}
+	if(!sk_X509_num(stack)) {
+		BIO_printf(bio_err,"no certificates in file, %s\n",certfile);
+		sk_X509_free(stack);
+		goto end;
+	}
+	ret=stack;
+end:
+	BIO_free(in);
+	sk_X509_INFO_free(sk);
+	return(ret);
+	}
+
 static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
 	{
 	char buf[256];
@@ -230,6 +327,11 @@
 		 * the user.
  		 */
 		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
+		/* Continue after extension errors too */
+		if (ctx->error == X509_V_ERR_INVALID_CA) ok=1;
+		if (ctx->error == X509_V_ERR_PATH_LENGTH_EXCEEDED) ok=1;
+		if (ctx->error == X509_V_ERR_INVALID_PURPOSE) ok=1;
+		if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
 		}
 	if (!v_verbose)
 		ERR_clear_error();
diff --git a/apps/x509.c b/apps/x509.c
index a6b5deb..6469761 100644
--- a/apps/x509.c
+++ b/apps/x509.c
@@ -136,14 +136,9 @@
 static int x509_certify (X509_STORE *ctx,char *CAfile,const EVP_MD *digest,
 			 X509 *x,X509 *xca,EVP_PKEY *pkey,char *serial,
 			 int create,int days, LHASH *conf, char *section);
-static int efunc(X509_PURPOSE *pt, void *arg);
+static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt);
 static int reqfile=0;
 
-typedef struct {
-BIO *bio;
-X509 *cert;
-} X509_PPRINT;
-
 int MAIN(int argc, char **argv)
 	{
 	int ret=1;
@@ -609,11 +604,14 @@
 				}
 			else if (pprint == i)
 				{
-				X509_PPRINT ptmp;
-				ptmp.bio = STDout;
-				ptmp.cert = x;
+				X509_PURPOSE *ptmp;
+				int j;
 				BIO_printf(STDout, "Certificate purposes:\n");
-				X509_PURPOSE_enum(efunc, &ptmp);
+				for(j = 0; j < X509_PURPOSE_get_count(); j++)
+					{
+					ptmp = X509_PURPOSE_iget(j);
+					purpose_print(STDout, x, ptmp);
+					}
 				}
 			else
 				if (modulus == i)
@@ -1227,20 +1225,18 @@
 	return(0);
 	}
 
-static int efunc(X509_PURPOSE *pt, void *arg)
+static int purpose_print(BIO *bio, X509 *cert, X509_PURPOSE *pt)
 {
-	X509_PPRINT *ptmp;
 	int id, i, idret;
 	char *pname;
-	ptmp = arg;
 	id = X509_PURPOSE_get_id(pt);
-	pname = X509_PURPOSE_get_name(pt);
+	pname = X509_PURPOSE_iget_name(pt);
 	for(i = 0; i < 2; i++) {
-		idret = X509_check_purpose(ptmp->cert, id, i);
-		BIO_printf(ptmp->bio, "%s%s : ", pname, i ? " CA" : ""); 
-		if(idret == 1) BIO_printf(ptmp->bio, "Yes\n");
-		else if (idret == 0) BIO_printf(ptmp->bio, "No\n");
-		else BIO_printf(ptmp->bio, "Yes (WARNING code=%d)\n", idret);
+		idret = X509_check_purpose(cert, id, i);
+		BIO_printf(bio, "%s%s : ", pname, i ? " CA" : ""); 
+		if(idret == 1) BIO_printf(bio, "Yes\n");
+		else if (idret == 0) BIO_printf(bio, "No\n");
+		else BIO_printf(bio, "Yes (WARNING code=%d)\n", idret);
 	}
 	return 1;
 }
diff --git a/crypto/asn1/t_x509a.c b/crypto/asn1/t_x509a.c
index 26d03f5..ebd62f6 100644
--- a/crypto/asn1/t_x509a.c
+++ b/crypto/asn1/t_x509a.c
@@ -66,11 +66,11 @@
  */
 
 static BIT_STRING_BITNAME tbits[] = {
-{X509_TRUST_ALL, "All Purposes", "all"},
-{X509_TRUST_SSL_CLIENT, "SSL client", "sslclient"},
-{X509_TRUST_SSL_SERVER, "SSL server", "sslserver"},
-{X509_TRUST_EMAIL, "S/MIME email", "email"},
-{X509_TRUST_OBJECT_SIGN, "Object Signing", "objsign"},
+{X509_TRUST_BIT_ALL, "All Purposes", "all"},
+{X509_TRUST_BIT_SSL_CLIENT, "SSL client", "sslclient"},
+{X509_TRUST_BIT_SSL_SERVER, "SSL server", "sslserver"},
+{X509_TRUST_BIT_EMAIL, "S/MIME email", "email"},
+{X509_TRUST_BIT_OBJECT_SIGN, "Object Signing", "objsign"},
 {-1, NULL, NULL}
 };
 
diff --git a/crypto/objects/obj_dat.h b/crypto/objects/obj_dat.h
index 89b134f..2272192 100644
--- a/crypto/objects/obj_dat.h
+++ b/crypto/objects/obj_dat.h
@@ -61,12 +61,12 @@
  * perl obj_dat.pl objects.h obj_dat.h
  */
 
-#define NUM_NID 180
+#define NUM_NID 181
 #define NUM_SN 128
-#define NUM_LN 174
-#define NUM_OBJ 151
+#define NUM_LN 175
+#define NUM_OBJ 152
 
-static unsigned char lvalues[1049]={
+static unsigned char lvalues[1057]={
 0x00,                                        /* [  0] OBJ_undef */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,               /* [  1] OBJ_rsadsi */
 0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,          /* [  7] OBJ_pkcs */
@@ -218,6 +218,7 @@
 0x2B,0x06,0x01,0x05,0x05,0x07,0x01,0x01,     /* [1024] OBJ_info_access */
 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x01,     /* [1032] OBJ_ad_OCSP */
 0x2B,0x06,0x01,0x05,0x05,0x07,0x30,0x02,     /* [1040] OBJ_ad_ca_issuers */
+0x2B,0x06,0x01,0x05,0x05,0x07,0x03,0x09,     /* [1048] OBJ_OCSP_sign */
 };
 
 static ASN1_OBJECT nid_objs[NUM_NID]={
@@ -471,6 +472,7 @@
 	8,&(lvalues[1024]),0},
 {"OCSP","OCSP",NID_ad_OCSP,8,&(lvalues[1032]),0},
 {"caIssuers","CA Issuers",NID_ad_ca_issuers,8,&(lvalues[1040]),0},
+{"OCSP Signing","OCSP Signing",NID_OCSP_sign,8,&(lvalues[1048]),0},
 };
 
 static ASN1_OBJECT *sn_objs[NUM_SN]={
@@ -631,6 +633,7 @@
 &(nid_objs[73]),/* "Netscape Revocation Url" */
 &(nid_objs[77]),/* "Netscape SSL Server Name" */
 &(nid_objs[139]),/* "Netscape Server Gated Crypto" */
+&(nid_objs[180]),/* "OCSP Signing" */
 &(nid_objs[178]),/* "OCSP" */
 &(nid_objs[161]),/* "PBES2" */
 &(nid_objs[69]),/* "PBKDF2" */
@@ -864,6 +867,7 @@
 &(nid_objs[131]),/* OBJ_code_sign                    1 3 6 1 5 5 7 3 3 */
 &(nid_objs[132]),/* OBJ_email_protect                1 3 6 1 5 5 7 3 4 */
 &(nid_objs[133]),/* OBJ_time_stamp                   1 3 6 1 5 5 7 3 8 */
+&(nid_objs[180]),/* OBJ_OCSP_sign                    1 3 6 1 5 5 7 3 9 */
 &(nid_objs[178]),/* OBJ_ad_OCSP                      1 3 6 1 5 5 7 48 1 */
 &(nid_objs[179]),/* OBJ_ad_ca_issuers                1 3 6 1 5 5 7 48 2 */
 &(nid_objs[58]),/* OBJ_netscape_cert_extension      2 16 840 1 113730 1 */
diff --git a/crypto/objects/objects.h b/crypto/objects/objects.h
index d7d1c53..ecdfd3e 100644
--- a/crypto/objects/objects.h
+++ b/crypto/objects/objects.h
@@ -935,6 +935,11 @@
 #define NID_ad_ca_issuers		179
 #define OBJ_ad_ca_issuers		OBJ_id_ad,2L
 
+#define SN_OSCP_sign			"OCSPSigning"
+#define LN_OCSP_sign			"OCSP Signing"
+#define NID_OCSP_sign			180
+#define OBJ_OCSP_sign			OBJ_id_kp,9L
+
 #include <openssl/bio.h>
 #include <openssl/asn1.h>
 
diff --git a/crypto/pem/pem.h b/crypto/pem/pem.h
index 9260a11..8ae1e9a 100644
--- a/crypto/pem/pem.h
+++ b/crypto/pem/pem.h
@@ -572,7 +572,7 @@
 
 DECLARE_PEM_rw_cb(PrivateKey, EVP_PKEY)
 
-DECLARE_PEM_rw(PUBKEY, EVP_PKEY);
+DECLARE_PEM_rw(PUBKEY, EVP_PKEY)
 
 int PEM_write_bio_PKCS8PrivateKey(BIO *, EVP_PKEY *, const EVP_CIPHER *,
                                   char *, int, pem_password_cb *, void *);
diff --git a/crypto/pem/pem_all.c b/crypto/pem/pem_all.c
index 93f5d7b..c6d8835 100644
--- a/crypto/pem/pem_all.c
+++ b/crypto/pem/pem_all.c
@@ -194,4 +194,4 @@
 IMPLEMENT_PEM_read(PrivateKey, EVP_PKEY, PEM_STRING_EVP_PKEY, PrivateKey)
 IMPLEMENT_PEM_write_cb(PrivateKey, EVP_PKEY, ((x->type == EVP_PKEY_DSA)?PEM_STRING_DSA:PEM_STRING_RSA), PrivateKey)
 
-IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY);
+IMPLEMENT_PEM_rw(PUBKEY, EVP_PKEY, PEM_STRING_PUBLIC, PUBKEY)
diff --git a/crypto/stack/stack.h b/crypto/stack/stack.h
index 0f825cc..a615d9b 100644
--- a/crypto/stack/stack.h
+++ b/crypto/stack/stack.h
@@ -76,8 +76,8 @@
 
 #define sk_new_null()	sk_new(NULL)
 
-#define M_sk_num(sk)		((sk)->num)
-#define M_sk_value(sk,n)	((sk)->data[n])
+#define M_sk_num(sk)		((sk) ? (sk)->num:-1)
+#define M_sk_value(sk,n)	((sk) ? (sk)->data[n] : NULL)
 
 int sk_num(STACK *);
 char *sk_value(STACK *, int);
diff --git a/crypto/x509/Makefile.ssl b/crypto/x509/Makefile.ssl
index 4fd06af..f29efba 100644
--- a/crypto/x509/Makefile.ssl
+++ b/crypto/x509/Makefile.ssl
@@ -332,21 +332,21 @@
 x509_vfy.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
 x509_vfy.o: ../../include/openssl/blowfish.h ../../include/openssl/bn.h
 x509_vfy.o: ../../include/openssl/buffer.h ../../include/openssl/cast.h
-x509_vfy.o: ../../include/openssl/crypto.h ../../include/openssl/des.h
-x509_vfy.o: ../../include/openssl/dh.h ../../include/openssl/dsa.h
-x509_vfy.o: ../../include/openssl/e_os.h ../../include/openssl/e_os2.h
-x509_vfy.o: ../../include/openssl/err.h ../../include/openssl/evp.h
-x509_vfy.o: ../../include/openssl/idea.h ../../include/openssl/lhash.h
-x509_vfy.o: ../../include/openssl/md2.h ../../include/openssl/md5.h
-x509_vfy.o: ../../include/openssl/mdc2.h ../../include/openssl/objects.h
-x509_vfy.o: ../../include/openssl/opensslconf.h
+x509_vfy.o: ../../include/openssl/conf.h ../../include/openssl/crypto.h
+x509_vfy.o: ../../include/openssl/des.h ../../include/openssl/dh.h
+x509_vfy.o: ../../include/openssl/dsa.h ../../include/openssl/e_os.h
+x509_vfy.o: ../../include/openssl/e_os2.h ../../include/openssl/err.h
+x509_vfy.o: ../../include/openssl/evp.h ../../include/openssl/idea.h
+x509_vfy.o: ../../include/openssl/lhash.h ../../include/openssl/md2.h
+x509_vfy.o: ../../include/openssl/md5.h ../../include/openssl/mdc2.h
+x509_vfy.o: ../../include/openssl/objects.h ../../include/openssl/opensslconf.h
 x509_vfy.o: ../../include/openssl/opensslv.h ../../include/openssl/pkcs7.h
 x509_vfy.o: ../../include/openssl/rc2.h ../../include/openssl/rc4.h
 x509_vfy.o: ../../include/openssl/rc5.h ../../include/openssl/ripemd.h
 x509_vfy.o: ../../include/openssl/rsa.h ../../include/openssl/safestack.h
 x509_vfy.o: ../../include/openssl/sha.h ../../include/openssl/stack.h
 x509_vfy.o: ../../include/openssl/x509.h ../../include/openssl/x509_vfy.h
-x509_vfy.o: ../cryptlib.h
+x509_vfy.o: ../../include/openssl/x509v3.h ../cryptlib.h
 x509name.o: ../../include/openssl/asn1.h ../../include/openssl/bio.h
 x509name.o: ../../include/openssl/blowfish.h ../../include/openssl/bn.h
 x509name.o: ../../include/openssl/buffer.h ../../include/openssl/cast.h
diff --git a/crypto/x509/x509.h b/crypto/x509/x509.h
index f35a614..ed08dfb 100644
--- a/crypto/x509/x509.h
+++ b/crypto/x509/x509.h
@@ -238,11 +238,12 @@
 
 /* Bit values for trust/notrust */
 
-#define X509_TRUST_ALL			0
-#define X509_TRUST_SSL_CLIENT		1
-#define X509_TRUST_SSL_SERVER		2
-#define X509_TRUST_EMAIL		3
-#define X509_TRUST_OBJECT_SIGN		4
+#define X509_TRUST_BIT_ALL			0
+#define X509_TRUST_BIT_SSL_CLIENT		1
+#define X509_TRUST_BIT_SSL_SERVER		2
+#define X509_TRUST_BIT_EMAIL			3
+#define X509_TRUST_BIT_OBJECT_SIGN		4
+
 
 typedef struct x509_cert_aux_st
 	{
@@ -276,6 +277,24 @@
 DECLARE_STACK_OF(X509)
 DECLARE_ASN1_SET_OF(X509)
 
+/* This is used for a table of trust checking functions */
+
+typedef struct x509_trust_st {
+	int trust_id;
+	int trust_flags;
+	int (*check_trust)(struct x509_trust_st *, X509 *, int);
+	char *trust_name;
+	int trust_bit;
+	void *usr_data;
+} X509_TRUST;
+
+/* X509 trust ids */
+
+#define X509_TRUST_ANY		1
+#define X509_TRUST_SSL_CLIENT	2
+#define X509_TRUST_SSL_SERVER	3
+#define X509_TRUST_EMAIL	4
+
 typedef struct X509_revoked_st
 	{
 	ASN1_INTEGER *serialNumber;
diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c
index 82e7fa5..837b81f 100644
--- a/crypto/x509/x509_lu.c
+++ b/crypto/x509/x509_lu.c
@@ -383,7 +383,10 @@
 
 X509_STORE_CTX *X509_STORE_CTX_new(void)
 {
-	return (X509_STORE_CTX *)Malloc(sizeof(X509_STORE_CTX));
+	X509_STORE_CTX *ctx;
+	ctx = (X509_STORE_CTX *)Malloc(sizeof(X509_STORE_CTX));
+	if(ctx) memset(ctx, 0, sizeof(X509_STORE_CTX));
+	return ctx;
 }
 
 void X509_STORE_CTX_free(X509_STORE_CTX *ctx)
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index 6ec5f95..13120ca 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -61,7 +61,6 @@
 #include <openssl/x509v3.h>
 
 
-static int x509_purpose_get_idx(int id);
 static void x509v3_cache_extensions(X509 *x);
 
 static int ca_check(X509 *x);
@@ -74,15 +73,16 @@
 static int check_purpose_crl_sign(X509_PURPOSE *xp, X509 *x, int ca);
 
 static int xp_cmp(X509_PURPOSE **a, X509_PURPOSE **b);
+static void xptable_free(X509_PURPOSE *p);
 
 static X509_PURPOSE xstandard[] = {
-	{1, 0, check_purpose_ssl_client, "SSL client", /* NULL */},
-	{2, 0, check_purpose_ssl_server, "SSL server", /* NULL */},
-	{3, 0, check_purpose_ns_ssl_server, "Netscape SSL server", /* NULL */},
-	{4, 0, check_purpose_smime_sign, "S/MIME signing", /* NULL */},
-	{5, 0, check_purpose_smime_encrypt, "S/MIME encryption", /* NULL */},
-	{6, 0, check_purpose_crl_sign, "CRL signing", /* NULL */},
-	{-1, 0, NULL, NULL, /* NULL */}
+	{X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL},
+	{X509_PURPOSE_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ssl_server, "SSL server", "sslserver", NULL},
+	{X509_PURPOSE_NS_SSL_SERVER, X509_TRUST_SSL_SERVER, 0, check_purpose_ns_ssl_server, "Netscape SSL server", "nssslserver", NULL},
+	{X509_PURPOSE_SMIME_SIGN, X509_TRUST_EMAIL, 0, check_purpose_smime_sign, "S/MIME signing", "smimesign", NULL},
+	{X509_PURPOSE_SMIME_ENCRYPT, X509_TRUST_EMAIL, 0, check_purpose_smime_encrypt, "S/MIME encryption", "smimeencrypt", NULL},
+	{X509_PURPOSE_CRL_SIGN, X509_TRUST_ANY, 0, check_purpose_crl_sign, "CRL signing", "crlsign", NULL},
+	{-1, 0, 0, NULL, NULL, NULL, NULL}
 };
 
 IMPLEMENT_STACK_OF(X509_PURPOSE)
@@ -104,16 +104,35 @@
 		CRYPTO_w_unlock(CRYPTO_LOCK_X509);
 	}
 	if(id == -1) return 1;
-	idx = x509_purpose_get_idx(id);
+	idx = X509_PURPOSE_get_by_id(id);
 	if(idx == -1) return -1;
 	pt = sk_X509_PURPOSE_value(xptable, idx);
 	return pt->check_purpose(pt, x,ca);
 }
 
+int X509_PURPOSE_get_count(void)
+{
+	return sk_X509_PURPOSE_num(xptable);
+}
+
+X509_PURPOSE * X509_PURPOSE_iget(int idx)
+{
+	return sk_X509_PURPOSE_value(xptable, idx);
+}
+
+int X509_PURPOSE_get_by_sname(char *sname)
+{
+	int i;
+	X509_PURPOSE *xptmp;
+	for(i = 0; i < sk_X509_PURPOSE_num(xptable); i++) {
+		xptmp = sk_X509_PURPOSE_value(xptable, i);
+		if(!strcmp(xptmp->purpose_sname, sname)) return i;
+	}
+	return -1;
+}
 
 
-
-static int x509_purpose_get_idx(int id)
+int X509_PURPOSE_get_by_id(int id)
 {
 	X509_PURPOSE tmp;
 	tmp.purpose_id = id;
@@ -134,24 +153,28 @@
 			}
 		}
 			
-	idx = x509_purpose_get_idx(xp->purpose_id);
-	if(idx != -1)
+	idx = X509_PURPOSE_get_by_id(xp->purpose_id);
+	if(idx != -1) {
+		xptable_free(sk_X509_PURPOSE_value(xptable, idx));
 		sk_X509_PURPOSE_set(xptable, idx, xp);
-	else
-		if (!sk_X509_PURPOSE_push(xptable, xp))
-			{
+	} else {
+		if (!sk_X509_PURPOSE_push(xptable, xp)) {
 			X509V3err(X509V3_F_X509_PURPOSE_ADD,ERR_R_MALLOC_FAILURE);
 			return 0;
-			}
+		}
+	}
 	return 1;
 }
 
 static void xptable_free(X509_PURPOSE *p)
 	{
+	if(!p) return;
 	if (p->purpose_flags & X509_PURPOSE_DYNAMIC) 
 		{
-		if (p->purpose_flags & X509_PURPOSE_DYNAMIC_NAME)
+		if (p->purpose_flags & X509_PURPOSE_DYNAMIC_NAME) {
 			Free(p->purpose_name);
+			Free(p->purpose_sname);
+		}
 		Free(p);
 		}
 	}
@@ -169,29 +192,26 @@
 		X509_PURPOSE_add(xp);
 }
 
-int X509_PURPOSE_enum(int (*efunc)(X509_PURPOSE *, void *), void *usr)
-{
-	int i;
-	X509_PURPOSE *xp;
-	if(!xptable) return 0;
-	for(i = 0; i < sk_X509_PURPOSE_num(xptable); i++) {
-		xp = sk_X509_PURPOSE_value(xptable, i);
-		if(!efunc(xp, usr)) return i;
-	}
-	return i;
-}
-
-
 int X509_PURPOSE_get_id(X509_PURPOSE *xp)
 {
 	return xp->purpose_id;
 }
 
-char *X509_PURPOSE_get_name(X509_PURPOSE *xp)
+char *X509_PURPOSE_iget_name(X509_PURPOSE *xp)
 {
 	return xp->purpose_name;
 }
 
+char *X509_PURPOSE_iget_sname(X509_PURPOSE *xp)
+{
+	return xp->purpose_sname;
+}
+
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
+{
+	return xp->trust_id;
+}
+
 static void x509v3_cache_extensions(X509 *x)
 {
 	BASIC_CONSTRAINTS *bs;
diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h
index 988cdb8..5a97e09 100644
--- a/crypto/x509v3/x509v3.h
+++ b/crypto/x509v3/x509v3.h
@@ -330,17 +330,23 @@
 
 typedef struct x509_purpose_st {
 	int purpose_id;
+	int trust_id;		/* Default trust ID */
 	int purpose_flags;
 	int (*check_purpose)(struct x509_purpose_st *, X509 *, int);
 	char *purpose_name;
-	/* void *usr_data; */ /* if we enable this it needs a free function */
+	char *purpose_sname;
+	void *usr_data;
 } X509_PURPOSE;
 
+#define X509_PURPOSE_SSL_CLIENT		1
+#define X509_PURPOSE_SSL_SERVER		2
+#define X509_PURPOSE_NS_SSL_SERVER	3
+#define X509_PURPOSE_SMIME_SIGN		4
+#define X509_PURPOSE_SMIME_ENCRYPT	5
+#define X509_PURPOSE_CRL_SIGN		6
+
 DECLARE_STACK_OF(X509_PURPOSE)
 
-
-
-
 void ERR_load_X509V3_strings(void);
 int i2d_BASIC_CONSTRAINTS(BASIC_CONSTRAINTS *a, unsigned char **pp);
 BASIC_CONSTRAINTS *d2i_BASIC_CONSTRAINTS(BASIC_CONSTRAINTS **a, unsigned char **pp, long length);
@@ -522,12 +528,17 @@
 int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
 
 int X509_check_purpose(X509 *x, int id, int ca);
+int X509_PURPOSE_get_count(void);
+X509_PURPOSE * X509_PURPOSE_iget(int idx);
+int X509_PURPOSE_get_by_sname(char *sname);
+int X509_PURPOSE_get_by_id(int id);
 int X509_PURPOSE_add(X509_PURPOSE *xp);
+char *X509_PURPOSE_iget_name(X509_PURPOSE *xp);
+char *X509_PURPOSE_iget_sname(X509_PURPOSE *xp);
+int X509_PURPOSE_get_trust(X509_PURPOSE *xp);
 void X509_PURPOSE_cleanup(void);
 void X509_PURPOSE_add_standard(void);
-int X509_PURPOSE_enum(int (*efunc)(X509_PURPOSE *, void *), void *usr);
 int X509_PURPOSE_get_id(X509_PURPOSE *);
-char * X509_PURPOSE_get_name(X509_PURPOSE *);
 
 /* BEGIN ERROR CODES */
 /* The following lines are auto generated by the script mkerr.pl. Any changes
diff --git a/util/libeay.num b/util/libeay.num
index 399165d..811f6ec 100755
--- a/util/libeay.num
+++ b/util/libeay.num
@@ -1914,7 +1914,7 @@
 DSA_set_default_method                  1939
 sk_X509_PURPOSE_set_cmp_func            1940
 PEM_write_bio_DSA_PUBKEY                1941
-X509_PURPOSE_get_id                     1942
+X509_PURPOSE_get_by_id                  1942
 DISPLAYTEXT_free                        1943
 X509V3_CRL_get_d2i                      1944
 ASN1_OCTET_STRING_free                  1945
@@ -1937,12 +1937,12 @@
 ASN1_UTCTIME_new                        1962
 ASN1_IA5STRING_free                     1963
 ASN1_STRING_data                        1964
-X509_PURPOSE_get_name                   1965
+X509_PURPOSE_iget_name                  1965
 sk_X509_PURPOSE_delete_ptr              1966
 ASN1_BIT_STRING_free                    1967
 X509_PURPOSE_add                        1968
 ASN1_UTF8STRING_free                    1969
-X509_PURPOSE_enum                       1970
+X509_PURPOSE_get                        1970
 sk_X509_PURPOSE_pop_free                1971
 i2d_DSA_PUBKEY_fp                       1972
 sk_X509_PURPOSE_free                    1973
@@ -2076,3 +2076,13 @@
 sk_ACCESS_DESCRIPTION_insert            2101
 sk_ACCESS_DESCRIPTION_sort              2102
 sk_ACCESS_DESCRIPTION_set_cmp_func      2103
+X509_STORE_CTX_chain_purpose            2104
+X509_STORE_CTX_free                     2105
+X509_STORE_CTX_trust_purpose            2106
+X509_STORE_CTX_new                      2107
+X509_PURPOSE_iget                       2108
+X509_PURPOSE_get_by_sname               2109
+X509_PURPOSE_get_id                     2110
+X509_PURPOSE_get_trust                  2111
+X509_PURPOSE_get_count                  2112
+X509_PURPOSE_iget_sname                 2113