From: Dr. Stephen Henson Date: Sun, 21 Oct 2001 02:09:15 +0000 (+0000) Subject: Reject certificates with unhandled critical extensions. X-Git-Tag: OpenSSL_0_9_6c~26^2~107 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=f1558bb4243d83781793ed758367bd71d0983a35;p=oweals%2Fopenssl.git Reject certificates with unhandled critical extensions. --- diff --git a/CHANGES b/CHANGES index 79ee3c82e4..94605d7ffd 100644 --- a/CHANGES +++ b/CHANGES @@ -12,6 +12,15 @@ *) applies to 0.9.6a/0.9.6b/0.9.6c and 0.9.7 +) 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 SSL_CTX_set_msg_callback(ctx, cb) diff --git a/apps/verify.c b/apps/verify.c index d4bf0693c8..255bf5ad28 100644 --- a/apps/verify.c +++ b/apps/verify.c @@ -146,6 +146,8 @@ int MAIN(int argc, char **argv) } else if (strcmp(*argv,"-help") == 0) goto end; + else if (strcmp(*argv,"-ignore_critical") == 0) + vflags |= X509_V_FLAG_IGNORE_CRITICAL; else if (strcmp(*argv,"-issuer_checks") == 0) vflags |= X509_V_FLAG_CB_ISSUER_CHECK; 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_CRL_HAS_EXPIRED) 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) ERR_clear_error(); diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index bcf38a6c91..4f83db8ba2 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -144,6 +144,9 @@ const char *X509_verify_cert_error_string(long n) case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: return("unable to get CRL issuer certificate"); + case X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION: + return("unhandled critical extension"); + default: sprintf(buf,"error number %ld",n); return(buf); diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 892b7849fd..3c69bb9e0e 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -384,6 +384,15 @@ static int check_chain_purpose(X509_STORE_CTX *ctx) for (i = 0; i < ctx->last_untrusted; 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 (i) @@ -721,8 +730,6 @@ static int internal_verify(X509_STORE_CTX *ctx) if (!ok) goto end; } - /* CRL CHECK */ - /* The last error (if any) is still in the error value */ ctx->current_cert=xs; ok=(*cb)(1,ctx); diff --git a/crypto/x509/x509_vfy.h b/crypto/x509/x509_vfy.h index 689062fa30..f0be21f452 100644 --- a/crypto/x509/x509_vfy.h +++ b/crypto/x509/x509_vfy.h @@ -303,6 +303,7 @@ struct x509_store_ctx_st /* X509_STORE_CTX */ #define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 #define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 /* The application is not happy */ #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_CRL_CHECK 0x4 /* Lookup CRLs */ #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, X509_NAME *name); diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index ad55016236..b739e4fd83 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -1,9 +1,9 @@ /* v3_purp.c */ /* 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 * modification, are permitted provided that the following conditions @@ -266,12 +266,51 @@ int X509_PURPOSE_get_trust(X509_PURPOSE *xp) 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) { BASIC_CONSTRAINTS *bs; ASN1_BIT_STRING *usage; ASN1_BIT_STRING *ns; EXTENDED_KEY_USAGE *extusage; + X509_EXTENSION *ex; int i; 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->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; } diff --git a/crypto/x509v3/x509v3.h b/crypto/x509v3/x509v3.h index 096dc56b68..d1c9828f78 100644 --- a/crypto/x509v3/x509v3.h +++ b/crypto/x509v3/x509v3.h @@ -324,6 +324,7 @@ DECLARE_ASN1_SET_OF(POLICYINFO) #define EXFLAG_V1 0x40 #define EXFLAG_INVALID 0x80 #define EXFLAG_SET 0x100 +#define EXFLAG_CRITICAL 0x200 #define KU_DIGITAL_SIGNATURE 0x0080 #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 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_check_issued(X509 *issuer, X509 *subject); int X509_PURPOSE_get_count(void);