Reject certificates with unhandled critical extensions.
This commit is contained in:
parent
6ca487992b
commit
f1558bb424
9
CHANGES
9
CHANGES
@ -12,6 +12,15 @@
|
|||||||
*) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7
|
*) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7
|
||||||
+) applies to 0.9.7 only
|
+) applies to 0.9.7 only
|
||||||
|
|
||||||
|
+) Test for certificates which contain unsupported critical extensions.
|
||||||
|
If such a certificate is found during a verify operation it is
|
||||||
|
rejected by default: this behaviour can be overridden by either
|
||||||
|
handling the new error X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION or
|
||||||
|
by setting the verify flag X509_V_FLAG_IGNORE_CRITICAL. A new function
|
||||||
|
X509_supported_extension() has also been added which returns 1 if a
|
||||||
|
particular extension is supported.
|
||||||
|
[Steve Henson]
|
||||||
|
|
||||||
+) New functions/macros
|
+) New functions/macros
|
||||||
|
|
||||||
SSL_CTX_set_msg_callback(ctx, cb)
|
SSL_CTX_set_msg_callback(ctx, cb)
|
||||||
|
@ -146,6 +146,8 @@ int MAIN(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else if (strcmp(*argv,"-help") == 0)
|
else if (strcmp(*argv,"-help") == 0)
|
||||||
goto end;
|
goto end;
|
||||||
|
else if (strcmp(*argv,"-ignore_critical") == 0)
|
||||||
|
vflags |= X509_V_FLAG_IGNORE_CRITICAL;
|
||||||
else if (strcmp(*argv,"-issuer_checks") == 0)
|
else if (strcmp(*argv,"-issuer_checks") == 0)
|
||||||
vflags |= X509_V_FLAG_CB_ISSUER_CHECK;
|
vflags |= X509_V_FLAG_CB_ISSUER_CHECK;
|
||||||
else if (strcmp(*argv,"-crl_check") == 0)
|
else if (strcmp(*argv,"-crl_check") == 0)
|
||||||
@ -343,6 +345,7 @@ static int MS_CALLBACK cb(int ok, X509_STORE_CTX *ctx)
|
|||||||
if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
|
if (ctx->error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) ok=1;
|
||||||
if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1;
|
if (ctx->error == X509_V_ERR_CRL_HAS_EXPIRED) ok=1;
|
||||||
if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1;
|
if (ctx->error == X509_V_ERR_CRL_NOT_YET_VALID) ok=1;
|
||||||
|
if (ctx->error == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) ok=1;
|
||||||
}
|
}
|
||||||
if (!v_verbose)
|
if (!v_verbose)
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
@ -144,6 +144,9 @@ const char *X509_verify_cert_error_string(long n)
|
|||||||
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
|
case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
|
||||||
return("unable to get CRL issuer certificate");
|
return("unable to get CRL issuer certificate");
|
||||||
|
|
||||||
|
case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION:
|
||||||
|
return("unhandled critical extension");
|
||||||
|
|
||||||
default:
|
default:
|
||||||
sprintf(buf,"error number %ld",n);
|
sprintf(buf,"error number %ld",n);
|
||||||
return(buf);
|
return(buf);
|
||||||
|
@ -384,6 +384,15 @@ static int check_chain_purpose(X509_STORE_CTX *ctx)
|
|||||||
for (i = 0; i < ctx->last_untrusted; i++)
|
for (i = 0; i < ctx->last_untrusted; i++)
|
||||||
{
|
{
|
||||||
x = sk_X509_value(ctx->chain, i);
|
x = sk_X509_value(ctx->chain, i);
|
||||||
|
if (!(ctx->flags & X509_V_FLAG_IGNORE_CRITICAL)
|
||||||
|
&& (x->ex_flags & EXFLAG_CRITICAL))
|
||||||
|
{
|
||||||
|
ctx->error = X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION;
|
||||||
|
ctx->error_depth = i;
|
||||||
|
ctx->current_cert = x;
|
||||||
|
ok=cb(0,ctx);
|
||||||
|
if (!ok) goto end;
|
||||||
|
}
|
||||||
if (!X509_check_purpose(x, ctx->purpose, i))
|
if (!X509_check_purpose(x, ctx->purpose, i))
|
||||||
{
|
{
|
||||||
if (i)
|
if (i)
|
||||||
@ -721,8 +730,6 @@ static int internal_verify(X509_STORE_CTX *ctx)
|
|||||||
if (!ok) goto end;
|
if (!ok) goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CRL CHECK */
|
|
||||||
|
|
||||||
/* The last error (if any) is still in the error value */
|
/* The last error (if any) is still in the error value */
|
||||||
ctx->current_cert=xs;
|
ctx->current_cert=xs;
|
||||||
ok=(*cb)(1,ctx);
|
ok=(*cb)(1,ctx);
|
||||||
|
@ -303,6 +303,7 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
|
|||||||
#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
|
#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32
|
||||||
|
|
||||||
#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
|
#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33
|
||||||
|
#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34
|
||||||
|
|
||||||
/* The application is not happy */
|
/* The application is not happy */
|
||||||
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
#define X509_V_ERR_APPLICATION_VERIFICATION 50
|
||||||
@ -313,6 +314,7 @@ struct x509_store_ctx_st /* X509_STORE_CTX */
|
|||||||
#define X509_V_FLAG_USE_CHECK_TIME 0x2 /* Use check time instead of current time */
|
#define X509_V_FLAG_USE_CHECK_TIME 0x2 /* Use check time instead of current time */
|
||||||
#define X509_V_FLAG_CRL_CHECK 0x4 /* Lookup CRLs */
|
#define X509_V_FLAG_CRL_CHECK 0x4 /* Lookup CRLs */
|
||||||
#define X509_V_FLAG_CRL_CHECK_ALL 0x8 /* Lookup CRLs for whole chain */
|
#define X509_V_FLAG_CRL_CHECK_ALL 0x8 /* Lookup CRLs for whole chain */
|
||||||
|
#define X509_V_FLAG_IGNORE_CRITICAL 0x10 /* Ignore unhandled critical extensions */
|
||||||
|
|
||||||
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
|
int X509_OBJECT_idx_by_subject(STACK_OF(X509_OBJECT) *h, int type,
|
||||||
X509_NAME *name);
|
X509_NAME *name);
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
/* v3_purp.c */
|
/* v3_purp.c */
|
||||||
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
/* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
|
||||||
* project 1999.
|
* project 2001.
|
||||||
*/
|
*/
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
* Copyright (c) 1999 The OpenSSL Project. All rights reserved.
|
* Copyright (c) 1999-2001 The OpenSSL Project. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -266,12 +266,51 @@ int X509_PURPOSE_get_trust(X509_PURPOSE *xp)
|
|||||||
return xp->trust;
|
return xp->trust;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nid_cmp(int *a, int *b)
|
||||||
|
{
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int X509_supported_extension(X509_EXTENSION *ex)
|
||||||
|
{
|
||||||
|
/* This table is a list of the NIDs of supported extensions:
|
||||||
|
* that is those which are used by the verify process. If
|
||||||
|
* an extension is critical and doesn't appear in this list
|
||||||
|
* then the verify process will normally reject the certificate.
|
||||||
|
* The list must be kept in numerical order because it will be
|
||||||
|
* searched using bsearch.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int supported_nids[] = {
|
||||||
|
NID_netscape_cert_type, /* 71 */
|
||||||
|
NID_key_usage, /* 83 */
|
||||||
|
NID_subject_alt_name, /* 85 */
|
||||||
|
NID_basic_constraints, /* 87 */
|
||||||
|
NID_ext_key_usage /* 126 */
|
||||||
|
};
|
||||||
|
|
||||||
|
int ex_nid;
|
||||||
|
|
||||||
|
ex_nid = OBJ_obj2nid(X509_EXTENSION_get_object(ex));
|
||||||
|
|
||||||
|
if (ex_nid == NID_undef)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (OBJ_bsearch((char *)&ex_nid, (char *)supported_nids,
|
||||||
|
sizeof(supported_nids)/sizeof(int), sizeof(int),
|
||||||
|
(int (*)(const void *, const void *))nid_cmp))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void x509v3_cache_extensions(X509 *x)
|
static void x509v3_cache_extensions(X509 *x)
|
||||||
{
|
{
|
||||||
BASIC_CONSTRAINTS *bs;
|
BASIC_CONSTRAINTS *bs;
|
||||||
ASN1_BIT_STRING *usage;
|
ASN1_BIT_STRING *usage;
|
||||||
ASN1_BIT_STRING *ns;
|
ASN1_BIT_STRING *ns;
|
||||||
EXTENDED_KEY_USAGE *extusage;
|
EXTENDED_KEY_USAGE *extusage;
|
||||||
|
X509_EXTENSION *ex;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
if(x->ex_flags & EXFLAG_SET) return;
|
if(x->ex_flags & EXFLAG_SET) return;
|
||||||
@ -352,6 +391,17 @@ static void x509v3_cache_extensions(X509 *x)
|
|||||||
}
|
}
|
||||||
x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
|
x->skid =X509_get_ext_d2i(x, NID_subject_key_identifier, NULL, NULL);
|
||||||
x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
|
x->akid =X509_get_ext_d2i(x, NID_authority_key_identifier, NULL, NULL);
|
||||||
|
for (i = 0; i < X509_get_ext_count(x); i++)
|
||||||
|
{
|
||||||
|
ex = X509_get_ext(x, i);
|
||||||
|
if (!X509_EXTENSION_get_critical(ex))
|
||||||
|
continue;
|
||||||
|
if (!X509_supported_extension(ex))
|
||||||
|
{
|
||||||
|
x->ex_flags |= EXFLAG_CRITICAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
x->ex_flags |= EXFLAG_SET;
|
x->ex_flags |= EXFLAG_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,6 +324,7 @@ DECLARE_ASN1_SET_OF(POLICYINFO)
|
|||||||
#define EXFLAG_V1 0x40
|
#define EXFLAG_V1 0x40
|
||||||
#define EXFLAG_INVALID 0x80
|
#define EXFLAG_INVALID 0x80
|
||||||
#define EXFLAG_SET 0x100
|
#define EXFLAG_SET 0x100
|
||||||
|
#define EXFLAG_CRITICAL 0x200
|
||||||
|
|
||||||
#define KU_DIGITAL_SIGNATURE 0x0080
|
#define KU_DIGITAL_SIGNATURE 0x0080
|
||||||
#define KU_NON_REPUDIATION 0x0040
|
#define KU_NON_REPUDIATION 0x0040
|
||||||
@ -528,6 +529,7 @@ int X509V3_EXT_print_fp(FILE *out, X509_EXTENSION *ext, int flag, int indent);
|
|||||||
int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
|
int X509V3_extensions_print(BIO *out, char *title, STACK_OF(X509_EXTENSION) *exts, unsigned long flag, int indent);
|
||||||
|
|
||||||
int X509_check_purpose(X509 *x, int id, int ca);
|
int X509_check_purpose(X509 *x, int id, int ca);
|
||||||
|
int X509_supported_extension(X509_EXTENSION *ex);
|
||||||
int X509_PURPOSE_set(int *p, int purpose);
|
int X509_PURPOSE_set(int *p, int purpose);
|
||||||
int X509_check_issued(X509 *issuer, X509 *subject);
|
int X509_check_issued(X509 *issuer, X509 *subject);
|
||||||
int X509_PURPOSE_get_count(void);
|
int X509_PURPOSE_get_count(void);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user