Added restrictions on the use of proxy certificates, as they may pose
a security threat on unexpecting applications.  Document and test.
diff --git a/CHANGES b/CHANGES
index 458843b..46db3be 100644
--- a/CHANGES
+++ b/CHANGES
@@ -783,6 +783,12 @@
   *) Undo Cygwin change.
      [Ulf Möller]
 
+  *) Added support for proxy certificates according to RFC 3820.
+     Because they may be a security thread to unaware applications,
+     they must be explicitely allowed in run-time.  See
+     docs/HOWTO/proxy_certificates.txt for further information.
+     [Richard Levitte]
+
  Changes between 0.9.7e and 0.9.7f  [22 Mar 2005]
 
   *) Use (SSL_RANDOM_VALUE - 4) bytes of pseudo random data when generating
diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c
index 247e7e1..7dd2b76 100644
--- a/crypto/x509/x509_txt.c
+++ b/crypto/x509/x509_txt.c
@@ -128,6 +128,8 @@
 		return ("path length constraint exceeded");
 	case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
 		return("proxy path length constraint exceeded");
+	case X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED:
+		return("proxy cerificates not allowed, please set the appropriate flag");
 	case X509_V_ERR_INVALID_PURPOSE:
 		return ("unsupported certificate purpose");
 	case X509_V_ERR_CERT_UNTRUSTED:
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c
index 431a620..3da2490 100644
--- a/crypto/x509/x509_vfy.c
+++ b/crypto/x509/x509_vfy.c
@@ -391,6 +391,7 @@
 	int (*cb)(int ok,X509_STORE_CTX *ctx);
 	int proxy_path_length = 0;
 	cb=ctx->verify_cb;
+	int allow_proxy_certs = !!(ctx->flags & X509_V_FLAG_ALLOW_PROXY_CERTS);
 
 	/* must_be_ca can have 1 of 3 values:
 	   -1: we accept both CA and non-CA certificates, to allow direct
@@ -401,6 +402,12 @@
 	       all certificates in the chain except the leaf certificate.
 	*/
 	must_be_ca = -1;
+
+	/* A hack to keep people who don't want to modify their software
+	   happy */
+	if (getenv("OPENSSL_ALLOW_PROXY_CERTS"))
+		allow_proxy_certs = 1;
+
 	/* Check all untrusted certificates */
 	for (i = 0; i < ctx->last_untrusted; i++)
 		{
@@ -415,6 +422,14 @@
 			ok=cb(0,ctx);
 			if (!ok) goto end;
 			}
+		if (!allow_proxy_certs && (x->ex_flags & EXFLAG_PROXY))
+			{
+			ctx->error = X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED;
+			ctx->error_depth = i;
+			ctx->current_cert = x;
+			ok=cb(0,ctx);
+			if (!ok) goto end;
+			}
 		ret = X509_check_ca(x);
 		switch(must_be_ca)
 			{
diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h
index 33ace72..85bd640 100644
--- a/crypto/x509/x509_vfy.h
+++ b/crypto/x509/x509_vfy.h
@@ -292,7 +292,7 @@
 #define		X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY	6
 #define		X509_V_ERR_CERT_SIGNATURE_FAILURE		7
 #define		X509_V_ERR_CRL_SIGNATURE_FAILURE		8
-#define		X509_V_ERR_CERT_NOT_YET_VALID			9	
+#define		X509_V_ERR_CERT_NOT_YET_VALID			9
 #define		X509_V_ERR_CERT_HAS_EXPIRED			10
 #define		X509_V_ERR_CRL_NOT_YET_VALID			11
 #define		X509_V_ERR_CRL_HAS_EXPIRED			12
@@ -325,10 +325,11 @@
 #define		X509_V_ERR_INVALID_NON_CA			37
 #define		X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED		38
 #define		X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE	39
+#define		X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED	40
 
-#define		X509_V_ERR_INVALID_EXTENSION			40
-#define		X509_V_ERR_INVALID_POLICY_EXTENSION		41
-#define		X509_V_ERR_NO_EXPLICIT_POLICY			42
+#define		X509_V_ERR_INVALID_EXTENSION			41
+#define		X509_V_ERR_INVALID_POLICY_EXTENSION		42
+#define		X509_V_ERR_NO_EXPLICIT_POLICY			43
 
 
 /* The application is not happy */
@@ -348,14 +349,16 @@
 #define	X509_V_FLAG_IGNORE_CRITICAL		0x10
 /* Disable workarounds for broken certificates */
 #define	X509_V_FLAG_X509_STRICT			0x20
+/* Enable proxy certificate validation */
+#define	X509_V_FLAG_ALLOW_PROXY_CERTS		0x40
 /* Enable policy checking */
-#define X509_V_FLAG_POLICY_CHECK		0x40
+#define X509_V_FLAG_POLICY_CHECK		0x80
 /* Policy variable require-explicit-policy */
-#define X509_V_FLAG_EXPLICIT_POLICY		0x80
+#define X509_V_FLAG_EXPLICIT_POLICY		0x100
 /* Policy variable inhibit-any-policy */
-#define	X509_V_FLAG_INHIBIT_ANY			0x100
+#define	X509_V_FLAG_INHIBIT_ANY			0x200
 /* Policy variable inhibit-policy-mapping */
-#define X509_V_FLAG_INHIBIT_MAP			0x200
+#define X509_V_FLAG_INHIBIT_MAP			0x400
 /* Notify callback that policy is OK */
 #define X509_V_FLAG_NOTIFY_POLICY		0x800
 
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index 9f992c9..1222c3c 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -338,7 +338,9 @@
 	}
 	/* Handle proxy certificates */
 	if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
