Fix no-ocsp
[openssl.git] / crypto / x509 / x509_trs.c
index 6632f9b9de7d07ac67298f2e0bc31b8917941680..4c5281a718c3bdf7fe001c970a0a1a1ec0f81b01 100644 (file)
@@ -1,4 +1,3 @@
-/* x509_trs.c */
 /*
  * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project
  * 1999.
@@ -58,8 +57,9 @@
  */
 
 #include <stdio.h>
-#include "cryptlib.h"
+#include "internal/cryptlib.h"
 #include <openssl/x509v3.h>
+#include "internal/x509_int.h"
 
 static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b);
 static void trtable_free(X509_TRUST *p);
@@ -115,16 +115,11 @@ 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);
-    }
+    if (id == X509_TRUST_DEFAULT)
+        return obj_trust(NID_anyExtendedKeyUsage, x,
+                         flags | X509_TRUST_DO_SS_COMPAT);
     idx = X509_TRUST_get_by_id(id);
     if (idx == -1)
         return default_trust(id, x, flags);
@@ -188,7 +183,7 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
     idx = X509_TRUST_get_by_id(id);
     /* Need a new entry */
     if (idx == -1) {
-        if (!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) {
+        if ((trtmp = OPENSSL_malloc(sizeof(*trtmp))) == NULL) {
             X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
             return 0;
         }
@@ -200,7 +195,7 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
     if (trtmp->flags & X509_TRUST_DYNAMIC_NAME)
         OPENSSL_free(trtmp->name);
     /* dup supplied name */
-    if (!(trtmp->name = BUF_strdup(name))) {
+    if ((trtmp->name = OPENSSL_strdup(name)) == NULL) {
         X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
         return 0;
     }
@@ -216,7 +211,8 @@ int X509_TRUST_add(int id, int flags, int (*ck) (X509_TRUST *, X509 *, int),
 
     /* If its a new entry manage the dynamic table */
     if (idx == -1) {
-        if (!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) {
+        if (trtable == NULL
+            && (trtable = sk_X509_TRUST_new(tr_cmp)) == NULL) {
             X509err(X509_F_X509_TRUST_ADD, ERR_R_MALLOC_FAILURE);
             return 0;
         }
@@ -265,26 +261,32 @@ int X509_TRUST_get_trust(X509_TRUST *xp)
 
 static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags)
 {
-    if (x->aux && (x->aux->trust || x->aux->reject))
-        return obj_trust(trust->arg1, x, flags);
     /*
-     * we don't have any trust settings: for compatibility we return trusted
-     * if it is self signed
+     * Declare the chain verified if the desired trust OID is not rejected in
+     * any auxiliary trust info for this certificate, and the OID is either
+     * expressly trusted, or else either "anyEKU" is trusted, or the
+     * certificate is self-signed.
      */
-    return trust_compat(trust, x, flags);
+    flags |= X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU;
+    return obj_trust(trust->arg1, x, flags);
 }
 
 static int trust_1oid(X509_TRUST *trust, X509 *x, int flags)
 {
-    if (x->aux)
-        return obj_trust(trust->arg1, x, flags);
-    return X509_TRUST_UNTRUSTED;
+    /*
+     * Declare the chain verified only if the desired trust OID is not
+     * rejected and is expressly trusted.  Neither "anyEKU" nor "compat"
+     * trust in self-signed certificates apply.
+     */
+    flags &= ~(X509_TRUST_DO_SS_COMPAT | X509_TRUST_OK_ANY_EKU);
+    return obj_trust(trust->arg1, x, flags);
 }
 
 static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
 {
+    /* Call for side-effect of computing hash and caching extensions */
     X509_check_purpose(x, -1, 0);
-    if (x->ex_flags & EXFLAG_SS)
+    if ((flags & X509_TRUST_NO_SS_COMPAT) == 0 && x->ex_flags & EXFLAG_SS)
         return X509_TRUST_TRUSTED;
     else
         return X509_TRUST_UNTRUSTED;
@@ -292,25 +294,51 @@ static int trust_compat(X509_TRUST *trust, X509 *x, int flags)
 
 static int obj_trust(int id, X509 *x, int flags)
 {
-    ASN1_OBJECT *obj;
+    X509_CERT_AUX *ax = x->aux;
     int i;
-    X509_CERT_AUX *ax;
-    ax = x->aux;
-    if (!ax)
-        return X509_TRUST_UNTRUSTED;
-    if (ax->reject) {
+
+    if (ax && ax->reject) {
         for (i = 0; i < sk_ASN1_OBJECT_num(ax->reject); i++) {
-            obj = sk_ASN1_OBJECT_value(ax->reject, i);
-            if (OBJ_obj2nid(obj) == id)
+            ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->reject, i);
+            int nid = OBJ_obj2nid(obj);
+
+            if (nid == id || (nid == NID_anyExtendedKeyUsage &&
+                (flags & X509_TRUST_OK_ANY_EKU)))
                 return X509_TRUST_REJECTED;
         }
     }
-    if (ax->trust) {
+
+    if (ax && ax->trust) {
         for (i = 0; i < sk_ASN1_OBJECT_num(ax->trust); i++) {
-            obj = sk_ASN1_OBJECT_value(ax->trust, i);
-            if (OBJ_obj2nid(obj) == id)
+            ASN1_OBJECT *obj = sk_ASN1_OBJECT_value(ax->trust, i);
+            int nid = OBJ_obj2nid(obj);
+
+            if (nid == id || (nid == NID_anyExtendedKeyUsage &&
+                (flags & X509_TRUST_OK_ANY_EKU)))
                 return X509_TRUST_TRUSTED;
         }
+        /*
+         * Reject when explicit trust EKU are set and none match.
+         *
+         * Returning untrusted is enough for for full chains that end in
+         * self-signed roots, because when explicit trust is specified it
+         * suppresses the default blanket trust of self-signed objects.
+         *
+         * But for partial chains, this is not enough, because absent a similar
+         * trust-self-signed policy, non matching EKUs are indistinguishable
+         * from lack of EKU constraints.
+         *
+         * Therefore, failure to match any trusted purpose must trigger an
+         * explicit reject.
+         */
+        return X509_TRUST_REJECTED;
     }
-    return X509_TRUST_UNTRUSTED;
+
+    if ((flags & X509_TRUST_DO_SS_COMPAT) == 0)
+        return X509_TRUST_UNTRUSTED;
+
+    /*
+     * Not rejected, and there is no list of accepted uses, try compat.
+     */
+    return trust_compat(NULL, x, flags);
 }