external/boringssl: Sync to 915c121bb5d424e09bf05c3aabf172a44e958e28.

This includes the following changes:

https://boringssl.googlesource.com/boringssl/+log/ea52ec98a56a40879b37493f3d1da1a1679e1fba..915c121bb5d424e09bf05c3aabf172a44e958e28

Test: BoringSSL CTS Presubmits
Change-Id: I3f5eba69372b484e19f4ca250c81f208aa5d3dc5
diff --git a/src/crypto/asn1/a_int.c b/src/crypto/asn1/a_int.c
index 8a4edd6..dd74550 100644
--- a/src/crypto/asn1/a_int.c
+++ b/src/crypto/asn1/a_int.c
@@ -347,40 +347,45 @@
 
 int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
 {
-    int j, k;
-    unsigned int i;
-    unsigned char buf[sizeof(long) + 1];
-    long d;
-
-    a->type = V_ASN1_INTEGER;
-    if (a->length < (int)(sizeof(long) + 1)) {
-        if (a->data != NULL)
-            OPENSSL_free(a->data);
-        if ((a->data =
-             (unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
-            OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
+    if (v >= 0) {
+        return ASN1_INTEGER_set_uint64(a, (uint64_t) v);
     }
-    if (a->data == NULL) {
+
+    if (!ASN1_INTEGER_set_uint64(a, 0 - (uint64_t) v)) {
+        return 0;
+    }
+
+    a->type = V_ASN1_NEG_INTEGER;
+    return 1;
+}
+
+int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v)
+{
+    uint8_t *const newdata = OPENSSL_malloc(sizeof(uint64_t));
+    if (newdata == NULL) {
         OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
-        return (0);
-    }
-    d = v;
-    if (d < 0) {
-        d = -d;
-        a->type = V_ASN1_NEG_INTEGER;
+        return 0;
     }
 
-    for (i = 0; i < sizeof(long); i++) {
-        if (d == 0)
+    OPENSSL_free(out->data);
+    out->data = newdata;
+    v = CRYPTO_bswap8(v);
+    memcpy(out->data, &v, sizeof(v));
+
+    out->type = V_ASN1_INTEGER;
+
+    size_t leading_zeros;
+    for (leading_zeros = 0; leading_zeros < sizeof(uint64_t) - 1;
+         leading_zeros++) {
+        if (out->data[leading_zeros] != 0) {
             break;
-        buf[i] = (int)d & 0xff;
-        d >>= 8;
+        }
     }
-    j = 0;
-    for (k = i - 1; k >= 0; k--)
-        a->data[j++] = buf[k];
-    a->length = j;
-    return (1);
+
+    out->length = sizeof(uint64_t) - leading_zeros;
+    OPENSSL_memmove(out->data, out->data + leading_zeros, out->length);
+
+    return 1;
 }
 
 long ASN1_INTEGER_get(const ASN1_INTEGER *a)
diff --git a/src/crypto/asn1/asn1_test.cc b/src/crypto/asn1/asn1_test.cc
index accf3ba..7c114dd 100644
--- a/src/crypto/asn1/asn1_test.cc
+++ b/src/crypto/asn1/asn1_test.cc
@@ -15,6 +15,7 @@
 #include <stdio.h>
 
 #include <gtest/gtest.h>
+#include <limits.h>
 
 #include <openssl/asn1.h>
 #include <openssl/err.h>
@@ -60,3 +61,30 @@
   EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
                                     obj->value.asn1_string->length));
 }
+
+TEST(ASN1Test, IntegerSetting) {
+  bssl::UniquePtr<ASN1_INTEGER> by_bn(M_ASN1_INTEGER_new());
+  bssl::UniquePtr<ASN1_INTEGER> by_long(M_ASN1_INTEGER_new());
+  bssl::UniquePtr<ASN1_INTEGER> by_uint64(M_ASN1_INTEGER_new());
+  bssl::UniquePtr<BIGNUM> bn(BN_new());
+
+  const std::vector<int64_t> kValues = {
+      LONG_MIN, -2, -1, 0, 1, 2, 0xff, 0x100, 0xffff, 0x10000, LONG_MAX,
+  };
+  for (const auto &i : kValues) {
+    SCOPED_TRACE(i);
+
+    ASSERT_EQ(1, ASN1_INTEGER_set(by_long.get(), i));
+    const uint64_t abs = i < 0 ? (0 - (uint64_t) i) : i;
+    ASSERT_TRUE(BN_set_u64(bn.get(), abs));
+    BN_set_negative(bn.get(), i < 0);
+    ASSERT_TRUE(BN_to_ASN1_INTEGER(bn.get(), by_bn.get()));
+
+    EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_long.get()));
+
+    if (i >= 0) {
+      ASSERT_EQ(1, ASN1_INTEGER_set_uint64(by_uint64.get(), i));
+      EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_uint64.get()));
+    }
+  }
+}
diff --git a/src/crypto/bytestring/ber.c b/src/crypto/bytestring/ber.c
index 4dc94f6..bb5e17c 100644
--- a/src/crypto/bytestring/ber.c
+++ b/src/crypto/bytestring/ber.c
@@ -29,10 +29,7 @@
 // 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) {
