Remove dynamic X509_TRUST and X509_PURPOSE registration

This is not thread-safe. Even if made thread-safe, it involves
registering globals, so it's just not a good API.

Note this means that there is no longer a way to configure custom trust
OIDs or purpose checks. Evidently no one was doing that. Should a use
case arise, I don't think it should be met by this API. The things one
might want to configure here are:

- Which OID to match against X509_add1_trust_object and
  X509_add1_reject_object

- Whether self-signed certificates, if no trust objects are configured,
  also count as trust anchors

- Which EKU OID to look for up the chain

- Which legacy Netscape certificate type to look for (can we remove
  this?)

- Which key usage bits to look for in the leaf

We can simply add APIs for specifying those if we need them.

Interestingly, there's a call to check_ca inside the purpose checks
(which gets skipped if you don't configure a purpose!), but I think it
may be redundant with the X509_check_ca call in the path verifier.

Change-Id: If71ee3d0768b5fc71422852b4fcf7eb23e937dd2
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/64507
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c
index de1e8be..9db45ba 100644
--- a/crypto/x509/v3_purp.c
+++ b/crypto/x509/v3_purp.c
@@ -94,9 +94,6 @@
 static int no_check(const X509_PURPOSE *xp, const X509 *x, int ca);
 static int ocsp_helper(const X509_PURPOSE *xp, const X509 *x, int ca);
 
-static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b);
-static void xptable_free(X509_PURPOSE *p);
-
 static X509_PURPOSE xstandard[] = {
     {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0,
      check_purpose_ssl_client, (char *)"SSL client", (char *)"sslclient", NULL},
@@ -121,14 +118,6 @@
      (char *)"timestampsign", NULL},
 };
 
-#define X509_PURPOSE_COUNT (sizeof(xstandard) / sizeof(X509_PURPOSE))
-
-static STACK_OF(X509_PURPOSE) *xptable = NULL;
-
-static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b) {
-  return (*a)->purpose - (*b)->purpose;
-}
-
 // As much as I'd like to make X509_check_purpose use a "const" X509* I
 // really can't because it does recalculate hashes and do other non-const
 // things.
@@ -159,21 +148,13 @@
   return 1;
 }
 
