Define CBS/CBB tags as uint32_t with a typedef.

We use unsigned, but we actually assume it is 32-bit for the bit-packing
strategy. But also introduce a typedef to hint that callers shouldn't
treat it as an arbitrary 32-bit integer. A typedef would also allow us
to extend to uint64_t in the future, if we ever need to.

Update-Note: Some APIs switch from unsigned * to uint32_t * out
pointers. This is only source-compatible if unsigned and uint32_t are
the exact same type. The CQ suggests this is indeed true. If they are
not, replace unsigned with CBS_ASN1_TAG to fix the build.

Bug: 525
Change-Id: I45cbe127c1aa252f5f6a169dca2e44d1e6e1d669
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/54986
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/asn1_lib.c b/crypto/asn1/asn1_lib.c
index a0e8f48..73f828e 100644
--- a/crypto/asn1/asn1_lib.c
+++ b/crypto/asn1/asn1_lib.c
@@ -117,7 +117,7 @@
   // signature fields (see b/18228011). Make this only apply to that field,
   // while requiring DER elsewhere. Better yet, it should be limited to an
   // preprocessing step in that part of Android.
-  unsigned tag;
+  CBS_ASN1_TAG tag;
   size_t header_len;
   int indefinite;
   CBS cbs, body;
diff --git a/crypto/bytestring/ber.c b/crypto/bytestring/ber.c
index dc707b9..5d43d0b 100644
--- a/crypto/bytestring/ber.c
+++ b/crypto/bytestring/ber.c
@@ -24,11 +24,11 @@
 // kMaxDepth is a just a sanity limit. The code should be such that the length
 // of the input being processes always decreases. None the less, a very large
 // input could otherwise cause the stack to overflow.
-static const unsigned kMaxDepth = 2048;
+static const uint32_t kMaxDepth = 2048;
 
 // is_string_type returns one if |tag| is a string type and zero otherwise. It
 // ignores the constructed bit.