-  if ((tag & 0xc0) != 0) {
-    return 0;
-  }
-  switch (tag & 0x1f) {
+  switch (tag & ~CBS_ASN1_CONSTRUCTED) {
     case CBS_ASN1_BITSTRING:
     case CBS_ASN1_OCTETSTRING:
     case CBS_ASN1_UTF8STRING:
diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc
index 5a6a5c1..1969e73 100644
--- a/src/crypto/bytestring/bytestring_test.cc
+++ b/src/crypto/bytestring/bytestring_test.cc
@@ -123,27 +123,27 @@
   uint64_t value;
 
   CBS_init(&data, kData1, sizeof(kData1));
-  EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x1));
-  EXPECT_TRUE(CBS_peek_asn1_tag(&data, 0x30));
+  EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_BOOLEAN));
+  EXPECT_TRUE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
 
-  ASSERT_TRUE(CBS_get_asn1(&data, &contents, 0x30));
+  ASSERT_TRUE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
   EXPECT_EQ(Bytes("\x01\x02"), Bytes(CBS_data(&contents), CBS_len(&contents)));
 
   CBS_init(&data, kData2, sizeof(kData2));
   // data is truncated
-  EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+  EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
 
   CBS_init(&data, kData3, sizeof(kData3));
   // zero byte length of length
-  EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+  EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
 
   CBS_init(&data, kData4, sizeof(kData4));
   // long form mistakenly used.
-  EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+  EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
 
   CBS_init(&data, kData5, sizeof(kData5));
   // length takes too many bytes.
-  EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+  EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
 
   CBS_init(&data, kData1, sizeof(kData1));
   // wrong tag.
@@ -151,56 +151,72 @@
 
   CBS_init(&data, NULL, 0);
   // peek at empty data.
-  EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x30));
+  EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
 
   CBS_init(&data, NULL, 0);
   // optional elements at empty data.
-  ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
+  ASSERT_TRUE(CBS_get_optional_asn1(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
   EXPECT_FALSE(present);
-  ASSERT_TRUE(
-      CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0));
+  ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
   EXPECT_FALSE(present);
   EXPECT_EQ(0u, CBS_len(&contents));
-  ASSERT_TRUE(CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0));
+  ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+      &data, &contents, NULL,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
   EXPECT_EQ(0u, CBS_len(&contents));
-  ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
+  ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+      &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
   EXPECT_EQ(42u, value);
 
   CBS_init(&data, kData6, sizeof(kData6));
   // optional element.
-  ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
+  ASSERT_TRUE(CBS_get_optional_asn1(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
   EXPECT_FALSE(present);
-  ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa1));
+  ASSERT_TRUE(CBS_get_optional_asn1(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
   EXPECT_TRUE(present);
   EXPECT_EQ(Bytes("\x04\x01\x01"),
             Bytes(CBS_data(&contents), CBS_len(&contents)));
 
   CBS_init(&data, kData6, sizeof(kData6));
   // optional octet string.
-  ASSERT_TRUE(
-      CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0));
+  ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
   EXPECT_FALSE(present);
   EXPECT_EQ(0u, CBS_len(&contents));
-  ASSERT_TRUE(
-      CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1));
+  ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
   EXPECT_TRUE(present);
   EXPECT_EQ(Bytes("\x01"), Bytes(CBS_data(&contents), CBS_len(&contents)));
 
   CBS_init(&data, kData7, sizeof(kData7));
   // invalid optional octet string.
