From d9bfe4f97cd4244beb0598cc348d68b04dac7068 Mon Sep 17 00:00:00 2001 From: Richard Levitte Date: Sat, 9 Apr 2005 16:07:12 +0000 Subject: [PATCH] Added restrictions on the use of proxy certificates, as they may pose a security threat on unexpecting applications. Document and test. --- CHANGES | 6 +++++ crypto/x509/x509_txt.c | 2 ++ crypto/x509/x509_vfy.c | 15 +++++++++++ crypto/x509/x509_vfy.h | 19 +++++++------ crypto/x509v3/v3_purp.c | 4 ++- doc/HOWTO/proxy_certificates.txt | 46 ++++++++++++++++++++++++++++++-- doc/standards.txt | 4 +++ ssl/ssltest.c | 17 +++++++++++- test/testsslproxy | 2 +- 9 files changed, 102 insertions(+), 13 deletions(-) diff --git a/CHANGES b/CHANGES index 458843b1aa..46db3be250 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 247e7e178a..7dd2b761d9 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -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: diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 431a620618..3da2490fea 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -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) { diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h index 33ace72671..85bd6406bb 100644 --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -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 diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 9f992c9087..1222c3ce5b 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -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) { diff --git a/doc/HOWTO/proxy_certificates.txt b/doc/HOWTO/proxy_certificates.txt index fbb6e953b5..3d36b02f6b 100644 --- a/doc/HOWTO/proxy_certificates.txt +++ b/doc/HOWTO/proxy_certificates.txt @@ -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) diff --git a/doc/standards.txt b/doc/standards.txt index edbe2f3a57..f6675b574b 100644 --- a/doc/standards.txt +++ b/doc/standards.txt @@ -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: -------- diff --git a/ssl/ssltest.c b/ssl/ssltest.c index e57a8e7540..9e565fb846 100644 --- a/ssl/ssltest.c +++ b/ssl/ssltest.c @@ -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 - set proxy policy rights\n"); fprintf(stderr," -proxy_cond - 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 diff --git a/test/testsslproxy b/test/testsslproxy index 70cf12342d..58bbda8ab7 100644 --- a/test/testsslproxy +++ b/test/testsslproxy @@ -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 -- 2.34.1