-static int is_string_type(unsigned tag) {
+static int is_string_type(CBS_ASN1_TAG tag) {
   // While BER supports constructed BIT STRINGS, OpenSSL misparses them. To
   // avoid acting on an ambiguous input, we do not support constructed BIT
   // STRINGS. See https://github.com/openssl/openssl/issues/12810.
@@ -55,7 +55,7 @@
 // depending on whether an indefinite length element or constructed string was
 // found. The value of |orig_in| is not changed. It returns one on success (i.e.
 // |*ber_found| was set) and zero on error.
-static int cbs_find_ber(const CBS *orig_in, int *ber_found, unsigned depth) {
+static int cbs_find_ber(const CBS *orig_in, int *ber_found, uint32_t depth) {
   CBS in;
 
   if (depth > kMaxDepth) {
@@ -67,7 +67,7 @@
 
   while (CBS_len(&in) > 0) {
     CBS contents;
-    unsigned tag;
+    CBS_ASN1_TAG tag;
     size_t header_len;
     int indefinite;
     if (!CBS_get_any_ber_asn1_element(&in, &contents, &tag, &header_len,
@@ -110,8 +110,8 @@
 // constructed string. If |looking_for_eoc| is set then any EOC elements found
 // will cause the function to return after consuming it. It returns one on
 // success and zero on error.
-static int cbs_convert_ber(CBS *in, CBB *out, unsigned string_tag,
-                           char looking_for_eoc, unsigned depth) {
+static int cbs_convert_ber(CBS *in, CBB *out, CBS_ASN1_TAG string_tag,
+                           int looking_for_eoc, uint32_t depth) {
   assert(!(string_tag & CBS_ASN1_CONSTRUCTED));
 
   if (depth > kMaxDepth) {
@@ -124,7 +124,7 @@
     }
 
     CBS contents;
-    unsigned tag, child_string_tag = string_tag;
+    CBS_ASN1_TAG tag, child_string_tag = string_tag;
     size_t header_len;
     int indefinite;
     CBB *out_contents, out_contents_storage;
@@ -142,7 +142,7 @@
       }
       out_contents = out;
     } else {
-      unsigned out_tag = tag;
+      CBS_ASN1_TAG out_tag = tag;
       if ((tag & CBS_ASN1_CONSTRUCTED) && is_string_type(tag)) {
         // If a constructed string, clear the constructed bit and inform
         // children to concatenate bodies.
@@ -221,7 +221,8 @@
 }
 
 int CBS_get_asn1_implicit_string(CBS *in, CBS *out, uint8_t **out_storage,
-                                 unsigned outer_tag, unsigned inner_tag) {
+                                 CBS_ASN1_TAG outer_tag,
+                                 CBS_ASN1_TAG inner_tag) {
   assert(!(outer_tag & CBS_ASN1_CONSTRUCTED));
   assert(!(inner_tag & CBS_ASN1_CONSTRUCTED));
   assert(is_string_type(inner_tag));
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc
index c14e88a..e35b1bc 100644
--- a/crypto/bytestring/bytestring_test.cc
+++ b/crypto/bytestring/bytestring_test.cc
@@ -249,7 +249,7 @@
   EXPECT_FALSE(CBS_get_optional_asn1_uint64(
       &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
 
-  unsigned tag;
+  CBS_ASN1_TAG tag;
   CBS_init(&data, kData1, sizeof(kData1));
   ASSERT_TRUE(CBS_get_any_asn1(&data, &contents, &tag));
   EXPECT_EQ(CBS_ASN1_SEQUENCE, tag);
@@ -267,7 +267,7 @@
 TEST(CBSTest, ParseASN1Tag) {
   const struct {
     bool ok;
-    unsigned tag;
+    CBS_ASN1_TAG tag;
     std::vector<uint8_t> in;
   } kTests[] = {
       {true, CBS_ASN1_SEQUENCE, {0x30, 0}},
@@ -278,9 +278,9 @@
       {true,
        CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff,
        {0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 0}},
-      // Tag number fits in unsigned but not |CBS_ASN1_TAG_NUMBER_MASK|.
+      // Tag number fits in |uint32_t| but not |CBS_ASN1_TAG_NUMBER_MASK|.
       {false, 0, {0xff, 0x82, 0xff, 0xff, 0xff, 0x7f, 0}},
-      // Tag number does not fit in unsigned.
+      // Tag number does not fit in |uint32_t|.
       {false, 0, {0xff, 0x90, 0x80, 0x80, 0x80, 0, 0}},
       // Tag number is not minimally-encoded
       {false, 0, {0x5f, 0x80, 0x1f, 0}},
@@ -289,7 +289,7 @@
   };
   for (const auto &t : kTests) {
     SCOPED_TRACE(Bytes(t.in));
-    unsigned tag;
+    CBS_ASN1_TAG tag;
     CBS cbs, child;
     CBS_init(&cbs, t.in.data(), t.in.size());
     ASSERT_EQ(t.ok, !!CBS_get_any_asn1(&cbs, &child, &tag));
@@ -702,7 +702,7 @@
   bool ok;
   bool ber_found;
   bool indefinite;
-  unsigned tag;
+  CBS_ASN1_TAG tag;
 };
 
 static const BERTest kBERTests[] = {
@@ -748,7 +748,7 @@
     ASSERT_TRUE(DecodeHex(&in_bytes, test.in_hex));
     CBS in(in_bytes);
     CBS out;
-    unsigned tag;
+    CBS_ASN1_TAG tag;
     size_t header_len;
     int ber_found;
     int indefinite;
diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c
index d768942..86625fe 100644
--- a/crypto/bytestring/cbb.c
+++ b/crypto/bytestring/cbb.c
@@ -333,14 +333,14 @@
   return 1;
 }
 
-int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
+int CBB_add_asn1(CBB *cbb, CBB *out_contents, CBS_ASN1_TAG tag) {
   if (!CBB_flush(cbb)) {
     return 0;
   }
 
   // Split the tag into leading bits and tag number.
   uint8_t tag_bits = (tag >> CBS_ASN1_TAG_SHIFT) & 0xe0;
-  unsigned tag_number = tag & CBS_ASN1_TAG_NUMBER_MASK;
+  CBS_ASN1_TAG tag_number = tag & CBS_ASN1_TAG_NUMBER_MASK;
   if (tag_number >= 0x1f) {
     // Set all the bits in the tag number to signal high tag number form.
     if (!CBB_add_u8(cbb, tag_bits | 0x1f) ||
@@ -470,7 +470,7 @@
   return CBB_add_asn1_uint64_with_tag(cbb, value, CBS_ASN1_INTEGER);
 }
 
-int CBB_add_asn1_uint64_with_tag(CBB *cbb, uint64_t value, unsigned tag) {
+int CBB_add_asn1_uint64_with_tag(CBB *cbb, uint64_t value, CBS_ASN1_TAG tag) {
   CBB child;
   if (!CBB_add_asn1(cbb, &child, tag)) {
     return 0;
@@ -508,7 +508,7 @@
   return CBB_add_asn1_int64_with_tag(cbb, value, CBS_ASN1_INTEGER);
 }
 
-int CBB_add_asn1_int64_with_tag(CBB *cbb, int64_t value, unsigned tag) {
+int CBB_add_asn1_int64_with_tag(CBB *cbb, int64_t value, CBS_ASN1_TAG tag) {
   if (value >= 0) {
     return CBB_add_asn1_uint64_with_tag(cbb, (uint64_t)value, tag);
   }
diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c
index ddf1f67..c28f08d 100644
--- a/crypto/bytestring/cbs.c
+++ b/crypto/bytestring/cbs.c
@@ -254,7 +254,7 @@
   return 1;
 }
 
-static int parse_asn1_tag(CBS *cbs, unsigned *out) {
+static int parse_asn1_tag(CBS *cbs, CBS_ASN1_TAG *out) {
   uint8_t tag_byte;
   if (!CBS_get_u8(cbs, &tag_byte)) {
     return 0;
@@ -266,8 +266,8 @@
   // If the number portion is 31 (0x1f, the largest value that fits in the
   // allotted bits), then the tag is more than one byte long and the
   // continuation bytes contain the tag number.
-  unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
-  unsigned tag_number = tag_byte & 0x1f;
+  CBS_ASN1_TAG tag = ((CBS_ASN1_TAG)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
+  CBS_ASN1_TAG tag_number = tag_byte & 0x1f;
   if (tag_number == 0x1f) {
     uint64_t v;
     if (!parse_base128_integer(cbs, &v) ||
@@ -277,7 +277,7 @@
         v < 0x1f) {
       return 0;
     }
-    tag_number = (unsigned)v;
+    tag_number = (CBS_ASN1_TAG)v;
   }
 
   tag |= tag_number;
@@ -293,7 +293,7 @@
   return 1;
 }
 
-static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, CBS_ASN1_TAG *out_tag,
                                     size_t *out_header_len, int *out_ber_found,
                                     int *out_indefinite, int ber_ok) {
   CBS header = *cbs;
@@ -310,7 +310,7 @@
     assert(out_indefinite == NULL);
   }
 
-  unsigned tag;
+  CBS_ASN1_TAG tag;
   if (!parse_asn1_tag(&header, &tag)) {
     return 0;
   }
@@ -394,7 +394,7 @@
   return CBS_get_bytes(cbs, out, len);
 }
 
-int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag) {
+int CBS_get_any_asn1(CBS *cbs, CBS *out, CBS_ASN1_TAG *out_tag) {
   size_t header_len;
   if (!CBS_get_any_asn1_element(cbs, out, out_tag, &header_len)) {
     return 0;
@@ -408,13 +408,13 @@
   return 1;
 }
 
-int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+int CBS_get_any_asn1_element(CBS *cbs, CBS *out, CBS_ASN1_TAG *out_tag,
                                     size_t *out_header_len) {
   return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, NULL, NULL,
                                   /*ber_ok=*/0);
 }
 
-int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out, CBS_ASN1_TAG *out_tag,
                                  size_t *out_header_len, int *out_ber_found,
                                  int *out_indefinite) {
   int ber_found_temp;
@@ -424,10 +424,10 @@
       /*ber_ok=*/1);
 }
 
-static int cbs_get_asn1(CBS *cbs, CBS *out, unsigned tag_value,
+static int cbs_get_asn1(CBS *cbs, CBS *out, CBS_ASN1_TAG tag_value,
                         int skip_header) {
   size_t header_len;
-  unsigned tag;
+  CBS_ASN1_TAG tag;
   CBS throwaway;
 
   if (out == NULL) {
@@ -447,21 +447,21 @@
   return 1;
 }
 
-int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value) {
+int CBS_get_asn1(CBS *cbs, CBS *out, CBS_ASN1_TAG tag_value) {
   return cbs_get_asn1(cbs, out, tag_value, 1 /* skip header */);
 }
 
-int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value) {
+int CBS_get_asn1_element(CBS *cbs, CBS *out, CBS_ASN1_TAG tag_value) {
   return cbs_get_asn1(cbs, out, tag_value, 0 /* include header */);
 }
 
-int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) {
+int CBS_peek_asn1_tag(const CBS *cbs, CBS_ASN1_TAG tag_value) {
   if (CBS_len(cbs) < 1) {
     return 0;
   }
 
   CBS copy = *cbs;
-  unsigned actual_tag;
+  CBS_ASN1_TAG actual_tag;
   return parse_asn1_tag(&copy, &actual_tag) && tag_value == actual_tag;
 }
 
@@ -524,7 +524,7 @@
   return 1;
 }
 
-int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) {
+int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, CBS_ASN1_TAG tag) {
   int present = 0;
 
   if (CBS_peek_asn1_tag(cbs, tag)) {
@@ -542,7 +542,7 @@
 }
 
 int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present,
-                                       unsigned tag) {
+                                       CBS_ASN1_TAG tag) {
   CBS child;
   int present;
   if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
@@ -563,7 +563,7 @@
   return 1;
 }
 
-int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
+int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, CBS_ASN1_TAG tag,
                                  uint64_t default_value) {
   CBS child;
   int present;
@@ -581,7 +581,7 @@
   return 1;
 }
 
-int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+int CBS_get_optional_asn1_bool(CBS *cbs, int *out, CBS_ASN1_TAG tag,
                                int default_value) {
   CBS child, child2;
   int present;
diff --git a/crypto/bytestring/internal.h b/crypto/bytestring/internal.h
index 7ef0e21..ba23244 100644
--- a/crypto/bytestring/internal.h
+++ b/crypto/bytestring/internal.h
@@ -54,8 +54,8 @@
 // It returns one on success and zero otherwise.
 OPENSSL_EXPORT int CBS_get_asn1_implicit_string(CBS *in, CBS *out,
                                                 uint8_t **out_storage,
-                                                unsigned outer_tag,
-                                                unsigned inner_tag);
+                                                CBS_ASN1_TAG outer_tag,
+                                                CBS_ASN1_TAG inner_tag);
 
 // CBB_finish_i2d calls |CBB_finish| on |cbb| which must have been initialized
 // with |CBB_init|. If |outp| is not NULL then the result is written to |*outp|
diff --git a/crypto/ec_extra/ec_asn1.c b/crypto/ec_extra/ec_asn1.c
index 56cbbed..43132a6 100644
--- a/crypto/ec_extra/ec_asn1.c
+++ b/crypto/ec_extra/ec_asn1.c
@@ -67,9 +67,9 @@
 #include "../internal.h"
 
 
-static const unsigned kParametersTag =
+static const CBS_ASN1_TAG kParametersTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 0;
-static const unsigned kPublicKeyTag =
+static const CBS_ASN1_TAG kPublicKeyTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
 
 EC_KEY *EC_KEY_parse_private_key(CBS *cbs, const EC_GROUP *group) {
diff --git a/fuzz/der_roundtrip.cc b/fuzz/der_roundtrip.cc
index b88a7d6..03fa4c3 100644
--- a/fuzz/der_roundtrip.cc
+++ b/fuzz/der_roundtrip.cc
@@ -22,7 +22,7 @@
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *buf, size_t len) {
   CBS cbs, body;
-  unsigned tag;
+  CBS_ASN1_TAG tag;
   CBS_init(&cbs, buf, len);
   if (CBS_get_any_asn1(&cbs, &body, &tag)) {
     // DER has a unique encoding, so any parsed input should round-trip
diff --git a/include/openssl/base.h b/include/openssl/base.h
index 1e61e98..a2fb76b 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -335,6 +335,10 @@
 // are sizes of or indices into C objects, can be converted without overflow.
 typedef ptrdiff_t ossl_ssize_t;
 
+// CBS_ASN1_TAG is the type used by |CBS| and |CBB| for ASN.1 tags. See that
+// header for details. This type is defined in base.h as a forward declaration.
+typedef uint32_t CBS_ASN1_TAG;
+
 // CRYPTO_THREADID is a dummy value.
 typedef int CRYPTO_THREADID;
 
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 5496644..28297d4 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -169,8 +169,8 @@
 // SEQUENCE, branching on CHOICEs or OPTIONAL fields, checking for trailing
 // data, and handling explict vs. implicit tagging.
 //
-// Tags are represented as |unsigned| values in memory. The upper few bits store
-// the class and constructed bit, and the remaining bits store the tag
+// Tags are represented as |CBS_ASN1_TAG| values in memory. The upper few bits
+// store the class and constructed bit, and the remaining bits store the tag
 // number. Note this differs from the DER serialization, to support tag numbers
 // beyond 31. Consumers must use the constants defined below to decompose or
 // assemble tags.
@@ -231,31 +231,33 @@
 // including tag and length bytes) and advances |cbs| over it. The ASN.1
 // element must match |tag_value|. It returns one on success and zero
 // on error.
-OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value);
+OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, CBS_ASN1_TAG tag_value);
 
 // CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the
 // ASN.1 header bytes too.
-OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value);
+OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out,
+                                        CBS_ASN1_TAG tag_value);
 
 // CBS_peek_asn1_tag looks ahead at the next ASN.1 tag and returns one
 // if the next ASN.1 element on |cbs| would have tag |tag_value|. If
 // |cbs| is empty or the tag does not match, it returns zero. Note: if
 // it returns one, CBS_get_asn1 may still fail if the rest of the
 // element is malformed.
-OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value);
+OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, CBS_ASN1_TAG tag_value);
 
 // CBS_get_any_asn1 sets |*out| to contain the next ASN.1 element from |*cbs|
 // (not including tag and length bytes), sets |*out_tag| to the tag number, and
 // advances |*cbs|. It returns one on success and zero on error. Either of |out|
 // and |out_tag| may be NULL to ignore the value.
-OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag);
+OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out,
+                                    CBS_ASN1_TAG *out_tag);
 
 // CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from
 // |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to
 // the tag number and |*out_header_len| to the length of the ASN.1 header. Each
 // of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value.
 OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out,
-                                            unsigned *out_tag,
+                                            CBS_ASN1_TAG *out_tag,
                                             size_t *out_header_len);
 
 // CBS_get_any_ber_asn1_element acts the same as |CBS_get_any_asn1_element| but
@@ -271,7 +273,7 @@
 // element. Callers parsing indefinite-length encoding must check for EOC
 // separately.
 OPENSSL_EXPORT int CBS_get_any_ber_asn1_element(CBS *cbs, CBS *out,
-                                                unsigned *out_tag,
+                                                CBS_ASN1_TAG *out_tag,
                                                 size_t *out_header_len,
                                                 int *out_ber_found,
                                                 int *out_indefinite);
@@ -297,7 +299,7 @@
 // one, otherwise zero. It returns one on success, whether or not the element
 // was present, and zero on decode failure.
 OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present,
-                                         unsigned tag);
+                                         CBS_ASN1_TAG tag);
 
 // CBS_get_optional_asn1_octet_string gets an optional
 // explicitly-tagged OCTET STRING from |cbs|. If present, it sets
@@ -307,7 +309,7 @@
 // present, and zero on decode failure.
 OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out,
                                                       int *out_present,
-                                                      unsigned tag);
+                                                      CBS_ASN1_TAG tag);
 
 // CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged
 // INTEGER from |cbs|. If present, it sets |*out| to the
@@ -315,7 +317,7 @@
 // on success, whether or not the element was present, and zero on
 // decode failure.
 OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out,
-                                                unsigned tag,
+                                                CBS_ASN1_TAG tag,
                                                 uint64_t default_value);
 
 // CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from
@@ -323,7 +325,8 @@
 // boolean. Otherwise, it sets |*out| to |default_value|. It returns one on
 // success, whether or not the element was present, and zero on decode
 // failure.
-OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
+OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out,
+                                              CBS_ASN1_TAG tag,
                                               int default_value);
 
 // CBS_is_valid_asn1_bitstring returns one if |cbs| is a valid ASN.1 BIT STRING
@@ -502,7 +505,7 @@
 // CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an
 // ASN.1 object can be written. The |tag| argument will be used as the tag for
 // the object. It returns one on success or zero on error.
-OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag);
+OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, CBS_ASN1_TAG tag);
 
 // CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on
 // success and zero otherwise.
@@ -574,7 +577,7 @@
 // |tag| as the tag instead of INTEGER. This is useful if the INTEGER type uses
 // implicit tagging.
 OPENSSL_EXPORT int CBB_add_asn1_uint64_with_tag(CBB *cbb, uint64_t value,
-                                                unsigned tag);
+                                                CBS_ASN1_TAG tag);
 
 // CBB_add_asn1_int64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1|
 // and writes |value| in its contents. It returns one on success and zero on