-  EXPECT_FALSE(
-      CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1));
+  EXPECT_FALSE(CBS_get_optional_asn1_octet_string(
+      &data, &contents, &present,
+      CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
 
   CBS_init(&data, kData8, sizeof(kData8));
   // optional integer.
-  ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
+  ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+      &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
   EXPECT_EQ(42u, value);
-  ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
+  ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+      &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
   EXPECT_EQ(1u, value);
 
   CBS_init(&data, kData9, sizeof(kData9));
   // invalid optional integer.
-  EXPECT_FALSE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
+  EXPECT_FALSE(CBS_get_optional_asn1_uint64(
+      &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
 
   unsigned tag;
   CBS_init(&data, kData1, sizeof(kData1));
@@ -217,6 +233,54 @@
             Bytes(CBS_data(&contents), CBS_len(&contents)));
 }
 
+TEST(CBSTest, ParseASN1Tag) {
+  const struct {
+    bool ok;
+    unsigned tag;
+    std::vector<uint8_t> in;
+  } kTests[] = {
+      {true, CBS_ASN1_SEQUENCE, {0x30, 0}},
+      {true, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4, {0xa4, 0}},
+      {true, CBS_ASN1_APPLICATION | 30, {0x5e, 0}},
+      {true, CBS_ASN1_APPLICATION | 31, {0x5f, 0x1f, 0}},
+      {true, CBS_ASN1_APPLICATION | 32, {0x5f, 0x20, 0}},
+      {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|.
+      {false, 0, {0xff, 0x82, 0xff, 0xff, 0xff, 0x7f, 0}},
+      // Tag number does not fit in unsigned.
+      {false, 0, {0xff, 0x90, 0x80, 0x80, 0x80, 0, 0}},
+      // Tag number is not minimally-encoded
+      {false, 0, {0x5f, 0x80, 0x1f, 0}},
+      // Tag number should have used short form.
+      {false, 0, {0x5f, 0x80, 0x1e, 0}},
+  };
+  for (const auto &t : kTests) {
+    SCOPED_TRACE(Bytes(t.in));
+    unsigned tag;
+    CBS cbs, child;
+    CBS_init(&cbs, t.in.data(), t.in.size());
+    ASSERT_EQ(t.ok, !!CBS_get_any_asn1(&cbs, &child, &tag));
+    if (t.ok) {
+      EXPECT_EQ(t.tag, tag);
+      EXPECT_EQ(0u, CBS_len(&child));
+      EXPECT_EQ(0u, CBS_len(&cbs));
+
+      CBS_init(&cbs, t.in.data(), t.in.size());
+      EXPECT_TRUE(CBS_peek_asn1_tag(&cbs, t.tag));
+      EXPECT_FALSE(CBS_peek_asn1_tag(&cbs, t.tag + 1));
+
+      EXPECT_TRUE(CBS_get_asn1(&cbs, &child, t.tag));
+      EXPECT_EQ(0u, CBS_len(&child));
+      EXPECT_EQ(0u, CBS_len(&cbs));
+
+      CBS_init(&cbs, t.in.data(), t.in.size());
+      EXPECT_FALSE(CBS_get_asn1(&cbs, &child, t.tag + 1));
+    }
+  }
+}
+
 TEST(CBSTest, GetOptionalASN1Bool) {
   static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
   static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
@@ -416,15 +480,42 @@
 }
 
 TEST(CBBTest, ASN1) {
-  static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
+  static const uint8_t kExpected[] = {
+      // SEQUENCE { 1 2 3 }
+      0x30, 3, 1, 2, 3,
+      // [4 CONSTRUCTED] { 4 5 6 }
+      0xa4, 3, 4, 5, 6,
+      // [APPLICATION 30 PRIMITIVE] { 7 8 9 }
+      0x5e, 3, 7, 8, 9,
+      // [APPLICATION 31 PRIMITIVE] { 10 11 12 }
+      0x5f, 0x1f, 3, 10, 11, 12,
+      // [PRIVATE 2^29-1 CONSTRUCTED] { 13 14 15 }
+      0xff, 0x81, 0xff, 0xff, 0xff, 0x7f, 3, 13, 14, 15,
+  };
   uint8_t *buf;
   size_t buf_len;
   bssl::ScopedCBB cbb;
   CBB contents, inner_contents;
 
   ASSERT_TRUE(CBB_init(cbb.get(), 0));
-  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
+  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
   ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x01\x02\x03", 3));
+  ASSERT_TRUE(
+      CBB_add_asn1(cbb.get(), &contents,
+                   CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 4));
+  ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x04\x05\x06", 3));
+  ASSERT_TRUE(
+      CBB_add_asn1(cbb.get(), &contents,
+                   CBS_ASN1_APPLICATION | 30));
+  ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x07\x08\x09", 3));
+  ASSERT_TRUE(
+      CBB_add_asn1(cbb.get(), &contents,
+                   CBS_ASN1_APPLICATION | 31));
+  ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0a\x0b\x0c", 3));
+  ASSERT_TRUE(
+      CBB_add_asn1(cbb.get(), &contents,
+                   CBS_ASN1_PRIVATE | CBS_ASN1_CONSTRUCTED | 0x1fffffff));
+  ASSERT_TRUE(CBB_add_bytes(&contents, (const uint8_t *)"\x0d\x0e\x0f", 3));
   ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
   bssl::UniquePtr<uint8_t> scoper(buf);
 
@@ -432,7 +523,7 @@
 
   std::vector<uint8_t> test_data(100000, 0x42);
   ASSERT_TRUE(CBB_init(cbb.get(), 0));
-  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
+  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
   ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 130));
   ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
   scoper.reset(buf);
@@ -442,7 +533,7 @@
   EXPECT_EQ(Bytes(test_data.data(), 130), Bytes(buf + 3, 130));
 
   ASSERT_TRUE(CBB_init(cbb.get(), 0));
-  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
+  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
   ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 1000));
   ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
   scoper.reset(buf);