-int X509_PURPOSE_get_count(void) {
-  if (!xptable) {
-    return X509_PURPOSE_COUNT;
-  }
-  return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT;
-}
+int X509_PURPOSE_get_count(void) { return OPENSSL_ARRAY_SIZE(xstandard); }
 
 X509_PURPOSE *X509_PURPOSE_get0(int idx) {
-  if (idx < 0) {
+  if (idx < 0 || (size_t)idx >= OPENSSL_ARRAY_SIZE(xstandard)) {
     return NULL;
   }
-  if (idx < (int)X509_PURPOSE_COUNT) {
-    return xstandard + idx;
-  }
-  return sk_X509_PURPOSE_value(xptable, idx - X509_PURPOSE_COUNT);
+  return xstandard + idx;
 }
 
 int X509_PURPOSE_get_by_sname(const char *sname) {
@@ -188,118 +169,10 @@
 }
 
 int X509_PURPOSE_get_by_id(int purpose) {
-  X509_PURPOSE tmp;
-  size_t idx;
-
-  if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) {
+  if (purpose >= X509_PURPOSE_MIN && purpose <= X509_PURPOSE_MAX) {
     return purpose - X509_PURPOSE_MIN;
   }
-  tmp.purpose = purpose;
-  if (!xptable) {
-    return -1;
-  }
-
-  if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp)) {
-    return -1;
-  }
-  return idx + X509_PURPOSE_COUNT;
-}
-
-int X509_PURPOSE_add(int id, int trust, int flags,
-                     int (*ck)(const X509_PURPOSE *, const X509 *, int),
-                     const char *name, const char *sname, void *arg) {
-  X509_PURPOSE *ptmp;
-  char *name_dup, *sname_dup;
-
-  // This is set according to what we change: application can't set it
-  flags &= ~X509_PURPOSE_DYNAMIC;
-  // This will always be set for application modified trust entries
-  flags |= X509_PURPOSE_DYNAMIC_NAME;
-  // Get existing entry if any
-  int idx = X509_PURPOSE_get_by_id(id);
-  // Need a new entry
-  if (idx == -1) {
-    if (!(ptmp = OPENSSL_malloc(sizeof(X509_PURPOSE)))) {
-      return 0;
-    }
-    ptmp->flags = X509_PURPOSE_DYNAMIC;
-  } else {
-    ptmp = X509_PURPOSE_get0(idx);
-  }
-
-  // Duplicate the supplied names.
-  name_dup = OPENSSL_strdup(name);
-  sname_dup = OPENSSL_strdup(sname);
-  if (name_dup == NULL || sname_dup == NULL) {
-    if (name_dup != NULL) {
-      OPENSSL_free(name_dup);
-    }
-    if (sname_dup != NULL) {
-      OPENSSL_free(sname_dup);
-    }
-    if (idx == -1) {
-      OPENSSL_free(ptmp);
-    }
-    return 0;
-  }
-
-  // OPENSSL_free existing name if dynamic
-  if (ptmp->flags & X509_PURPOSE_DYNAMIC_NAME) {
-    OPENSSL_free(ptmp->name);
-    OPENSSL_free(ptmp->sname);
-  }
-  // dup supplied name
-  ptmp->name = name_dup;
-  ptmp->sname = sname_dup;
-  // Keep the dynamic flag of existing entry
-  ptmp->flags &= X509_PURPOSE_DYNAMIC;
-  // Set all other flags
-  ptmp->flags |= flags;
-
-  ptmp->purpose = id;
-  ptmp->trust = trust;
-  ptmp->check_purpose = ck;
-  ptmp->usr_data = arg;
-
-  // If its a new entry manage the dynamic table
-  if (idx == -1) {
-    // TODO(davidben): This should be locked. Alternatively, remove the dynamic
-    // registration mechanism entirely. The trouble is there no way to pass in
-    // the various parameters into an |X509_VERIFY_PARAM| directly. You can only
-    // register it in the global table and get an ID.
-    if (!xptable && !(xptable = sk_X509_PURPOSE_new(xp_cmp))) {
-      xptable_free(ptmp);
-      return 0;
-    }
-    if (!sk_X509_PURPOSE_push(xptable, ptmp)) {
-      xptable_free(ptmp);
-      return 0;
-    }
-    sk_X509_PURPOSE_sort(xptable);
-  }
-  return 1;
-}
-
-static void xptable_free(X509_PURPOSE *p) {
-  if (!p) {
-    return;
-  }
-  if (p->flags & X509_PURPOSE_DYNAMIC) {
-    if (p->flags & X509_PURPOSE_DYNAMIC_NAME) {
-      OPENSSL_free(p->name);
-      OPENSSL_free(p->sname);
-    }
-    OPENSSL_free(p);
-  }
-}
-
-void X509_PURPOSE_cleanup(void) {
-  unsigned int i;
-  sk_X509_PURPOSE_pop_free(xptable, xptable_free);
-  for (i = 0; i < X509_PURPOSE_COUNT; i++) {
-    xptable_free(xstandard + i);
-  }
-  xptable = NULL;
+  return -1;
 }
 
 int X509_PURPOSE_get_id(const X509_PURPOSE *xp) { return xp->purpose; }
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c
index 53819b3..ce4194b 100644
--- a/crypto/x509/x509_trs.c
+++ b/crypto/x509/x509_trs.c
@@ -59,12 +59,10 @@
 #include <openssl/obj.h>
 #include <openssl/x509.h>
 
+#include "../internal.h"
 #include "internal.h"
 
 
-static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b);
-static void trtable_free(X509_TRUST *p);
-
 static int trust_1oidany(X509_TRUST *trust, X509 *x, int flags);
 static int trust_1oid(X509_TRUST *trust, X509 *x, int flags);
 static int trust_compat(X509_TRUST *trust, X509 *x, int flags);
@@ -92,14 +90,6 @@
     {X509_TRUST_TSA, 0, trust_1oidany, (char *)"TSA server", NID_time_stamp,
      NULL}};
 
