Experimental support for partial chain verification: if an intermediate
authorDr. Stephen Henson <steve@openssl.org>
Thu, 25 Feb 2010 00:17:22 +0000 (00:17 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Thu, 25 Feb 2010 00:17:22 +0000 (00:17 +0000)
certificate is explicitly trusted (using -addtrust option to x509 utility
for example) the verification is sucessful even if the chain is not complete.

CHANGES
crypto/x509/x509_trs.c
crypto/x509/x509_vfy.c

diff --git a/CHANGES b/CHANGES
index ec2ee0d17d7052194ba3d8513598ece78ff36eb3..7aae336e3757882016a00a47cc338ab67065cb52 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,16 @@
 
  Changes between 1.0.0 and 1.1.0  [xx XXX xxxx]
 
+  *) Initial experimental support for explicitly trusted non-root CAs. 
+     OpenSSL still tries to build a complete chain to a root but if an
+     intermediate CA has a trust setting included that is used. The first
+     setting is used: whether to trust or reject.
+     [Steve Henson]
+
+  *) New -verify_name option in command line utilities to set verification
+     parameters by name.
+     [Steve Henson]
+
   *) Initial CMAC implementation. WARNING: EXPERIMENTAL, API MAY CHANGE.
      Add CMAC pkey methods.
      [Steve Henson]
index a6cb9c8b1b37ecac5ebd7eb490669bf48a33e2be..3d7e06815c8e04eee3bc2d50e958ec3a493ce57f 100644 (file)
@@ -114,6 +114,15 @@ int X509_check_trust(X509 *x, int id, int flags)
        X509_TRUST *pt;
        int idx;
        if(id == -1) return 1;
+       /* We get this as a default value */
+       if (id == 0)
+               {
+               int rv;
+               rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
+               if (rv != X509_TRUST_UNTRUSTED)
+                       return rv;
+               return trust_compat(NULL, x, 0);
+               }
        idx = X509_TRUST_get_by_id(id);
        if(idx == -1) return default_trust(id, x, flags);
        pt = X509_TRUST_get0(idx);
index 87ebf62525cad5e2579d6708a47859a2945b7e45..14e29f2782b85705fcc4752e3f241b58196d08cd 100644 (file)
@@ -312,8 +312,13 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
        /* we now have our chain, lets check it... */
        xn=X509_get_issuer_name(x);
 
-       /* Is last certificate looked up self signed? */
-       if (!ctx->check_issued(ctx,x,x))
+       i = check_trust(ctx);
+
+       /* If explicitly rejected error */
+       if (i == X509_TRUST_REJECTED)
+               goto end;
+       /* If not explicitly trusted then indicate error */
+       if (i != X509_TRUST_TRUSTED)
                {
                if ((chain_ss == NULL) || !ctx->check_issued(ctx, x, chain_ss))
                        {
@@ -351,12 +356,6 @@ int X509_verify_cert(X509_STORE_CTX *ctx)
        
        if (!ok) goto end;
 
-       /* The chain extensions are OK: check trust */
-
-       if (param->trust > 0) ok = check_trust(ctx);
-
-       if (!ok) goto end;
-
        /* We may as well copy down any DSA parameters that are required */
        X509_get_pubkey_parameters(NULL,ctx->chain);
 
@@ -647,28 +646,35 @@ static int check_name_constraints(X509_STORE_CTX *ctx)
 
 static int check_trust(X509_STORE_CTX *ctx)
 {
-#ifdef OPENSSL_NO_CHAIN_VERIFY
-       return 1;
-#else
        int i, ok;
-       X509 *x;
+       X509 *x = NULL;
        int (*cb)(int xok,X509_STORE_CTX *xctx);
        cb=ctx->verify_cb;
-/* For now just check the last certificate in the chain */
-       i = sk_X509_num(ctx->chain) - 1;
-       x = sk_X509_value(ctx->chain, i);
-       ok = X509_check_trust(x, ctx->param->trust, 0);
-       if (ok == X509_TRUST_TRUSTED)
-               return 1;
-       ctx->error_depth = i;
-       ctx->current_cert = x;
-       if (ok == X509_TRUST_REJECTED)
-               ctx->error = X509_V_ERR_CERT_REJECTED;
-       else
-               ctx->error = X509_V_ERR_CERT_UNTRUSTED;
-       ok = cb(0, ctx);
-       return ok;
-#endif
+       /* Check all trusted certificates in chain */
+       for (i = ctx->last_untrusted; i < sk_X509_num(ctx->chain); i++)
+               {
+               x = sk_X509_value(ctx->chain, i);
+               ok = X509_check_trust(x, ctx->param->trust, 0);
+               /* If explicitly trusted return trusted */
+               if (ok == X509_TRUST_TRUSTED)
+                       return X509_TRUST_TRUSTED;
+               /* If explicitly rejected notify callback and reject if
+                * not overridden.
+                */
+               if (ok == X509_TRUST_REJECTED)
+                       {
+                       ctx->error_depth = i;
+                       ctx->current_cert = x;
+                       ctx->error = X509_V_ERR_CERT_REJECTED;
+                       ok = cb(0, ctx);
+                       if (!ok)
+                               return X509_TRUST_REJECTED;
+                       }
+               }
+       /* If no trusted certs in chain at all return untrusted and
+        * allow standard (no issuer cert) etc errors to be indicated.
+        */
+       return X509_TRUST_UNTRUSTED;
 }
 
 static int check_revocation(X509_STORE_CTX *ctx)