@@ -452,8 +543,8 @@
   EXPECT_EQ(Bytes(test_data.data(), 1000), Bytes(buf + 4, 1000));
 
   ASSERT_TRUE(CBB_init(cbb.get(), 0));
-  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
-  ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, 0x30));
+  ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
+  ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, CBS_ASN1_SEQUENCE));
   ASSERT_TRUE(CBB_add_bytes(&inner_contents, test_data.data(), 100000));
   ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
   scoper.reset(buf);
@@ -490,6 +581,12 @@
   static const uint8_t kIndefBER[] = {0x30, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00};
   static const uint8_t kIndefDER[] = {0x30, 0x03, 0x01, 0x01, 0x02};
 
+  // kIndefBER2 contains a constructed [APPLICATION 31] with an indefinite
+  // length.
+  static const uint8_t kIndefBER2[] = {0x7f, 0x1f, 0x80, 0x01,
+                                       0x01, 0x02, 0x00, 0x00};
+  static const uint8_t kIndefDER2[] = {0x7f, 0x1f, 0x03, 0x01, 0x01, 0x02};
+
   // kOctetStringBER contains an indefinite length OCTET STRING with two parts.
   // These parts need to be concatenated in DER form.
   static const uint8_t kOctetStringBER[] = {0x24, 0x80, 0x04, 0x02, 0,    1,
@@ -534,6 +631,8 @@
                    sizeof(kSimpleBER));
   ExpectBerConvert("kIndefBER", kIndefDER, sizeof(kIndefDER), kIndefBER,
                    sizeof(kIndefBER));
