Export CBS/CBB unicode functions

This way the Chromium certificate verifier can more easily use them.

Bug: chromium:1322914
Change-Id: I51dafc4e70d74da8543688b6457563d78e298150
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/62745
Auto-Submit: David Benjamin <davidben@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
diff --git a/crypto/asn1/a_mbstr.c b/crypto/asn1/a_mbstr.c
index 8fc82ab..4d7ea14 100644
--- a/crypto/asn1/a_mbstr.c
+++ b/crypto/asn1/a_mbstr.c
@@ -97,22 +97,22 @@
   int error;
   switch (inform) {
     case MBSTRING_BMP:
-      decode_func = cbs_get_ucs2_be;
+      decode_func = CBS_get_ucs2_be;
       error = ASN1_R_INVALID_BMPSTRING;
       break;
 
     case MBSTRING_UNIV:
-      decode_func = cbs_get_utf32_be;
+      decode_func = CBS_get_utf32_be;
       error = ASN1_R_INVALID_UNIVERSALSTRING;
       break;
 
     case MBSTRING_UTF8:
-      decode_func = cbs_get_utf8;
+      decode_func = CBS_get_utf8;
       error = ASN1_R_INVALID_UTF8STRING;
       break;
 
     case MBSTRING_ASC:
-      decode_func = cbs_get_latin1;
+      decode_func = CBS_get_latin1;
       error = ERR_R_INTERNAL_ERROR;  // Latin-1 inputs are never invalid.
       break;
 
@@ -162,7 +162,7 @@
     }
 
     nchar++;