-#define X509_TRUST_COUNT (sizeof(trstandard) / sizeof(X509_TRUST))
-
-static STACK_OF(X509_TRUST) *trtable = NULL;
-
-static int tr_cmp(const X509_TRUST *const *a, const X509_TRUST *const *b) {
-  return (*a)->trust - (*b)->trust;
-}
-
 int X509_check_trust(X509 *x, int id, int flags) {
   X509_TRUST *pt;
   int idx;
@@ -123,38 +113,20 @@
   return pt->check_trust(pt, x, flags);
 }
 
-int X509_TRUST_get_count(void) {
-  if (!trtable) {
-    return X509_TRUST_COUNT;
-  }
-  return sk_X509_TRUST_num(trtable) + X509_TRUST_COUNT;
-}
+int X509_TRUST_get_count(void) { return OPENSSL_ARRAY_SIZE(trstandard); }
 
 X509_TRUST *X509_TRUST_get0(int idx) {
-  if (idx < 0) {
+  if (idx < 0 || (size_t)idx >= OPENSSL_ARRAY_SIZE(trstandard)) {
     return NULL;
   }
-  if (idx < (int)X509_TRUST_COUNT) {
-    return trstandard + idx;
-  }
-  return sk_X509_TRUST_value(trtable, idx - X509_TRUST_COUNT);
+  return trstandard + idx;
 }
 
 int X509_TRUST_get_by_id(int id) {
-  X509_TRUST tmp;
-  size_t idx;
-
-  if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) {
+  if (id >= X509_TRUST_MIN && id <= X509_TRUST_MAX) {
     return id - X509_TRUST_MIN;
   }
-  tmp.trust = id;
-  if (!trtable) {
-    return -1;
-  }
-  if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) {
-    return -1;
-  }
-  return idx + X509_TRUST_COUNT;
+  return -1;
 }
 
 int X509_TRUST_set(int *t, int trust) {
@@ -166,92 +138,6 @@
   return 1;
 }
 
-int X509_TRUST_add(int id, int flags, int (*ck)(X509_TRUST *, X509 *, int),
-                   const char *name, int arg1, void *arg2) {
-  int idx;
-  X509_TRUST *trtmp;
-  char *name_dup;
-
-  // This is set according to what we change: application can't set it
-  flags &= ~X509_TRUST_DYNAMIC;
-  // This will always be set for application modified trust entries
-  flags |= X509_TRUST_DYNAMIC_NAME;
-  // Get existing entry if any
-  idx = X509_TRUST_get_by_id(id);
-  // Need a new entry
-  if (idx == -1) {
-    if (!(trtmp = OPENSSL_malloc(sizeof(X509_TRUST)))) {
-      return 0;
-    }
-    trtmp->flags = X509_TRUST_DYNAMIC;
-  } else {
-    trtmp = X509_TRUST_get0(idx);
-  }
-
-  // Duplicate the supplied name.
-  name_dup = OPENSSL_strdup(name);
-  if (name_dup == NULL) {
-    if (idx == -1) {
-      OPENSSL_free(trtmp);
-    }
-    return 0;
-  }
-
-  // OPENSSL_free existing name if dynamic
-  if (trtmp->flags & X509_TRUST_DYNAMIC_NAME) {
-    OPENSSL_free(trtmp->name);
-  }
-  trtmp->name = name_dup;
-  // Keep the dynamic flag of existing entry
-  trtmp->flags &= X509_TRUST_DYNAMIC;
-  // Set all other flags
-  trtmp->flags |= flags;
-
-  trtmp->trust = id;
-  trtmp->check_trust = ck;
-  trtmp->arg1 = arg1;
-  trtmp->arg2 = arg2;
-
-  // If its a new entry manage the dynamic table
-  if (idx == -1) {
-    // TODO(davidben): This should be locked. Alternatively, remove the dynamic
-    // registration mechanism entirely. The trouble is there no way to pass in
-    // the various parameters into an |X509_VERIFY_PARAM| directly. You can only
-    // register it in the global table and get an ID.
-    if (!trtable && !(trtable = sk_X509_TRUST_new(tr_cmp))) {
-      trtable_free(trtmp);
-      return 0;
-    }
-    if (!sk_X509_TRUST_push(trtable, trtmp)) {
-      trtable_free(trtmp);
-      return 0;
-    }
-    sk_X509_TRUST_sort(trtable);
-  }
-  return 1;
-}
-
-static void trtable_free(X509_TRUST *p) {
-  if (!p) {
-    return;
-  }
-  if (p->flags & X509_TRUST_DYNAMIC) {
-    if (p->flags & X509_TRUST_DYNAMIC_NAME) {
-      OPENSSL_free(p->name);
-    }
-    OPENSSL_free(p);
-  }
-}
-
-void X509_TRUST_cleanup(void) {
-  unsigned int i;
-  for (i = 0; i < X509_TRUST_COUNT; i++) {
-    trtable_free(trstandard + i);
-  }
-  sk_X509_TRUST_pop_free(trtable, trtable_free);
-  trtable = NULL;
-}
-
 int X509_TRUST_get_flags(const X509_TRUST *xp) { return xp->flags; }
 
 char *X509_TRUST_get0_name(const X509_TRUST *xp) { return xp->name; }