+  ExpectBerConvert("kIndefBER2", kIndefDER2, sizeof(kIndefDER2), kIndefBER2,
+                   sizeof(kIndefBER2));
   ExpectBerConvert("kOctetStringBER", kOctetStringDER, sizeof(kOctetStringDER),
                    kOctetStringBER, sizeof(kOctetStringBER));
   ExpectBerConvert("kNSSBER", kNSSDER, sizeof(kNSSDER), kNSSBER,
diff --git a/src/crypto/bytestring/cbb.c b/src/crypto/bytestring/cbb.c
index f8f5e0f..b12a66c 100644
--- a/src/crypto/bytestring/cbb.c
+++ b/src/crypto/bytestring/cbb.c
@@ -356,17 +356,20 @@
 }
 
 int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) {
-  if (tag > 0xff ||
-      (tag & 0x1f) == 0x1f) {
-    // Long form identifier octets are not supported. Further, all current valid
-    // tag serializations are 8 bits.
-    cbb->base->error = 1;
+  if (!CBB_flush(cbb)) {
     return 0;
   }
 
-  if (!CBB_flush(cbb) ||
-      // |tag|'s representation matches the DER encoding.
-      !CBB_add_u8(cbb, (uint8_t)tag)) {
+  // 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;
+  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) ||
+        !add_base128_integer(cbb, tag_number)) {
+      return 0;
+    }
+  } else if (!CBB_add_u8(cbb, tag_bits | tag_number)) {
     return 0;
   }
 
diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c
index f3fc863..e456330 100644
--- a/src/crypto/bytestring/cbs.c
+++ b/src/crypto/bytestring/cbs.c
@@ -207,18 +207,9 @@
   return 1;
 }
 
-static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
-                                    size_t *out_header_len, int ber_ok) {
-  uint8_t tag, length_byte;
-  CBS header = *cbs;
-  CBS throwaway;
-
-  if (out == NULL) {
-    out = &throwaway;
-  }
-
-  if (!CBS_get_u8(&header, &tag) ||
-      !CBS_get_u8(&header, &length_byte)) {
+static int parse_asn1_tag(CBS *cbs, unsigned *out) {
+  uint8_t tag_byte;
+  if (!CBS_get_u8(cbs, &tag_byte)) {
     return 0;
   }
 
@@ -229,22 +220,58 @@
   // allotted bits), then the tag is more than one byte long and the
   // continuation bytes contain the tag number. This parser only supports tag
   // numbers less than 31 (and thus single-byte tags).
-  if ((tag & 0x1f) == 0x1f) {
-    return 0;
+  unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
+  unsigned tag_number = tag_byte & 0x1f;
+  if (tag_number == 0x1f) {
+    uint64_t v;
+    if (!parse_base128_integer(cbs, &v) ||
+        // Check the tag number is within our supported bounds.
+        v > CBS_ASN1_TAG_NUMBER_MASK ||
+        // Small tag numbers should have used low tag number form.
+        v < 0x1f) {
+      return 0;
+    }
+    tag_number = (unsigned)v;
   }
 
+  tag |= tag_number;
+
+  *out = tag;
+  return 1;
+}
+
+static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+                                    size_t *out_header_len, int ber_ok) {
+  CBS header = *cbs;
+  CBS throwaway;
+
+  if (out == NULL) {
+    out = &throwaway;
+  }
+
+  unsigned tag;
+  if (!parse_asn1_tag(&header, &tag)) {
+    return 0;
+  }
   if (out_tag != NULL) {
     *out_tag = tag;
   }
 
+  uint8_t length_byte;
+  if (!CBS_get_u8(&header, &length_byte)) {
+    return 0;
+  }
+
+  size_t header_len = CBS_len(cbs) - CBS_len(&header);
+
   size_t len;
   // The format for the length encoding is specified in ITU-T X.690 section
   // 8.1.3.
   if ((length_byte & 0x80) == 0) {
     // Short form length.
-    len = ((size_t) length_byte) + 2;
+    len = ((size_t) length_byte) + header_len;
     if (out_header_len != NULL) {
-      *out_header_len = 2;
+      *out_header_len = header_len;
     }
   } else {
     // The high bit indicate that this is the long form, while the next 7 bits
@@ -256,9 +283,9 @@
     if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
       // indefinite length
       if (out_header_len != NULL) {
-        *out_header_len = 2;
+        *out_header_len = header_len;
       }
-      return CBS_get_bytes(cbs, out, 2);
+      return CBS_get_bytes(cbs, out, header_len);
     }
 
     // ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be
@@ -281,13 +308,13 @@
       return 0;
     }
     len = len32;
-    if (len + 2 + num_bytes < len) {
+    if (len + header_len + num_bytes < len) {
       // Overflow.
       return 0;
     }
-    len += 2 + num_bytes;
+    len += header_len + num_bytes;
     if (out_header_len != NULL) {
-      *out_header_len = 2 + num_bytes;
+      *out_header_len = header_len + num_bytes;
     }
   }
 
@@ -355,7 +382,10 @@
   if (CBS_len(cbs) < 1) {
     return 0;
   }
-  return CBS_data(cbs)[0] == tag_value;
+
+  CBS copy = *cbs;
+  unsigned actual_tag;
+  return parse_asn1_tag(&copy, &actual_tag) && tag_value == actual_tag;
 }
 
 int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
diff --git a/src/crypto/cipher_extra/e_tls.c b/src/crypto/cipher_extra/e_tls.c
index 72754c0..bba22be 100644
--- a/src/crypto/cipher_extra/e_tls.c
+++ b/src/crypto/cipher_extra/e_tls.c
@@ -191,8 +191,7 @@
   // block from encrypting the input and split the result between |out| and
   // |out_tag|. Then feed the rest.
 
-  const size_t early_mac_len =
-      (block_size - (in_len % block_size) % block_size);
+  const size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
   if (early_mac_len != 0) {
     assert(len + block_size - early_mac_len == in_len);
     uint8_t buf[EVP_MAX_BLOCK_LENGTH];
diff --git a/src/crypto/fipsmodule/ec/ec_key.c b/src/crypto/fipsmodule/ec/ec_key.c
index f64cb21..4e0bcb2 100644
--- a/src/crypto/fipsmodule/ec/ec_key.c
+++ b/src/crypto/fipsmodule/ec/ec_key.c
@@ -233,20 +233,21 @@
 const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
 
 int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
+  // If |key| already has a group, it is an error to switch to another one.
+  if (key->group != NULL) {
+    if (EC_GROUP_cmp(key->group, group, NULL) != 0) {
+      OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
+      return 0;
+    }
+    return 1;
+  }
+
+  assert(key->priv_key == NULL);
+  assert(key->pub_key == NULL);
+
   EC_GROUP_free(key->group);
-  // TODO(fork): duplicating the group seems wasteful but see
-  // |EC_KEY_set_conv_form|.
   key->group = EC_GROUP_dup(group);
-  if (key->group == NULL) {
-    return 0;
-  }
-  // XXX: |BN_cmp| is not constant time.
-  if (key->priv_key != NULL &&
-      (BN_is_negative(key->priv_key) ||
-       BN_cmp(key->priv_key, EC_GROUP_get0_order(group)) >= 0)) {
-    return 0;
-  }
-  return 1;
+  return key->group != NULL;
 }
 
 const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
@@ -254,10 +255,14 @@
 }
 
 int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