-    utf8_len += cbb_get_utf8_len(c);
+    utf8_len += CBB_get_utf8_len(c);
     if (maxsize > 0 && nchar > (size_t)maxsize) {
       OPENSSL_PUT_ERROR(ASN1, ASN1_R_STRING_TOO_LONG);
       ERR_add_error_dataf("maxsize=%zu", (size_t)maxsize);
@@ -178,7 +178,7 @@
 
   // Now work out output format and string type
   int str_type;
-  int (*encode_func)(CBB *, uint32_t) = cbb_add_latin1;
+  int (*encode_func)(CBB *, uint32_t) = CBB_add_latin1;
   size_t size_estimate = nchar;
   int outform = MBSTRING_ASC;
   if (mask & B_ASN1_PRINTABLESTRING) {
@@ -190,17 +190,17 @@
   } else if (mask & B_ASN1_BMPSTRING) {
     str_type = V_ASN1_BMPSTRING;
     outform = MBSTRING_BMP;
-    encode_func = cbb_add_ucs2_be;
+    encode_func = CBB_add_ucs2_be;
     size_estimate = 2 * nchar;
   } else if (mask & B_ASN1_UNIVERSALSTRING) {
     str_type = V_ASN1_UNIVERSALSTRING;
-    encode_func = cbb_add_utf32_be;
+    encode_func = CBB_add_utf32_be;
     size_estimate = 4 * nchar;
     outform = MBSTRING_UNIV;
   } else if (mask & B_ASN1_UTF8STRING) {
     str_type = V_ASN1_UTF8STRING;
     outform = MBSTRING_UTF8;
-    encode_func = cbb_add_utf8;
+    encode_func = CBB_add_utf8;
     size_estimate = utf8_len;
   } else {
     OPENSSL_PUT_ERROR(ASN1, ASN1_R_ILLEGAL_CHARACTERS);
diff --git a/crypto/asn1/a_strex.c b/crypto/asn1/a_strex.c
index dcc87f1..7e9afad 100644
--- a/crypto/asn1/a_strex.c
+++ b/crypto/asn1/a_strex.c
@@ -137,19 +137,19 @@
   int get_char_error;
   switch (encoding) {
     case MBSTRING_UNIV:
-      get_char = cbs_get_utf32_be;
+      get_char = CBS_get_utf32_be;
       get_char_error = ASN1_R_INVALID_UNIVERSALSTRING;
       break;
     case MBSTRING_BMP:
-      get_char = cbs_get_ucs2_be;
+      get_char = CBS_get_ucs2_be;
       get_char_error = ASN1_R_INVALID_BMPSTRING;
       break;
     case MBSTRING_ASC:
-      get_char = cbs_get_latin1;
+      get_char = CBS_get_latin1;
       get_char_error = ERR_R_INTERNAL_ERROR;  // Should not be possible.
       break;
     case MBSTRING_UTF8:
-      get_char = cbs_get_utf8;
+      get_char = CBS_get_utf8;
       get_char_error = ASN1_R_INVALID_UTF8STRING;
       break;
     default:
@@ -172,7 +172,7 @@
       uint8_t utf8_buf[6];
       CBB utf8_cbb;
       CBB_init_fixed(&utf8_cbb, utf8_buf, sizeof(utf8_buf));
-      if (!cbb_add_utf8(&utf8_cbb, c)) {
+      if (!CBB_add_utf8(&utf8_cbb, c)) {
         OPENSSL_PUT_ERROR(ASN1, ERR_R_INTERNAL_ERROR);
         return 1;
       }
diff --git a/crypto/asn1/tasn_dec.c b/crypto/asn1/tasn_dec.c
index 24ab04f..94891c8 100644
--- a/crypto/asn1/tasn_dec.c
+++ b/crypto/asn1/tasn_dec.c
@@ -850,7 +850,7 @@
       if (utype == V_ASN1_BMPSTRING) {
         while (CBS_len(&cbs) != 0) {
           uint32_t c;
-          if (!cbs_get_ucs2_be(&cbs, &c)) {
+          if (!CBS_get_ucs2_be(&cbs, &c)) {
             OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_BMPSTRING);
             goto err;
           }
@@ -859,7 +859,7 @@
       if (utype == V_ASN1_UNIVERSALSTRING) {
         while (CBS_len(&cbs) != 0) {
           uint32_t c;
-          if (!cbs_get_utf32_be(&cbs, &c)) {
+          if (!CBS_get_utf32_be(&cbs, &c)) {
             OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UNIVERSALSTRING);
             goto err;
           }
@@ -868,7 +868,7 @@
       if (utype == V_ASN1_UTF8STRING) {
         while (CBS_len(&cbs) != 0) {
           uint32_t c;
-          if (!cbs_get_utf8(&cbs, &c)) {
+          if (!CBS_get_utf8(&cbs, &c)) {
             OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_UTF8STRING);
             goto err;
           }
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc
index 10d3469..08cfb87 100644
--- a/crypto/bytestring/bytestring_test.cc
+++ b/crypto/bytestring/bytestring_test.cc
@@ -1353,7 +1353,7 @@
     std::vector<uint32_t> out;
     bool ok;
   } kTests[] = {
-      {cbs_get_utf8, cbb_add_utf8,
+      {CBS_get_utf8, CBB_add_utf8,
        // This test string captures all four cases in UTF-8.
        LiteralToBytes(u8"Hello, 世界! ¡Hola, 🌎!"),
        LiteralToCodePoints(U"Hello, 世界! ¡Hola, 🌎!"), true},
@@ -1362,120 +1362,120 @@
       // http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
       // 2.1  First possible sequence of a certain length. (5- and 6-bit
       // sequences no longer exist.)
-      {cbs_get_utf8, cbb_add_utf8, {0xf8, 0x88, 0x80, 0x80, 0x80}, {}, false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8, CBB_add_utf8, {0xf8, 0x88, 0x80, 0x80, 0x80}, {}, false},
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xfc, 0x84, 0x80, 0x80, 0x80, 0x80},
        {},
        false},
       // 3.1  Unexpected continuation bytes.
-      {cbs_get_utf8, cbb_add_utf8, {0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xbf}, {}, false},
       // 3.2  Lonely start characters.
-      {cbs_get_utf8, cbb_add_utf8, {0xc0, ' '}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, ' '}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, ' '}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xc0, ' '}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, ' '}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, ' '}, {}, false},
       // 3.3  Sequences with last continuation byte missing
-      {cbs_get_utf8, cbb_add_utf8, {0xc0}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xc0}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x80, 0x80}, {}, false},
       // Variation of the above with unexpected spaces.
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, ' '}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, ' '}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, 0x80, ' '}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x80, 0x80, ' '}, {}, false},
       // 4.1  Examples of an overlong ASCII character
-      {cbs_get_utf8, cbb_add_utf8, {0xc0, 0xaf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, 0xaf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, 0xaf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xc0, 0xaf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, 0x80, 0xaf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x80, 0x80, 0xaf}, {}, false},
       // 4.2  Maximum overlong sequences
