Do not access value.ptr with V_ASN1_BOOLEAN.
This fixes a bug in ASN1_TYPE_get. Partly imported from upstream's
261ec72d58af64327214a78ca1c54b169ad93c28, though I don't believe
ASN1_TYPE_set was broken per se. There's also a lot more than in that
commit.
I've added a test to ensure we maintain the unused bits invariant
anyway, in case external code relies on it. (The invariant comes from
the pointer being NULL-initialized and from ASN1_primitive_free zeroing
*pval on free.)
Change-Id: I4c0c57519a7628041d81c26cd850317e01409556
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46324
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc
index 210e57d..57641bb 100644
--- a/crypto/x509/x509_test.cc
+++ b/crypto/x509/x509_test.cc
@@ -3040,3 +3040,83 @@
}
}
}
+
+// Test that extracting fields of an |X509_ALGOR| works correctly.
+TEST(X509Test, X509AlgorExtract) {
+ static const char kTestOID[] = "1.2.840.113554.4.1.72585.2";
+ const struct {
+ int param_type;
+ std::vector<uint8_t> param_der;
+ } kTests[] = {
+ // No parameter.
+ {V_ASN1_UNDEF, {}},
+ // BOOLEAN { TRUE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0xff}},
+ // BOOLEAN { FALSE }
+ {V_ASN1_BOOLEAN, {0x01, 0x01, 0x00}},
+ // OCTET_STRING { "a" }
+ {V_ASN1_OCTET_STRING, {0x04, 0x01, 0x61}},
+ // BIT_STRING { `01` `00` }
+ {V_ASN1_BIT_STRING, {0x03, 0x02, 0x01, 0x00}},
+ // INTEGER { -1 }
+ {V_ASN1_INTEGER, {0x02, 0x01, 0xff}},
+ // OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585.2 }
+ {V_ASN1_OBJECT,
+ {0x06, 0x0c, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7,
+ 0x09, 0x02}},
+ // NULL {}
+ {V_ASN1_NULL, {0x05, 0x00}},
+ // SEQUENCE {}
+ {V_ASN1_SEQUENCE, {0x30, 0x00}},
+ // SET {}
+ {V_ASN1_SET, {0x31, 0x00}},
+ // [0] { UTF8String { "a" } }
+ {V_ASN1_OTHER, {0xa0, 0x03, 0x0c, 0x01, 0x61}},
+ };
+ for (const auto &t : kTests) {
+ SCOPED_TRACE(Bytes(t.param_der));
+
+ // Assemble an AlgorithmIdentifier with the parameter.
+ bssl::ScopedCBB cbb;
+ CBB seq, oid;
+ ASSERT_TRUE(CBB_init(cbb.get(), 64));
+ ASSERT_TRUE(CBB_add_asn1(cbb.get(), &seq, CBS_ASN1_SEQUENCE));
+ ASSERT_TRUE(CBB_add_asn1(&seq, &oid, CBS_ASN1_OBJECT));
+ ASSERT_TRUE(CBB_add_asn1_oid_from_text(&oid, kTestOID, strlen(kTestOID)));
+ ASSERT_TRUE(CBB_add_bytes(&seq, t.param_der.data(), t.param_der.size()));
+ ASSERT_TRUE(CBB_flush(cbb.get()));
+
+ const uint8_t *ptr = CBB_data(cbb.get());
+ bssl::UniquePtr<X509_ALGOR> alg(
+ d2i_X509_ALGOR(nullptr, &ptr, CBB_len(cbb.get())));
+ ASSERT_TRUE(alg);
+
+ const ASN1_OBJECT *obj;
+ int param_type;
+ const void *param_value;
+ X509_ALGOR_get0(&obj, ¶m_type, ¶m_value, alg.get());
+
+ EXPECT_EQ(param_type, t.param_type);
+ char oid_buf[sizeof(kTestOID)];
+ ASSERT_EQ(int(sizeof(oid_buf) - 1),
+ OBJ_obj2txt(oid_buf, sizeof(oid_buf), obj,
+ /*always_return_oid=*/1));
+ EXPECT_STREQ(oid_buf, kTestOID);
+
+ // |param_type| and |param_value| must be consistent with |ASN1_TYPE|.
+ if (param_type == V_ASN1_UNDEF) {
+ EXPECT_EQ(nullptr, param_value);
+ } else {
+ bssl::UniquePtr<ASN1_TYPE> param(ASN1_TYPE_new());
+ ASSERT_TRUE(param);
+ ASSERT_TRUE(ASN1_TYPE_set1(param.get(), param_type, param_value));
+
+ uint8_t *param_der = nullptr;
+ int param_len = i2d_ASN1_TYPE(param.get(), ¶m_der);
+ ASSERT_GE(param_len, 0);
+ bssl::UniquePtr<uint8_t> free_param_der(param_der);
+
+ EXPECT_EQ(Bytes(param_der, param_len), Bytes(t.param_der));
+ }
+ }
+}