Reject certificates with unhandled critical extensions.
authorDr. Stephen Henson <steve@openssl.org>
Sun, 21 Oct 2001 02:09:15 +0000 (02:09 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Sun, 21 Oct 2001 02:09:15 +0000 (02:09 +0000)
CHANGES
apps/verify.c
crypto/x509/x509_txt.c
crypto/x509/x509_vfy.c
crypto/x509/x509_vfy.h
crypto/x509v3/v3_purp.c
crypto/x509v3/x509v3.h

diff --git a/CHANGES b/CHANGES
index 79ee3c8..94605d7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
          *) 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)
index d4bf069..255bf5a 100644 (file)
@@ -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();
index bcf38a6..4f83db8 100644 (file)
@@ -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);
index 892b784..3c69bb9 100644 (file)
@@ -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);
index 689062f..f0be21f 100644 (file)
@@ -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);
index ad55016..b739e4f 100644 (file)
@@ -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;
 }
 
index 096dc56..d1c9828 100644 (file)
@@ -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);