-      {cbs_get_utf8, cbb_add_utf8, {0xc1, 0xbf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, 0x9f, 0xbf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x8f, 0xbf, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xc1, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, 0x9f, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x8f, 0xbf, 0xbf}, {}, false},
       // 4.3  Overlong representation of the NUL character
-      {cbs_get_utf8, cbb_add_utf8, {0xc0, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xe0, 0x80, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x80, 0x80, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xc0, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xe0, 0x80, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x80, 0x80, 0x80}, {}, false},
       // 5.1  Single UTF-16 surrogates
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xa0, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xad, 0xbf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xae, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xb0, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xbe, 0x80}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xed, 0xbf, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xa0, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xad, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xae, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xb0, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xbe, 0x80}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xed, 0xbf, 0xbf}, {}, false},
       // 5.2  Paired UTF-16 surrogates
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xa0, 0x80, 0xed, 0xbf, 0xbf},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xad, 0xbf, 0xed, 0xb0, 0x80},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xad, 0xbf, 0xed, 0xbf, 0xbf},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xae, 0x80, 0xed, 0xb0, 0x80},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xae, 0x80, 0xed, 0xbf, 0xbf},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xaf, 0xbf, 0xed, 0xb0, 0x80},
        {},
        false},
-      {cbs_get_utf8,
-       cbb_add_utf8,
+      {CBS_get_utf8,
+       CBB_add_utf8,
        {0xed, 0xaf, 0xbf, 0xed, 0xbf, 0xbf},
        {},
        false},
       // 5.3  Noncharacter code positions
-      {cbs_get_utf8, cbb_add_utf8, {0xef, 0xbf, 0xbe}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xef, 0xbf, 0xbf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xef, 0xb7, 0x90}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xef, 0xb7, 0xaf}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x9f, 0xbf, 0xbe}, {}, false},
-      {cbs_get_utf8, cbb_add_utf8, {0xf0, 0x9f, 0xbf, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xef, 0xbf, 0xbe}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xef, 0xbf, 0xbf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xef, 0xb7, 0x90}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xef, 0xb7, 0xaf}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x9f, 0xbf, 0xbe}, {}, false},
+      {CBS_get_utf8, CBB_add_utf8, {0xf0, 0x9f, 0xbf, 0xbf}, {}, false},
 
