Sort various X.509 global lists sooner

These functions need a lot more work, documentation, warnings
that using them isn't a good idea, and really we should just remove them
entirely.

But, for now, this is a minimal fix to the most egregious of issues: not
only are the functions themselves not thread-safe (i.e. you must call it
in some program-global initialization), but using them puts you in a
state where future uses of the X.509 library are not thread-safe! Fix
the latter by sorting the list at the point we're already mutating
things.

Re-sorting a list after every addition is not a particularly sensible
implementation, but we can assume these lists will only ever contain
O(1) entries.

(The sort calls date to
https://boringssl-review.googlesource.com/c/boringssl/+/27304, but the
issue was there before. Prior to that CL, sk_FOO_find implicitly sorted
the list. That CL made sk_FOO_find itself a const operation, necessary
for this, and just added explicit sk_FOO_sort calls to preserve the
existing behavior, initially.)

Change-Id: I063b8e708eaf17dfe66c5a3e8d33733adb3297e9
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58385
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c
index 1329a9f..553a0ae 100644
--- a/crypto/x509/x509_trs.c
+++ b/crypto/x509/x509_trs.c
@@ -152,7 +152,6 @@
   if (!trtable) {
     return -1;
   }
-  sk_X509_TRUST_sort(trtable);
   if (!sk_X509_TRUST_find(trtable, &idx, &tmp)) {
     return -1;
   }
@@ -216,6 +215,10 @@
 
   // 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;
@@ -224,6 +227,7 @@
       trtable_free(trtmp);
       return 0;
     }
+    sk_X509_TRUST_sort(trtable);
   }
   return 1;
 }
diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c
index d985cb7..f14a531 100644
--- a/crypto/x509/x509_vpm.c
+++ b/crypto/x509/x509_vpm.c
@@ -554,6 +554,8 @@
 }
 
 int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) {
+  // TODO(davidben): This should be locked. Alternatively, remove the dynamic
+  // registration mechanism entirely.
   X509_VERIFY_PARAM *ptmp;
   if (!param_table) {
     param_table = sk_X509_VERIFY_PARAM_new(param_cmp);
@@ -562,8 +564,6 @@
     }
   } else {
     size_t idx;
-
-    sk_X509_VERIFY_PARAM_sort(param_table);
     if (sk_X509_VERIFY_PARAM_find(param_table, &idx, param)) {
       ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx);
       X509_VERIFY_PARAM_free(ptmp);
@@ -573,6 +573,7 @@
   if (!sk_X509_VERIFY_PARAM_push(param_table, param)) {
     return 0;
   }
+  sk_X509_VERIFY_PARAM_sort(param_table);
   return 1;
 }
 
@@ -599,7 +600,6 @@
   pm.name = (char *)name;
   if (param_table) {
     size_t idx;
-    sk_X509_VERIFY_PARAM_sort(param_table);
     if (sk_X509_VERIFY_PARAM_find(param_table, &idx, &pm)) {
       return sk_X509_VERIFY_PARAM_value(param_table, idx);
     }
diff --git a/crypto/x509v3/v3_lib.c b/crypto/x509v3/v3_lib.c
index d006a5e..5a3c3e8 100644
--- a/crypto/x509v3/v3_lib.c
+++ b/crypto/x509v3/v3_lib.c
@@ -78,6 +78,7 @@
 }
 
 int X509V3_EXT_add(X509V3_EXT_METHOD *ext) {
+  // TODO(davidben): This should be locked. Also check for duplicates.
   if (!ext_list && !(ext_list = sk_X509V3_EXT_METHOD_new(ext_stack_cmp))) {
     ext_list_free(ext);
     return 0;
@@ -86,6 +87,7 @@
     ext_list_free(ext);
     return 0;
   }
+  sk_X509V3_EXT_METHOD_sort(ext_list);
   return 1;
 }
 
@@ -113,7 +115,6 @@
     return NULL;
   }
 
-  sk_X509V3_EXT_METHOD_sort(ext_list);
   if (!sk_X509V3_EXT_METHOD_find(ext_list, &idx, &tmp)) {
     return NULL;
   }
diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c
index 71b2c6d..8c254e8 100644
--- a/crypto/x509v3/v3_purp.c
+++ b/crypto/x509v3/v3_purp.c
@@ -201,7 +201,6 @@
     return -1;
   }
 
-  sk_X509_PURPOSE_sort(xptable);
   if (!sk_X509_PURPOSE_find(xptable, &idx, &tmp)) {
     return -1;
   }
@@ -267,6 +266,10 @@
 
   // 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;
@@ -275,6 +278,7 @@
       xptable_free(ptmp);
       return 0;
     }
+    sk_X509_PURPOSE_sort(xptable);
   }
   return 1;
 }