Added restrictions on the use of proxy certificates, as they may pose
authorRichard Levitte <levitte@openssl.org>
Sat, 9 Apr 2005 16:07:12 +0000 (16:07 +0000)
committerRichard Levitte <levitte@openssl.org>
Sat, 9 Apr 2005 16:07:12 +0000 (16:07 +0000)
a security threat on unexpecting applications.  Document and test.

CHANGES
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vfy.h
crypto/x509v3/v3_purp.c
doc/HOWTO/proxy_certificates.txt
doc/standards.txt
ssl/ssltest.c
test/testsslproxy

diff --git a/CHANGES b/CHANGES
index 458843b1aad3102fa8ac2a4210e9ecd9b81e54fe..46db3be250be9ff776ed5c080d46f89e504e78ab 100644 (file)
--- a/CHANGES
+++ b/CHANGES
   *) 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
index 247e7e178ab6363ce1a59b3ffc5e63cdeb3e3382..7dd2b761d9ab3a18b17881bb34fadf39c186b73f 100644 (file)
@@ -128,6 +128,8 @@ const char *X509_verify_cert_error_string(long n)
                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:
index 431a620618debf144fcfd71b84086cb40aac3748..3da2490fea29934f4acb37e8355b31c7b48c3bd8 100644 (file)
@@ -391,6 +391,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
        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 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
               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 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
                        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)
                        {
index 33ace72671a8f7086f6dcd43a5f584a72cc42084..85bd6406bbcb68e8d79f5768715f8a524cc45809 100644 (file)
@@ -292,7 +292,7 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 #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 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 #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 @@ void X509_STORE_CTX_set_depth(X509_STORE_CTX *ctx, int depth);
 #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
 
index 9f992c9087598a7125b140252baa7714106e6417..1222c3ce5b13ac6f11dc3060f01a528b6235c3ec 100644 (file)
@@ -338,7 +338,9 @@ static void x509v3_cache_extensions(X509 *x)
        }
        /* 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) {
index fbb6e953b53f5f044e1efaa886fd7701bf5d3d32..3d36b02f6b318c0754d2cf567f889ddc5a9be09a 100644 (file)
@@ -22,7 +22,48 @@ name of the owner of the EE certificate.
 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 @@ section for it):
          -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 @@ This is some cookbook code for you to fill in:
 
     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)
index edbe2f3a57def88ec396efd4961a0533badbaccb..f6675b574b6f5e0217aea0f5a0e19380444bf939 100644 (file)
@@ -88,6 +88,10 @@ PKCS#12: Personal Information Exchange Syntax Standard, version 1.0.
      (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:
 --------
index e57a8e7540f8f968f263717478f4afe987276bd4..9e565fb8466ed4e1a4db08fc63ecf9a9cbe06ff8 100644 (file)
@@ -190,6 +190,7 @@ struct app_verify_arg
        {
        char *string;
        int app_verify;
+       int allow_proxy_certs;
        char *proxy_auth;
        char *proxy_cond;
        };
@@ -223,6 +224,7 @@ static void sv_usage(void)
        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 main(int argc, char *argv[])
        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 @@ int main(int argc, char *argv[])
                        {
                        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 @@ static int MS_CALLBACK verify_callback(int ok, X509_STORE_CTX *ctx)
                        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 @@ static int MS_CALLBACK app_verify_callback(X509_STORE_CTX *ctx, void *arg)
                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
index 70cf12342d39a82490e6a5cbb445819c83abdb23..58bbda8ab7d66f1e12725b3932473b776ca45e8c 100644 (file)
@@ -4,7 +4,7 @@ echo 'Testing a lot of proxy conditions.'
 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