@@ -585,7 +588,7 @@
 // as the tag instead of INTEGER. This is useful if the INTEGER type uses
 // implicit tagging.
 OPENSSL_EXPORT int CBB_add_asn1_int64_with_tag(CBB *cbb, int64_t value,
-                                               unsigned tag);
+                                               CBS_ASN1_TAG tag);
 
 // CBB_add_asn1_octet_string writes an ASN.1 OCTET STRING into |cbb| with the
 // given contents. It returns one on success and zero on error.
diff --git a/ssl/handoff.cc b/ssl/handoff.cc
index dd24811..b885c4c 100644
--- a/ssl/handoff.cc
+++ b/ssl/handoff.cc
@@ -26,7 +26,7 @@
 constexpr int kHandoffVersion = 0;
 constexpr int kHandbackVersion = 0;
 
-static const unsigned kHandoffTagALPS = CBS_ASN1_CONTEXT_SPECIFIC | 0;
+static const CBS_ASN1_TAG kHandoffTagALPS = CBS_ASN1_CONTEXT_SPECIFIC | 0;
 
 // early_data_t represents the state of early data in a more compact way than
 // the 3 bits used by the implementation.
@@ -823,19 +823,22 @@
 // }
 
 // HandshakeHints tags.
-static const unsigned kServerRandomTLS13Tag = CBS_ASN1_CONTEXT_SPECIFIC | 0;
-static const unsigned kKeyShareHintTag =
+static const CBS_ASN1_TAG kServerRandomTLS13Tag =
+    CBS_ASN1_CONTEXT_SPECIFIC | 0;
+static const CBS_ASN1_TAG kKeyShareHintTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
-static const unsigned kSignatureHintTag =
+static const CBS_ASN1_TAG kSignatureHintTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2;
-static const unsigned kDecryptedPSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 3;
-static const unsigned kIgnorePSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 4;
-static const unsigned kCompressCertificateTag = CBS_ASN1_CONTEXT_SPECIFIC | 5;
-static const unsigned kServerRandomTLS12Tag = CBS_ASN1_CONTEXT_SPECIFIC | 6;
-static const unsigned kECDHEHintTag = CBS_ASN1_CONSTRUCTED | 7;
-static const unsigned kDecryptedTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 8;
-static const unsigned kRenewTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 9;
-static const unsigned kIgnoreTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 10;
+static const CBS_ASN1_TAG kDecryptedPSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 3;
+static const CBS_ASN1_TAG kIgnorePSKTag = CBS_ASN1_CONTEXT_SPECIFIC | 4;
+static const CBS_ASN1_TAG kCompressCertificateTag =
+    CBS_ASN1_CONTEXT_SPECIFIC | 5;
+static const CBS_ASN1_TAG kServerRandomTLS12Tag =
+    CBS_ASN1_CONTEXT_SPECIFIC | 6;
+static const CBS_ASN1_TAG kECDHEHintTag = CBS_ASN1_CONSTRUCTED | 7;
+static const CBS_ASN1_TAG kDecryptedTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 8;
+static const CBS_ASN1_TAG kRenewTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 9;
+static const CBS_ASN1_TAG kIgnoreTicketTag = CBS_ASN1_CONTEXT_SPECIFIC | 10;
 
 int SSL_serialize_handshake_hints(const SSL *ssl, CBB *out) {
   const SSL_HANDSHAKE *hs = ssl->s3->hs.get();
@@ -954,7 +957,7 @@
 }
 
 static bool get_optional_implicit_null(CBS *cbs, bool *out_present,
-                                       unsigned tag) {
+                                       CBS_ASN1_TAG tag) {
   CBS value;
   int present;
   if (!CBS_get_optional_asn1(cbs, &value, &present, tag) ||
diff --git a/ssl/internal.h b/ssl/internal.h
index 8ef1509..4d9ab49 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1313,7 +1313,8 @@
 // ssl_cert_check_key_usage parses the DER-encoded, X.509 certificate in |in|
 // and returns true if doesn't specify a key usage or, if it does, if it
 // includes |bit|. Otherwise it pushes to the error queue and returns false.
-bool ssl_cert_check_key_usage(const CBS *in, enum ssl_key_usage_t bit);
+OPENSSL_EXPORT bool ssl_cert_check_key_usage(const CBS *in,
+                                             enum ssl_key_usage_t bit);
 
 // ssl_cert_parse_pubkey extracts the public key from the DER-encoded, X.509
 // certificate in |in|. It returns an allocated |EVP_PKEY| or else returns
diff --git a/ssl/ssl_asn1.cc b/ssl/ssl_asn1.cc
index 0426437..c25dbd8 100644
--- a/ssl/ssl_asn1.cc
+++ b/ssl/ssl_asn1.cc
@@ -150,57 +150,57 @@
 
 static const unsigned kVersion = 1;
 
-static const unsigned kTimeTag =
+static const CBS_ASN1_TAG kTimeTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1;
-static const unsigned kTimeoutTag =
+static const CBS_ASN1_TAG kTimeoutTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2;
-static const unsigned kPeerTag =
+static const CBS_ASN1_TAG kPeerTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3;
-static const unsigned kSessionIDContextTag =
+static const CBS_ASN1_TAG kSessionIDContextTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 4;
-static const unsigned kVerifyResultTag =
+static const CBS_ASN1_TAG kVerifyResultTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 5;
-static const unsigned kHostNameTag =
+static const CBS_ASN1_TAG kHostNameTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 6;
-static const unsigned kPSKIdentityTag =
+static const CBS_ASN1_TAG kPSKIdentityTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 8;
-static const unsigned kTicketLifetimeHintTag =
+static const CBS_ASN1_TAG kTicketLifetimeHintTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 9;
-static const unsigned kTicketTag =
+static const CBS_ASN1_TAG kTicketTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 10;
-static const unsigned kPeerSHA256Tag =
+static const CBS_ASN1_TAG kPeerSHA256Tag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 13;
-static const unsigned kOriginalHandshakeHashTag =
+static const CBS_ASN1_TAG kOriginalHandshakeHashTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 14;
-static const unsigned kSignedCertTimestampListTag =
+static const CBS_ASN1_TAG kSignedCertTimestampListTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15;
-static const unsigned kOCSPResponseTag =
+static const CBS_ASN1_TAG kOCSPResponseTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16;
-static const unsigned kExtendedMasterSecretTag =
+static const CBS_ASN1_TAG kExtendedMasterSecretTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
-static const unsigned kGroupIDTag =
+static const CBS_ASN1_TAG kGroupIDTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18;
-static const unsigned kCertChainTag =
+static const CBS_ASN1_TAG kCertChainTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19;
-static const unsigned kTicketAgeAddTag =
+static const CBS_ASN1_TAG kTicketAgeAddTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21;
-static const unsigned kIsServerTag =
+static const CBS_ASN1_TAG kIsServerTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 22;
-static const unsigned kPeerSignatureAlgorithmTag =
+static const CBS_ASN1_TAG kPeerSignatureAlgorithmTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 23;
-static const unsigned kTicketMaxEarlyDataTag =
+static const CBS_ASN1_TAG kTicketMaxEarlyDataTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24;
-static const unsigned kAuthTimeoutTag =
+static const CBS_ASN1_TAG kAuthTimeoutTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 25;
-static const unsigned kEarlyALPNTag =
+static const CBS_ASN1_TAG kEarlyALPNTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26;
-static const unsigned kIsQuicTag =
+static const CBS_ASN1_TAG kIsQuicTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 27;
-static const unsigned kQuicEarlyDataContextTag =
+static const CBS_ASN1_TAG kQuicEarlyDataContextTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 28;
-static const unsigned kLocalALPSTag =
+static const CBS_ASN1_TAG kLocalALPSTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 29;
-static const unsigned kPeerALPSTag =
+static const CBS_ASN1_TAG kPeerALPSTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 30;
 
 static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, CBB *cbb,
@@ -438,7 +438,8 @@
 // tagged with |tag| from |cbs| and saves it in |*out|. If the element was not
 // found, it sets |*out| to NULL. It returns one on success, whether or not the
 // element was found, and zero on decode error.
-static int SSL_SESSION_parse_string(CBS *cbs, UniquePtr<char> *out, unsigned tag) {
+static int SSL_SESSION_parse_string(CBS *cbs, UniquePtr<char> *out,
+                                    CBS_ASN1_TAG tag) {
   CBS value;
   int present;
   if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) {
@@ -466,7 +467,7 @@
 // tagged with |tag| from |cbs| and stows it in |*out|. It returns one on
 // success, whether or not the element was found, and zero on decode error.
 static bool SSL_SESSION_parse_octet_string(CBS *cbs, Array<uint8_t> *out,
-                                           unsigned tag) {
+                                           CBS_ASN1_TAG tag) {
   CBS value;
   if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
@@ -477,7 +478,7 @@
 
 static int SSL_SESSION_parse_crypto_buffer(CBS *cbs,
                                            UniquePtr<CRYPTO_BUFFER> *out,
-                                           unsigned tag,
+                                           CBS_ASN1_TAG tag,
                                            CRYPTO_BUFFER_POOL *pool) {
   if (!CBS_peek_asn1_tag(cbs, tag)) {
     return 1;
@@ -500,8 +501,10 @@
 
 // SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING
 // explicitly tagged with |tag| of size at most |max_out|.
-static int SSL_SESSION_parse_bounded_octet_string(
-    CBS *cbs, uint8_t *out, uint8_t *out_len, uint8_t max_out, unsigned tag) {
+static int SSL_SESSION_parse_bounded_octet_string(CBS *cbs, uint8_t *out,
+                                                  uint8_t *out_len,
+                                                  uint8_t max_out,
+                                                  CBS_ASN1_TAG tag) {
   CBS value;
   if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) ||
       CBS_len(&value) > max_out) {
@@ -513,7 +516,7 @@
   return 1;
 }
 
-static int SSL_SESSION_parse_long(CBS *cbs, long *out, unsigned tag,
+static int SSL_SESSION_parse_long(CBS *cbs, long *out, CBS_ASN1_TAG tag,
                                   long default_value) {
   uint64_t value;
   if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
@@ -526,7 +529,7 @@
   return 1;
 }
 
-static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag,
+static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, CBS_ASN1_TAG tag,
                                  uint32_t default_value) {
   uint64_t value;
   if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,
@@ -539,7 +542,7 @@
   return 1;
 }
 
-static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag,
+static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, CBS_ASN1_TAG tag,
                                  uint16_t default_value) {
   uint64_t value;
   if (!CBS_get_optional_asn1_uint64(cbs, &value, tag,