diff --git a/include/openssl/x509.h b/include/openssl/x509.h
index aa219b1..b7352af 100644
--- a/include/openssl/x509.h
+++ b/include/openssl/x509.h
@@ -3137,11 +3137,6 @@
 #define X509_TRUST_MIN 1
 #define X509_TRUST_MAX 8
 
-
-// trust_flags values
-#define X509_TRUST_DYNAMIC 1
-#define X509_TRUST_DYNAMIC_NAME 2
-
 // check_trust return codes
 
 #define X509_TRUST_TRUSTED 1
@@ -3184,10 +3179,6 @@
 OPENSSL_EXPORT int X509_TRUST_get_count(void);
 OPENSSL_EXPORT X509_TRUST *X509_TRUST_get0(int idx);
 OPENSSL_EXPORT int X509_TRUST_get_by_id(int id);
-OPENSSL_EXPORT int X509_TRUST_add(int id, int flags,
-                                  int (*ck)(X509_TRUST *, X509 *, int),
-                                  const char *name, int arg1, void *arg2);
-OPENSSL_EXPORT void X509_TRUST_cleanup(void);
 OPENSSL_EXPORT int X509_TRUST_get_flags(const X509_TRUST *xp);
 OPENSSL_EXPORT char *X509_TRUST_get0_name(const X509_TRUST *xp);
 OPENSSL_EXPORT int X509_TRUST_get_trust(const X509_TRUST *xp);
@@ -3967,9 +3958,6 @@
 #define NS_OBJSIGN_CA 0x01
 #define NS_ANY_CA (NS_SSL_CA | NS_SMIME_CA | NS_OBJSIGN_CA)
 
-#define X509_PURPOSE_DYNAMIC 0x1
-#define X509_PURPOSE_DYNAMIC_NAME 0x2
-
 typedef struct x509_purpose_st {
   int purpose;
   int trust;  // Default trust ID
@@ -4237,15 +4225,9 @@
 OPENSSL_EXPORT X509_PURPOSE *X509_PURPOSE_get0(int idx);
 OPENSSL_EXPORT int X509_PURPOSE_get_by_sname(const char *sname);
 OPENSSL_EXPORT int X509_PURPOSE_get_by_id(int id);
-OPENSSL_EXPORT int X509_PURPOSE_add(int id, int trust, int flags,
-                                    int (*ck)(const X509_PURPOSE *,
-                                              const X509 *, int),
-                                    const char *name, const char *sname,
-                                    void *arg);
 OPENSSL_EXPORT char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp);
 OPENSSL_EXPORT char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp);
 OPENSSL_EXPORT int X509_PURPOSE_get_trust(const X509_PURPOSE *xp);
-OPENSSL_EXPORT void X509_PURPOSE_cleanup(void);
 OPENSSL_EXPORT int X509_PURPOSE_get_id(const X509_PURPOSE *);
 
 // Flags for X509_check_* functions