-		if (x->ex_flags & EXFLAG_CA) {
+		if (x->ex_flags & EXFLAG_CA
+		    || X509_get_ext_by_NID(x, NID_subject_alt_name, 0) >= 0
+		    || X509_get_ext_by_NID(x, NID_issuer_alt_name, 0) >= 0) {
 			x->ex_flags |= EXFLAG_INVALID;
 		}
 		if (pci->pcPathLengthConstraint) {
diff --git a/doc/HOWTO/proxy_certificates.txt b/doc/HOWTO/proxy_certificates.txt
index fbb6e95..3d36b02 100644
--- a/doc/HOWTO/proxy_certificates.txt
+++ b/doc/HOWTO/proxy_certificates.txt
@@ -22,7 +22,48 @@
 See http://www.ietf.org/rfc/rfc3820.txt for more information.
 
 
-2. How to create proxy cerificates
+2. A warning about proxy certificates
+
+Noone seems to have tested proxy certificates with security in mind.
+Basically, to this date, it seems that proxy certificates have only
+been used in a world that's highly aware of them.  What would happen
+if an unsuspecting application is to validate a chain of certificates
+that contains proxy certificates?  It would usually consider the leaf
+to be the certificate to check for authorisation data, and since proxy
+certificates are controlled by the EE certificate owner alone, it's
+would be normal to consider what the EE certificate owner could do
+with them.
+
+subjectAltName and issuerAltName are forbidden in proxy certificates,
+and this is enforced in OpenSSL.  The subject must be the same as the
+issuer, with one commonName added on.
+
+Possible threats are, as far as has been imagined so far:
+
+ - impersonation through commonName (think server certificates).
+ - use of additional extensions, possibly non-standard ones used in
+   certain environments, that would grant extra or different
+   authorisation rights.
+
+For this reason, OpenSSL requires that the use of proxy certificates
+be explicitely allowed.  Currently, this can be done using the
+following methods:
+
+ - if the application calls X509_verify_cert() itself, it can do the
+   following prior to that call (ctx is the pointer passed in the call
+   to X509_verify_cert()):
+
+	X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
+
+ - in all other cases, proxy certificate validation can be enabled
+   before starting the application by setting the envirnoment variable
+   OPENSSL_ALLOW_PROXY with some non-empty value.
+
+There are thoughts to allow proxy certificates with a line in the
+default openssl.cnf, but that's still in the future.
+
+
+3. How to create proxy cerificates
 
 It's quite easy to create proxy certificates, by taking advantage of
 the lack of checks of the 'openssl x509' application (*ahem*).  But
@@ -111,7 +152,7 @@
 	  -extfile openssl.cnf -extensions v3_proxy2
 
 
-3. How to have your application interpret the policy?
+4. How to have your application interpret the policy?
 
 The basic way to interpret proxy policies is to prepare some default
 rights, then do a check of the proxy certificate against the a chain
@@ -258,6 +299,7 @@
 
     X509_STORE_CTX_set_verify_cb(ctx, verify_callback);
     X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(), &rights);
+    X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
     ok = X509_verify_cert(ctx);
 
     if (ok == 1)
diff --git a/doc/standards.txt b/doc/standards.txt
index edbe2f3..f6675b5 100644
--- a/doc/standards.txt
+++ b/doc/standards.txt
@@ -88,6 +88,10 @@
      (Format: TXT=143173 bytes) (Obsoletes RFC2437) (Status:           
      INFORMATIONAL)                                         
 
+3820 Internet X.509 Public Key Infrastructure (PKI) Proxy Certificate
+     Profile. S. Tuecke, V. Welch, D. Engert, L. Pearlman, M. Thompson.
+     June 2004. (Format: TXT=86374 bytes) (Status: PROPOSED STANDARD)
+
 
 Related:
 --------
diff --git a/ssl/ssltest.c b/ssl/ssltest.c
index e57a8e7..9e565fb 100644
--- a/ssl/ssltest.c
+++ b/ssl/ssltest.c
@@ -190,6 +190,7 @@
 	{
 	char *string;
 	int app_verify;
+	int allow_proxy_certs;
 	char *proxy_auth;
 	char *proxy_cond;
 	};
@@ -223,6 +224,7 @@
 	fprintf(stderr,"\n");
 	fprintf(stderr," -server_auth  - check server certificate\n");
 	fprintf(stderr," -client_auth  - do client authentication\n");
+	fprintf(stderr," -proxy        - allow proxy certificates\n");
 	fprintf(stderr," -proxy_auth <val> - set proxy policy rights\n");
 	fprintf(stderr," -proxy_cond <val> - experssion to test proxy policy rights\n");
 	fprintf(stderr," -v            - more output\n");
@@ -383,7 +385,7 @@
 	int client_auth=0;
 	int server_auth=0,i;
 	struct app_verify_arg app_verify_arg =
-		{ APP_CALLBACK_STRING, 0, NULL, NULL };
+		{ APP_CALLBACK_STRING, 0, 0, NULL, NULL };
 	char *server_cert=TEST_SERVER_CERT;
 	char *server_key=NULL;
 	char *client_cert=TEST_CLIENT_CERT;
@@ -580,6 +582,10 @@
 			{
 			app_verify_arg.app_verify = 1;
 			}
+		else if	(strcmp(*argv,"-proxy") == 0)
+			{
+			app_verify_arg.allow_proxy_certs = 1;
+			}
 		else
 			{
 			fprintf(stderr,"unknown option %s\n",*argv);
@@ -1606,17 +1612,22 @@
 			fprintf(stderr,"depth=%d %s\n",
 				ctx->error_depth,buf);
 		else
+			{
 			fprintf(stderr,"depth=%d error=%d %s\n",
 				ctx->error_depth,ctx->error,buf);
+			}
 		}
 
 	if (ok == 0)
 		{
+		fprintf(stderr,"Error string: %s\n",
+			X509_verify_cert_error_string(ctx->error));
 		switch (ctx->error)
 			{
 		case X509_V_ERR_CERT_NOT_YET_VALID:
 		case X509_V_ERR_CERT_HAS_EXPIRED:
 		case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+			fprintf(stderr,"  ... ignored.\n");
 			ok=1;
 			}
 		}
@@ -2018,6 +2029,10 @@
 		X509_STORE_CTX_set_ex_data(ctx,
 			get_proxy_auth_ex_data_idx(),letters);
 		}
+	if (cb_arg->allow_proxy_certs)
+		{
+		X509_STORE_CTX_set_flags(ctx, X509_V_FLAG_ALLOW_PROXY_CERTS);
+		}
 
 #ifndef OPENSSL_NO_X509_VERIFY
 # ifdef OPENSSL_FIPS
diff --git a/test/testsslproxy b/test/testsslproxy
index 70cf123..58bbda8 100644
--- a/test/testsslproxy
+++ b/test/testsslproxy
@@ -4,7 +4,7 @@
 echo 'Some of them may turn out being invalid, which is fine.'
 for auth in A B C BC; do
     for cond in A B C 'A|B&!C'; do
-	sh ./testssl $1 $2 $3 "-proxy_auth $auth -proxy_cond $cond"
+	sh ./testssl $1 $2 $3 "-proxy -proxy_auth $auth -proxy_cond $cond"
 	if [ $? = 3 ]; then exit 1; fi
     done
 done