runner: Switch to CertificatePropertyList for passing properties to the shim

One less thing we have to transcribe to command-line flags in the tests,
when we add a more complicated structurte. We'd prefer to have folks use
this format anyway, since it's extensible.

Bug: 524722668
Change-Id: Ibf10e4b35143ee31826e66dcc068a61e5e3c27b5
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/98587
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Lily Chen <chlily@google.com>
diff --git a/ssl/test/runner/certificate_selection_tests.go b/ssl/test/runner/certificate_selection_tests.go
index c0082be..5eeb186 100644
--- a/ssl/test/runner/certificate_selection_tests.go
+++ b/ssl/test/runner/certificate_selection_tests.go
@@ -21,7 +21,7 @@
 
 func canBeShimCertificate(c *Credential) bool {
 	// Some options can only be set with the credentials API.
-	return c.Type == CredentialTypeX509 && !c.MustMatchIssuer && c.TrustAnchorID == nil
+	return c.Type == CredentialTypeX509 && !c.MustMatchIssuer && c.Properties.Empty()
 }
 
 func addCertificateSelectionTests() {
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index ff2a825..a46c32f 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -18,6 +18,7 @@
 	"time"
 
 	"boringssl.googlesource.com/boringssl.git/ssl/test/runner/hpke"
+	"golang.org/x/crypto/cryptobyte"
 )
 
 const (
@@ -2433,6 +2434,31 @@
 	return supportedSignatureAlgorithms
 }
 
+const (
+	certPropTrustAnchorID uint16 = 0
+)
+
+type CertificatePropertyList struct {
+	TrustAnchorID []byte
+}
+
+func (c *CertificatePropertyList) Empty() bool {
+	return len(c.TrustAnchorID) == 0
+}
+
+func (c *CertificatePropertyList) Marshal() []byte {
+	bb := cryptobyte.NewBuilder(nil)
+	bb.AddUint16LengthPrefixed(func(props *cryptobyte.Builder) {
+		if len(c.TrustAnchorID) != 0 {
+			props.AddUint16(certPropTrustAnchorID)
+			// The ID is encoded directly in the property data, with
+			// no additional length prefix.
+			addUint16LengthPrefixedBytes(props, c.TrustAnchorID)
+		}
+	})
+	return bb.BytesOrPanic()
+}
+
 type CredentialType int
 
 const (
@@ -2522,9 +2548,9 @@
 	// AppendToImportedPSKIdentity is a byte string that is appended to the
 	// imported PSK identity.
 	AppendToImportedPSKIdentity []byte
-	// TrustAnchorID, if not empty, is the trust anchor ID for the issuer
-	// of the certificate chain.
-	TrustAnchorID []byte
+	// Properties is the certificate properties (draft-ietf-tls-trust-anchor-ids)
+	// associated with this credential.
+	Properties CertificatePropertyList
 }
 
 func (c *Credential) WithSignatureAlgorithms(sigAlgs ...signatureAlgorithm) *Credential {
@@ -2560,7 +2586,7 @@
 
 func (c *Credential) WithTrustAnchorID(id []byte) *Credential {
 	ret := *c
-	ret.TrustAnchorID = id
+	ret.Properties.TrustAnchorID = id
 	ret.MustMatchIssuer = true
 	return &ret
 }
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 0f1fb47..eead92d 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -1184,9 +1184,9 @@
 		if config.Bugs.AlwaysMatchTrustAnchorID {
 			certMsg.matchedTrustAnchor = true
 		} else {
-			if hs.clientHello.trustAnchors != nil && useCert.TrustAnchorID != nil {
+			if hs.clientHello.trustAnchors != nil && useCert.Properties.TrustAnchorID != nil {
 				for _, id := range hs.clientHello.trustAnchors {
-					if bytes.Equal(useCert.TrustAnchorID, id) {
+					if bytes.Equal(useCert.Properties.TrustAnchorID, id) {
 						certMsg.matchedTrustAnchor = true
 					}
 				}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 69ec526..d9aa9b3 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -1613,7 +1613,9 @@
 	default:
 		panic(fmt.Sprintf("unknown PSK hash %s", cred.PSKHash))
 	}
-	handleBase64Field("trust-anchor-id", cred.TrustAnchorID)
+	if !cred.Properties.Empty() {
+		handleBase64Field("cert-properties", cred.Properties.Marshal())
+	}
 	return flags
 }
 
diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc
index 58f0c01..c15b2ab 100644
--- a/ssl/test/test_config.cc
+++ b/ssl/test/test_config.cc
@@ -629,7 +629,7 @@
         CredentialFlag(SetValueFlag("-psk-importer-sha384",
                                     &CredentialConfig::psk_hash, EVP_sha384())),
         CredentialFlag(
-            Base64Flag("-trust-anchor-id", &CredentialConfig::trust_anchor_id)),
+            Base64Flag("-cert-properties", &CredentialConfig::cert_properties)),
         IntFlag("-private-key-delay-ms", &TestConfig::private_key_delay_ms),
         BoolFlag("-resumption-across-names-enabled",
                  &TestConfig::resumption_across_names_enabled),
@@ -1640,10 +1640,12 @@
     SSL_CREDENTIAL_set_must_match_issuer(cred.get(), 1);
   }
 
-  if (!cred_config.trust_anchor_id.empty()) {
-    if (!SSL_CREDENTIAL_set1_trust_anchor_id(
-            cred.get(), cred_config.trust_anchor_id.data(),
-            cred_config.trust_anchor_id.size())) {
+  if (!cred_config.cert_properties.empty()) {
+    bssl::UniquePtr<CRYPTO_BUFFER> buf(
+        CRYPTO_BUFFER_new(cred_config.cert_properties.data(),
+                          cred_config.cert_properties.size(), nullptr));
+    if (buf == nullptr ||
+        !SSL_CREDENTIAL_set1_certificate_properties(cred.get(), buf.get())) {
       return nullptr;
     }
   }
diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h
index fea9848..f781a59 100644
--- a/ssl/test/test_config.h
+++ b/ssl/test/test_config.h
@@ -46,7 +46,7 @@
   std::vector<uint8_t> pake_client_id;
   std::vector<uint8_t> pake_server_id;
   std::vector<uint8_t> pake_password;
-  std::vector<uint8_t> trust_anchor_id;
+  std::vector<uint8_t> cert_properties;
   bool wrong_pake_role = false;
   std::vector<uint8_t> psk;
   std::vector<uint8_t> psk_identity;