Added restrictions on the use of proxy certificates, as they may pose
a security threat on unexpecting applications. Document and test.
This commit is contained in:
parent
dc0ed30cfe
commit
d9bfe4f97c
6
CHANGES
6
CHANGES
@ -783,6 +783,12 @@
|
|||||||
*) Undo Cygwin change.
|
*) Undo Cygwin change.
|
||||||
[Ulf Möller]
|
[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]
|
Changes between 0.9.7e and 0.9.7f [22 Mar 2005]
|
||||||
|
|
||||||
*) Use (SSL_RANDOM_VALUE - 4) bytes of pseudo random data when generating
|
*) Use (SSL_RANDOM_VALUE - 4) bytes of pseudo random data when generating
|
||||||
|
@ -128,6 +128,8 @@ const char *X509_verify_cert_error_string(long n)
|
|||||||
return ("path length constraint exceeded");
|
return ("path length constraint exceeded");
|
||||||
case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
|
case X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED:
|
||||||
return("proxy path length constraint 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:
|
case X509_V_ERR_INVALID_PURPOSE:
|
||||||
return ("unsupported certificate purpose");
|
return ("unsupported certificate purpose");
|
||||||
case X509_V_ERR_CERT_UNTRUSTED:
|
case X509_V_ERR_CERT_UNTRUSTED:
|
||||||
|
@ -391,6 +391,7 @@ static int check_chain_extensions(X509_STORE_CTX *ctx)
|
|||||||
int (*cb)(int ok,X509_STORE_CTX *ctx);
|
int (*cb)(int ok,X509_STORE_CTX *ctx);
|
||||||
int proxy_path_length = 0;
|
int proxy_path_length = 0;
|
||||||
cb=ctx->verify_cb;
|
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:
|
/* must_be_ca can have 1 of 3 values:
|
||||||
-1: we accept both CA and non-CA certificates, to allow direct
|
-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.
|
all certificates in the chain except the leaf certificate.
|
||||||
*/
|
*/
|
||||||
must_be_ca = -1;
|
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 */
|
/* Check all untrusted certificates */
|
||||||
for (i = 0; i < ctx->last_untrusted; i++)
|
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);
|
ok=cb(0,ctx);
|
||||||
if (!ok) goto end;
|
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);
|
ret = X509_check_ca(x);
|
||||||
switch(must_be_ca)
|
switch(must_be_ca)
|
||||||
{
|
{
|
||||||
|
@ -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_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6
|
||||||
#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
|
#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7
|
||||||
#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8
|
#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_CERT_HAS_EXPIRED 10
|
||||||
#define X509_V_ERR_CRL_NOT_YET_VALID 11
|
#define X509_V_ERR_CRL_NOT_YET_VALID 11
|
||||||
#define X509_V_ERR_CRL_HAS_EXPIRED 12
|
#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_INVALID_NON_CA 37
|
||||||
#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
|
#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38
|
||||||
#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39
|
#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_EXTENSION 41
|
||||||
#define X509_V_ERR_INVALID_POLICY_EXTENSION 41
|
#define X509_V_ERR_INVALID_POLICY_EXTENSION 42
|
||||||
#define X509_V_ERR_NO_EXPLICIT_POLICY 42
|
#define X509_V_ERR_NO_EXPLICIT_POLICY 43
|
||||||
|
|
||||||
|
|
||||||
/* The application is not happy */
|
/* 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
|
#define X509_V_FLAG_IGNORE_CRITICAL 0x10
|
||||||
/* Disable workarounds for broken certificates */
|
/* Disable workarounds for broken certificates */
|
||||||
#define X509_V_FLAG_X509_STRICT 0x20
|
#define X509_V_FLAG_X509_STRICT 0x20
|
||||||
|
/* Enable proxy certificate validation */
|
||||||
|
#define X509_V_FLAG_ALLOW_PROXY_CERTS 0x40
|
||||||
/* Enable policy checking */
|
/* Enable policy checking */
|
||||||
#define X509_V_FLAG_POLICY_CHECK 0x40
|
#define X509_V_FLAG_POLICY_CHECK 0x80
|
||||||
/* Policy variable require-explicit-policy */
|
/* Policy variable require-explicit-policy */
|
||||||
#define X509_V_FLAG_EXPLICIT_POLICY 0x80
|
#define X509_V_FLAG_EXPLICIT_POLICY 0x100
|
||||||
/* Policy variable inhibit-any-policy */
|
/* Policy variable inhibit-any-policy */
|
||||||
#define X509_V_FLAG_INHIBIT_ANY 0x100
|
#define X509_V_FLAG_INHIBIT_ANY 0x200
|
||||||
/* Policy variable inhibit-policy-mapping */
|
/* 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 */
|
/* Notify callback that policy is OK */
|
||||||
#define X509_V_FLAG_NOTIFY_POLICY 0x800
|
#define X509_V_FLAG_NOTIFY_POLICY 0x800
|
||||||
|
|
||||||
|
@ -338,7 +338,9 @@ static void x509v3_cache_extensions(X509 *x)
|
|||||||
}
|
}
|
||||||
/* Handle proxy certificates */
|
/* Handle proxy certificates */
|
||||||
if((pci=X509_get_ext_d2i(x, NID_proxyCertInfo, NULL, NULL))) {
|
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;
|
x->ex_flags |= EXFLAG_INVALID;
|
||||||
}
|
}
|
||||||
if (pci->pcPathLengthConstraint) {
|
if (pci->pcPathLengthConstraint) {
|
||||||
|
@ -22,7 +22,48 @@ name of the owner of the EE certificate.
|
|||||||
See http://www.ietf.org/rfc/rfc3820.txt for more information.
|
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
|
It's quite easy to create proxy certificates, by taking advantage of
|
||||||
the lack of checks of the 'openssl x509' application (*ahem*). But
|
the lack of checks of the 'openssl x509' application (*ahem*). But
|
||||||
@ -111,7 +152,7 @@ section for it):
|
|||||||
-extfile openssl.cnf -extensions v3_proxy2
|
-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
|
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
|
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_verify_cb(ctx, verify_callback);
|
||||||
X509_STORE_CTX_set_ex_data(ctx, get_proxy_auth_ex_data_idx(), &rights);
|
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);
|
ok = X509_verify_cert(ctx);
|
||||||
|
|
||||||
if (ok == 1)
|
if (ok == 1)
|
||||||
|
@ -88,6 +88,10 @@ PKCS#12: Personal Information Exchange Syntax Standard, version 1.0.
|
|||||||
(Format: TXT=143173 bytes) (Obsoletes RFC2437) (Status:
|
(Format: TXT=143173 bytes) (Obsoletes RFC2437) (Status:
|
||||||
INFORMATIONAL)
|
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:
|
Related:
|
||||||
--------
|
--------
|
||||||
|
@ -190,6 +190,7 @@ struct app_verify_arg
|
|||||||
{
|
{
|
||||||
char *string;
|
char *string;
|
||||||
int app_verify;
|
int app_verify;
|
||||||
|
int allow_proxy_certs;
|
||||||
char *proxy_auth;
|
char *proxy_auth;
|
||||||
char *proxy_cond;
|
char *proxy_cond;
|
||||||
};
|
};
|
||||||
@ -223,6 +224,7 @@ static void sv_usage(void)
|
|||||||
fprintf(stderr,"\n");
|
fprintf(stderr,"\n");
|
||||||
fprintf(stderr," -server_auth - check server certificate\n");
|
fprintf(stderr," -server_auth - check server certificate\n");
|
||||||
fprintf(stderr," -client_auth - do client authentication\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_auth <val> - set proxy policy rights\n");
|
||||||
fprintf(stderr," -proxy_cond <val> - experssion to test proxy policy rights\n");
|
fprintf(stderr," -proxy_cond <val> - experssion to test proxy policy rights\n");
|
||||||
fprintf(stderr," -v - more output\n");
|
fprintf(stderr," -v - more output\n");
|
||||||
@ -383,7 +385,7 @@ int main(int argc, char *argv[])
|
|||||||
int client_auth=0;
|
int client_auth=0;
|
||||||
int server_auth=0,i;
|
int server_auth=0,i;
|
||||||
struct app_verify_arg app_verify_arg =
|
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_cert=TEST_SERVER_CERT;
|
||||||
char *server_key=NULL;
|
char *server_key=NULL;
|
||||||
char *client_cert=TEST_CLIENT_CERT;
|
char *client_cert=TEST_CLIENT_CERT;
|
||||||
@ -580,6 +582,10 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
app_verify_arg.app_verify = 1;
|
app_verify_arg.app_verify = 1;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(*argv,"-proxy") == 0)
|
||||||
|
{
|
||||||
|
app_verify_arg.allow_proxy_certs = 1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr,"unknown option %s\n",*argv);
|
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",
|
fprintf(stderr,"depth=%d %s\n",
|
||||||
ctx->error_depth,buf);
|
ctx->error_depth,buf);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
fprintf(stderr,"depth=%d error=%d %s\n",
|
fprintf(stderr,"depth=%d error=%d %s\n",
|
||||||
ctx->error_depth,ctx->error,buf);
|
ctx->error_depth,ctx->error,buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok == 0)
|
if (ok == 0)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr,"Error string: %s\n",
|
||||||
|
X509_verify_cert_error_string(ctx->error));
|
||||||
switch (ctx->error)
|
switch (ctx->error)
|
||||||
{
|
{
|
||||||
case X509_V_ERR_CERT_NOT_YET_VALID:
|
case X509_V_ERR_CERT_NOT_YET_VALID:
|
||||||
case X509_V_ERR_CERT_HAS_EXPIRED:
|
case X509_V_ERR_CERT_HAS_EXPIRED:
|
||||||
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
|
||||||
|
fprintf(stderr," ... ignored.\n");
|
||||||
ok=1;
|
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,
|
X509_STORE_CTX_set_ex_data(ctx,
|
||||||
get_proxy_auth_ex_data_idx(),letters);
|
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
|
#ifndef OPENSSL_NO_X509_VERIFY
|
||||||
# ifdef OPENSSL_FIPS
|
# ifdef OPENSSL_FIPS
|
||||||
|
@ -4,7 +4,7 @@ echo 'Testing a lot of proxy conditions.'
|
|||||||
echo 'Some of them may turn out being invalid, which is fine.'
|
echo 'Some of them may turn out being invalid, which is fine.'
|
||||||
for auth in A B C BC; do
|
for auth in A B C BC; do
|
||||||
for cond in A B C 'A|B&!C'; 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
|
if [ $? = 3 ]; then exit 1; fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user