+  if (key->group == NULL) {
+    OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
+    return 0;
+  }
+
   // XXX: |BN_cmp| is not constant time.
-  if (key->group != NULL &&
-      (BN_is_negative(priv_key) ||
-       BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0)) {
+  if (BN_is_negative(priv_key) ||
+      BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
     OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
     return 0;
   }
@@ -271,6 +276,16 @@
 }
 
 int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
+  if (key->group == NULL) {
+    OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
+    return 0;
+  }
+
+  if (EC_GROUP_cmp(key->group, pub_key->group, NULL) != 0) {
+    OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
+    return 0;
+  }
+
   EC_POINT_free(key->pub_key);
   key->pub_key = EC_POINT_dup(pub_key, key->group);
   return (key->pub_key == NULL) ? 0 : 1;
diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc
index 8e7a81d..d2cd2af 100644
--- a/src/crypto/fipsmodule/ec/ec_test.cc
+++ b/src/crypto/fipsmodule/ec/ec_test.cc
@@ -305,6 +305,36 @@
   EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
 }
 
+TEST(ECTest, SetKeyWithoutGroup) {
+  bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
+  ASSERT_TRUE(key);
+
+  // Private keys may not be configured without a group.
+  EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
+
+  // Public keys may not be configured without a group.
+  bssl::UniquePtr<EC_GROUP> group(
+      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+  ASSERT_TRUE(group);
+  EXPECT_FALSE(
+      EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
+}
+
+TEST(ECTest, GroupMismatch) {
+  bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
+  ASSERT_TRUE(key);
+  bssl::UniquePtr<EC_GROUP> p256(
+      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+  ASSERT_TRUE(p256);
+
+  // Changing a key's group is invalid.
+  EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
+
+  // Configuring a public key with the wrong group is invalid.
+  EXPECT_FALSE(
+      EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
+}
+
 class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
 
 TEST_P(ECCurveTest, SetAffine) {
diff --git a/src/crypto/fipsmodule/modes/internal.h b/src/crypto/fipsmodule/modes/internal.h
index f6ee8f4..68ef4dc 100644
--- a/src/crypto/fipsmodule/modes/internal.h
+++ b/src/crypto/fipsmodule/modes/internal.h
@@ -66,38 +66,6 @@
 #define STRICT_ALIGNMENT 0
 #endif
 
-#if defined(__GNUC__) && __GNUC__ >= 2
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
-  return __builtin_bswap32(x);
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
-  return __builtin_bswap64(x);
-}
-#elif defined(_MSC_VER)
-OPENSSL_MSVC_PRAGMA(warning(push, 3))
-#include <intrin.h>
-OPENSSL_MSVC_PRAGMA(warning(pop))
-#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
-  return _byteswap_ulong(x);
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
-  return _byteswap_uint64(x);
-}
-#else
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
-  x = (x >> 16) | (x << 16);
-  x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
-  return x;
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
-  return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32);
-}
-#endif
-
 static inline uint32_t GETU32(const void *in) {
   uint32_t v;
   OPENSSL_memcpy(&v, in, sizeof(v));
diff --git a/src/crypto/fipsmodule/rsa/rsa.c b/src/crypto/fipsmodule/rsa/rsa.c
index 4a84314..ffe2cd0 100644
--- a/src/crypto/fipsmodule/rsa/rsa.c
+++ b/src/crypto/fipsmodule/rsa/rsa.c
@@ -852,6 +852,8 @@
   return rsa_default_private_transform(rsa, out, in, len);
 }
 
+int RSA_flags(const RSA *rsa) { return rsa->flags; }
+
 int RSA_blinding_on(RSA *rsa, BN_CTX *ctx) {
   return 1;
 }
diff --git a/src/crypto/fipsmodule/rsa/rsa_impl.c b/src/crypto/fipsmodule/rsa/rsa_impl.c
index c391228..b5a4e51 100644
--- a/src/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/src/crypto/fipsmodule/rsa/rsa_impl.c
@@ -1097,5 +1097,4 @@
   // |rsa_default_*| implementation.
   OPENSSL_memset(out, 0, sizeof(RSA_METHOD));
   out->common.is_static = 1;
-  out->flags = RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE;
 }
diff --git a/src/crypto/internal.h b/src/crypto/internal.h
index 5706414..e6bab02 100644
--- a/src/crypto/internal.h
+++ b/src/crypto/internal.h
@@ -591,6 +591,41 @@
                                         void *obj, CRYPTO_EX_DATA *ad);
 
 
+// Endianness conversions.
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+  return __builtin_bswap32(x);
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+  return __builtin_bswap64(x);
+}
+#elif defined(_MSC_VER)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <intrin.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+  return _byteswap_ulong(x);
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+  return _byteswap_uint64(x);
+}
+#else
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+  x = (x >> 16) | (x << 16);
+  x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
+  return x;
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+  return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32);
+}
+#endif
+
+
 // Language bug workarounds.
 //
 // Most C standard library functions are undefined if passed NULL, even when the
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index 158fd45..b4cecca 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -835,7 +835,7 @@
 
   /* This ensures the X509 took a reference to |buf|, otherwise this will be a
    * reference to free memory and ASAN should notice. */
-  ASSERT_EQ(CBS_ASN1_SEQUENCE, enc_pointer[0]);
+  ASSERT_EQ(0x30, enc_pointer[0]);
 }
 
 TEST(X509Test, TestFromBufferWithTrailingData) {