Rewrite X.509 policy tree logic.

This reimplements policy handling using a similar DAG structure as in
https://chromium-review.googlesource.com/c/chromium/src/+/4111415. The
main difference is that, being C, we don't have std::set or std::map
easily available. But the algorithm can be implemented purely with
sorted lists, while remaining subquadratic.

This implementation relies on two assumptions:

1. We do not return the policy tree. This was removed in
   https://boringssl-review.googlesource.com/c/boringssl/+/53327

2. We do not return the final set of certificate policies. I.e.,
   certificate policy checking is only used for evaluating policy
   constraints and X509_V_FLAG_EXPLICIT_POLICY.

The second assumption is not very important. It mostly simplifies
has_explicit_policy slightly.

In addition, this new implementation removes the per-certificate policy
cache. Instead, we just process the policy extensions anew on
certificate verification. This avoids a mess of threading complexity,
including a race condition in the old logic. See
https://boringssl-review.googlesource.com/c/boringssl/+/55762 for a
description of the race condition.

Change-Id: Ifba9037588ecff5eb6ed3c34c8bd7611f60013a6
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/56036
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index aba608e..e4af13e 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -5518,6 +5518,90 @@
              }));
 }
 
+#if defined(OPENSSL_THREADS)
+// A similar test to the above, but ensures the various bits of intermediate
+// state are computed safely.
+TEST(X509Test, PolicyThreads) {
+  const size_t kNumThreads = 10;
+
+  bssl::UniquePtr<ASN1_OBJECT> oid1(
+      OBJ_txt2obj("1.2.840.113554.4.1.72585.2.1", /*dont_search_names=*/1));
+  ASSERT_TRUE(oid1);
+  bssl::UniquePtr<ASN1_OBJECT> oid2(
+      OBJ_txt2obj("1.2.840.113554.4.1.72585.2.2", /*dont_search_names=*/1));
+  ASSERT_TRUE(oid2);
+  bssl::UniquePtr<ASN1_OBJECT> oid3(
+      OBJ_txt2obj("1.2.840.113554.4.1.72585.2.3", /*dont_search_names=*/1));
+  ASSERT_TRUE(oid3);
+
+  auto set_policies = [](X509_VERIFY_PARAM *param,
+                         std::vector<const ASN1_OBJECT *> oids) {
+    for (const ASN1_OBJECT *oid : oids) {
+      bssl::UniquePtr<ASN1_OBJECT> copy(OBJ_dup(oid));
+      ASSERT_TRUE(copy);
+      ASSERT_TRUE(X509_VERIFY_PARAM_add0_policy(param, copy.get()));
+      copy.release();  // |X509_VERIFY_PARAM_add0_policy| takes ownership on
+                       // success.
+    }
+  };
+
+  {
+    bssl::UniquePtr<X509> root(
+        CertFromPEM(GetTestData("crypto/x509/test/policy_root.pem").c_str()));
+    ASSERT_TRUE(root);
+    bssl::UniquePtr<X509> intermediate(CertFromPEM(
+        GetTestData("crypto/x509/test/policy_intermediate.pem").c_str()));
+    ASSERT_TRUE(intermediate);
+    bssl::UniquePtr<X509> leaf(
+        CertFromPEM(GetTestData("crypto/x509/test/policy_leaf.pem").c_str()));
+    ASSERT_TRUE(leaf);
+
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < kNumThreads; i++) {
+      threads.emplace_back([&] {
+        EXPECT_EQ(
+            X509_V_OK,
+            Verify(leaf.get(), {root.get()}, {intermediate.get()}, /*crls=*/{},
+                   X509_V_FLAG_EXPLICIT_POLICY, [&](X509_VERIFY_PARAM *param) {
+                     set_policies(param, {oid1.get()});
+                   }));
+      });
+    }
+    for (auto &thread : threads) {
+      thread.join();
+    }
+  }
+
+  {
+    bssl::UniquePtr<X509> root(
+        CertFromPEM(GetTestData("crypto/x509/test/policy_root.pem").c_str()));
+    ASSERT_TRUE(root);
+    bssl::UniquePtr<X509> intermediate(CertFromPEM(
+        GetTestData("crypto/x509/test/policy_intermediate.pem").c_str()));
+    ASSERT_TRUE(intermediate);
+    bssl::UniquePtr<X509> leaf_invalid(CertFromPEM(
+        GetTestData("crypto/x509/test/policy_leaf_invalid.pem").c_str()));
+    ASSERT_TRUE(leaf_invalid);
+
+
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < kNumThreads; i++) {
+      threads.emplace_back([&] {
+        EXPECT_EQ(X509_V_ERR_INVALID_POLICY_EXTENSION,
+                  Verify(leaf_invalid.get(), {root.get()}, {intermediate.get()},
+                         /*crls=*/{}, X509_V_FLAG_EXPLICIT_POLICY,
+                         [&](X509_VERIFY_PARAM *param) {
+                           set_policies(param, {oid1.get()});
+                         }));
+      });
+    }
+    for (auto &thread : threads) {
+      thread.join();
+    }
+  }
+}
+#endif  // OPENSSL_THREADS
+
 TEST(X509Test, ExtensionFromConf) {
   static const char kTestOID[] = "1.2.840.113554.4.1.72585.2";
   const struct {