-      {cbs_get_latin1, cbb_add_latin1, LiteralToBytes("\xa1Hola!"),
+      {CBS_get_latin1, CBB_add_latin1, LiteralToBytes("\xa1Hola!"),
        LiteralToCodePoints(U"¡Hola!"), true},
 
       // UCS-2 matches UTF-16 on the BMP.
-      {cbs_get_ucs2_be, cbb_add_ucs2_be, LiteralToBytes(u"Hello, 世界!"),
+      {CBS_get_ucs2_be, CBB_add_ucs2_be, LiteralToBytes(u"Hello, 世界!"),
        LiteralToCodePoints(U"Hello, 世界!"), true},
       // It does not support characters beyond the BMP.
-      {cbs_get_ucs2_be, cbb_add_ucs2_be,
+      {CBS_get_ucs2_be, CBB_add_ucs2_be,
        LiteralToBytes(u"Hello, 世界! ¡Hola, 🌎!"),
        LiteralToCodePoints(U"Hello, 世界! ¡Hola, "), false},
       // Unpaired surrogates and non-characters are also rejected.
-      {cbs_get_ucs2_be, cbb_add_ucs2_be, {0xd8, 0x00}, {}, false},
-      {cbs_get_ucs2_be, cbb_add_ucs2_be, {0xff, 0xfe}, {}, false},
+      {CBS_get_ucs2_be, CBB_add_ucs2_be, {0xd8, 0x00}, {}, false},
+      {CBS_get_ucs2_be, CBB_add_ucs2_be, {0xff, 0xfe}, {}, false},
 
-      {cbs_get_utf32_be, cbb_add_utf32_be,
+      {CBS_get_utf32_be, CBB_add_utf32_be,
        LiteralToBytes(U"Hello, 世界! ¡Hola, 🌎!"),
        LiteralToCodePoints(U"Hello, 世界! ¡Hola, 🌎!"), true},
       // Unpaired surrogates and non-characters are rejected.
-      {cbs_get_utf32_be, cbb_add_utf32_be, {0x00, 0x00, 0xd8, 0x00}, {}, false},
-      {cbs_get_utf32_be, cbb_add_utf32_be, {0x00, 0x00, 0xff, 0xfe}, {}, false},
+      {CBS_get_utf32_be, CBB_add_utf32_be, {0x00, 0x00, 0xd8, 0x00}, {}, false},
+      {CBS_get_utf32_be, CBB_add_utf32_be, {0x00, 0x00, 0xff, 0xfe}, {}, false},
 
       // Test that the NUL character can be encoded.
-      {cbs_get_latin1, cbb_add_latin1, {0}, {0}, true},
-      {cbs_get_utf8, cbb_add_utf8, {0}, {0}, true},
-      {cbs_get_ucs2_be, cbb_add_ucs2_be, {0, 0}, {0}, true},
-      {cbs_get_utf32_be, cbb_add_utf32_be, {0, 0, 0, 0}, {0}, true},
+      {CBS_get_latin1, CBB_add_latin1, {0}, {0}, true},
+      {CBS_get_utf8, CBB_add_utf8, {0}, {0}, true},
+      {CBS_get_ucs2_be, CBB_add_ucs2_be, {0, 0}, {0}, true},
+      {CBS_get_utf32_be, CBB_add_utf32_be, {0, 0, 0, 0}, {0}, true},
   };
   for (const auto &t : kTests) {
     SCOPED_TRACE(Bytes(t.in));
@@ -1524,24 +1524,24 @@
   ASSERT_TRUE(CBB_init(cbb.get(), 0));
   for (uint32_t v : kBadCodePoints) {
     SCOPED_TRACE(v);
-    EXPECT_FALSE(cbb_add_utf8(cbb.get(), v));
-    EXPECT_FALSE(cbb_add_latin1(cbb.get(), v));
-    EXPECT_FALSE(cbb_add_ucs2_be(cbb.get(), v));
-    EXPECT_FALSE(cbb_add_utf32_be(cbb.get(), v));
+    EXPECT_FALSE(CBB_add_utf8(cbb.get(), v));
+    EXPECT_FALSE(CBB_add_latin1(cbb.get(), v));
+    EXPECT_FALSE(CBB_add_ucs2_be(cbb.get(), v));
+    EXPECT_FALSE(CBB_add_utf32_be(cbb.get(), v));
   }
 
   // Additional values that are out of range.
-  EXPECT_FALSE(cbb_add_latin1(cbb.get(), 0x100));
-  EXPECT_FALSE(cbb_add_ucs2_be(cbb.get(), 0x10000));
+  EXPECT_FALSE(CBB_add_latin1(cbb.get(), 0x100));
+  EXPECT_FALSE(CBB_add_ucs2_be(cbb.get(), 0x10000));
 
-  EXPECT_EQ(1u, cbb_get_utf8_len(0));
-  EXPECT_EQ(1u, cbb_get_utf8_len(0x7f));
-  EXPECT_EQ(2u, cbb_get_utf8_len(0x80));
-  EXPECT_EQ(2u, cbb_get_utf8_len(0x7ff));
-  EXPECT_EQ(3u, cbb_get_utf8_len(0x800));
-  EXPECT_EQ(3u, cbb_get_utf8_len(0xffff));
-  EXPECT_EQ(4u, cbb_get_utf8_len(0x10000));
-  EXPECT_EQ(4u, cbb_get_utf8_len(0x10ffff));
+  EXPECT_EQ(1u, CBB_get_utf8_len(0));
+  EXPECT_EQ(1u, CBB_get_utf8_len(0x7f));
+  EXPECT_EQ(2u, CBB_get_utf8_len(0x80));
+  EXPECT_EQ(2u, CBB_get_utf8_len(0x7ff));
+  EXPECT_EQ(3u, CBB_get_utf8_len(0x800));
+  EXPECT_EQ(3u, CBB_get_utf8_len(0xffff));
+  EXPECT_EQ(4u, CBB_get_utf8_len(0x10000));
+  EXPECT_EQ(4u, CBB_get_utf8_len(0x10ffff));
 }
 
 TEST(CBSTest, BogusTime) {
diff --git a/crypto/bytestring/internal.h b/crypto/bytestring/internal.h
index ba23244..ff7a4a5 100644
--- a/crypto/bytestring/internal.h
+++ b/crypto/bytestring/internal.h
@@ -67,28 +67,6 @@
 int CBB_finish_i2d(CBB *cbb, uint8_t **outp);
 
 
-// Unicode utilities.
-
-// The following functions read one Unicode code point from |cbs| with the
-// corresponding encoding and store it in |*out|. They return one on success and
-// zero on error.
-OPENSSL_EXPORT int cbs_get_utf8(CBS *cbs, uint32_t *out);
-OPENSSL_EXPORT int cbs_get_latin1(CBS *cbs, uint32_t *out);
-OPENSSL_EXPORT int cbs_get_ucs2_be(CBS *cbs, uint32_t *out);
-OPENSSL_EXPORT int cbs_get_utf32_be(CBS *cbs, uint32_t *out);
-
-// cbb_get_utf8_len returns the number of bytes needed to represent |u| in
-// UTF-8.
-OPENSSL_EXPORT size_t cbb_get_utf8_len(uint32_t u);
-
-// The following functions encode |u| to |cbb| with the corresponding
-// encoding. They return one on success and zero on error.
-OPENSSL_EXPORT int cbb_add_utf8(CBB *cbb, uint32_t u);
-OPENSSL_EXPORT int cbb_add_latin1(CBB *cbb, uint32_t u);
-OPENSSL_EXPORT int cbb_add_ucs2_be(CBB *cbb, uint32_t u);
-OPENSSL_EXPORT int cbb_add_utf32_be(CBB *cbb, uint32_t u);
-
-
 #if defined(__cplusplus)
 }  // extern C
 #endif
diff --git a/crypto/bytestring/unicode.c b/crypto/bytestring/unicode.c
index 6f9467f..10fba07 100644
--- a/crypto/bytestring/unicode.c
+++ b/crypto/bytestring/unicode.c
@@ -38,7 +38,7 @@
 // TOP_BITS returns a byte with the top |n| bits set.
 #define TOP_BITS(n) ((uint8_t)~BOTTOM_BITS(8 - (n)))
 
-int cbs_get_utf8(CBS *cbs, uint32_t *out) {
+int CBS_get_utf8(CBS *cbs, uint32_t *out) {
   uint8_t c;
   if (!CBS_get_u8(cbs, &c)) {
     return 0;
@@ -80,7 +80,7 @@
   return 1;
 }
 
-int cbs_get_latin1(CBS *cbs, uint32_t *out) {
+int CBS_get_latin1(CBS *cbs, uint32_t *out) {
   uint8_t c;
   if (!CBS_get_u8(cbs, &c)) {
     return 0;
@@ -89,7 +89,7 @@
   return 1;
 }
 
-int cbs_get_ucs2_be(CBS *cbs, uint32_t *out) {
+int CBS_get_ucs2_be(CBS *cbs, uint32_t *out) {
   // Note UCS-2 (used by BMPString) does not support surrogates.
   uint16_t c;
   if (!CBS_get_u16(cbs, &c) ||
@@ -100,11 +100,11 @@
   return 1;
 }
 
-int cbs_get_utf32_be(CBS *cbs, uint32_t *out) {
+int CBS_get_utf32_be(CBS *cbs, uint32_t *out) {
   return CBS_get_u32(cbs, out) && is_valid_code_point(*out);
 }
 
-size_t cbb_get_utf8_len(uint32_t u) {
+size_t CBB_get_utf8_len(uint32_t u) {
   if (u <= 0x7f) {
     return 1;
   }
@@ -117,7 +117,7 @@
   return 4;
 }
 
-int cbb_add_utf8(CBB *cbb, uint32_t u) {
+int CBB_add_utf8(CBB *cbb, uint32_t u) {
   if (!is_valid_code_point(u)) {
     return 0;
   }
@@ -142,14 +142,14 @@
   return 0;
 }
 
-int cbb_add_latin1(CBB *cbb, uint32_t u) {
+int CBB_add_latin1(CBB *cbb, uint32_t u) {
   return u <= 0xff && CBB_add_u8(cbb, (uint8_t)u);
 }
 
-int cbb_add_ucs2_be(CBB *cbb, uint32_t u) {
+int CBB_add_ucs2_be(CBB *cbb, uint32_t u) {
   return u <= 0xffff && is_valid_code_point(u) && CBB_add_u16(cbb, (uint16_t)u);
 }
 
-int cbb_add_utf32_be(CBB *cbb, uint32_t u) {
+int CBB_add_utf32_be(CBB *cbb, uint32_t u) {
   return is_valid_code_point(u) && CBB_add_u32(cbb, u);
 }
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index 4bc337b..07d5de8 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -85,15 +85,15 @@
   CBS_init(&cbs, (const uint8_t *)in, in_len);
   while (CBS_len(&cbs) != 0) {
     uint32_t c;
-    if (!cbs_get_utf8(&cbs, &c) ||
-        !cbb_add_ucs2_be(&cbb, c)) {
+    if (!CBS_get_utf8(&cbs, &c) ||
+        !CBB_add_ucs2_be(&cbb, c)) {
       OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INVALID_CHARACTERS);
       goto err;
     }
   }
 
   // Terminate the result with a UCS-2 NUL.
-  if (!cbb_add_ucs2_be(&cbb, 0) ||
+  if (!CBB_add_ucs2_be(&cbb, 0) ||
       !CBB_finish(&cbb, out, out_len)) {
     goto err;
   }
diff --git a/crypto/pkcs8/pkcs8_x509.c b/crypto/pkcs8/pkcs8_x509.c
index 87c0961..92bdb9d 100644
--- a/crypto/pkcs8/pkcs8_x509.c
+++ b/crypto/pkcs8/pkcs8_x509.c
@@ -339,8 +339,8 @@
       }
       while (CBS_len(&value) != 0) {
         uint32_t c;
-        if (!cbs_get_ucs2_be(&value, &c) ||
-            !cbb_add_utf8(&cbb, c)) {
+        if (!CBS_get_ucs2_be(&value, &c) ||
+            !CBB_add_utf8(&cbb, c)) {
           OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INVALID_CHARACTERS);
           CBB_cleanup(&cbb);
           goto err;
@@ -972,8 +972,8 @@
     CBS_init(&name_cbs, (const uint8_t *)name, name_len);
     while (CBS_len(&name_cbs) != 0) {
       uint32_t c;
-      if (!cbs_get_utf8(&name_cbs, &c) ||
-          !cbb_add_ucs2_be(&value, c)) {
+      if (!CBS_get_utf8(&name_cbs, &c) ||
+          !CBB_add_ucs2_be(&value, c)) {
         OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_INVALID_CHARACTERS);
         return 0;
       }
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h
index 33e13ef..7dce9c4 100644
--- a/include/openssl/bytestring.h
+++ b/include/openssl/bytestring.h
@@ -635,6 +635,28 @@
 OPENSSL_EXPORT int CBB_flush_asn1_set_of(CBB *cbb);
 
 
+// Unicode utilities.
+
+// The following functions read one Unicode code point from |cbs| with the
+// corresponding encoding and store it in |*out|. They return one on success and
+// zero on error.
+OPENSSL_EXPORT int CBS_get_utf8(CBS *cbs, uint32_t *out);
+OPENSSL_EXPORT int CBS_get_latin1(CBS *cbs, uint32_t *out);
+OPENSSL_EXPORT int CBS_get_ucs2_be(CBS *cbs, uint32_t *out);
+OPENSSL_EXPORT int CBS_get_utf32_be(CBS *cbs, uint32_t *out);
+
+// CBB_get_utf8_len returns the number of bytes needed to represent |u| in
+// UTF-8.
+OPENSSL_EXPORT size_t CBB_get_utf8_len(uint32_t u);
+
+// The following functions encode |u| to |cbb| with the corresponding
+// encoding. They return one on success and zero on error.
+OPENSSL_EXPORT int CBB_add_utf8(CBB *cbb, uint32_t u);
+OPENSSL_EXPORT int CBB_add_latin1(CBB *cbb, uint32_t u);
+OPENSSL_EXPORT int CBB_add_ucs2_be(CBB *cbb, uint32_t u);
+OPENSSL_EXPORT int CBB_add_utf32_be(CBB *cbb, uint32_t u);
+
+
 #if defined(__cplusplus)
 }  // extern C