crypto/bytestring: Add helper for relative OID from DER to text into CBB It is similar to the existing CBS_asn1_relative_oid_to_text, except it writes directly into a CBB rather than allocating a new string. Change-Id: I2b7d7e1149d49d38ccacd37df4ff3bae6a6a6964 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/101047 Presubmit-BoringSSL-Verified: boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com <boringssl-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Lily Chen <chlily@google.com>
diff --git a/crypto/bytestring/bytestring_test.cc b/crypto/bytestring/bytestring_test.cc index b93c0ca..6395b42 100644 --- a/crypto/bytestring/bytestring_test.cc +++ b/crypto/bytestring/bytestring_test.cc
@@ -1669,6 +1669,12 @@ EXPECT_STREQ(t.text, text.get()); EXPECT_TRUE(CBS_is_valid_asn1_relative_oid(&cbs)); + + ScopedCBB text_cbb; + ASSERT_TRUE(CBB_init(text_cbb.get(), 0)); + EXPECT_TRUE(CBB_add_asn1_relative_oid_from_der_to_text( + text_cbb.get(), t.der.data(), t.der.size())); + EXPECT_EQ(Bytes(CBBAsSpan(text_cbb.get())), Bytes(t.text)); } for (const char *t : kInvalidTexts) { @@ -1685,6 +1691,11 @@ UniquePtr<char> text(CBS_asn1_relative_oid_to_text(&cbs)); EXPECT_FALSE(text); EXPECT_EQ(t.overflow ? 1 : 0, CBS_is_valid_asn1_relative_oid(&cbs)); + + ScopedCBB text_cbb; + ASSERT_TRUE(CBB_init(text_cbb.get(), 0)); + EXPECT_FALSE(CBB_add_asn1_relative_oid_from_der_to_text( + text_cbb.get(), t.der.data(), t.der.size())); } }
diff --git a/crypto/bytestring/cbb.cc b/crypto/bytestring/cbb.cc index 9400ab9..ab1b4be 100644 --- a/crypto/bytestring/cbb.cc +++ b/crypto/bytestring/cbb.cc
@@ -15,7 +15,9 @@ #include <openssl/bytestring.h> #include <assert.h> +#include <inttypes.h> #include <limits.h> +#include <stdio.h> #include <string.h> #include <algorithm> @@ -374,6 +376,13 @@ return 1; } +int bssl::cbb_add_decimal_ascii(CBB *out, uint64_t v) { + char buf[DECIMAL_SIZE(uint64_t) + 1]; + snprintf(buf, sizeof(buf), "%" PRIu64, v); + return CBB_add_bytes(out, reinterpret_cast<const uint8_t *>(buf), + strlen(buf)); +} + int CBB_add_asn1(CBB *cbb, CBB *out_contents, CBS_ASN1_TAG tag) { if (!CBB_flush(cbb)) { return 0; @@ -679,6 +688,26 @@ return 1; } +int CBB_add_asn1_relative_oid_from_der_to_text(CBB *cbb, const uint8_t *data, + size_t data_len) { + CBS der; + CBS_init(&der, data, data_len); + // Relative OIDs must have at least one component. + uint64_t v; + if (!CBS_get_asn1_oid_component(&der, &v) || !cbb_add_decimal_ascii(cbb, v)) { + return 0; + } + + while (CBS_len(&der) != 0) { + if (!CBS_get_asn1_oid_component(&der, &v) || !CBB_add_u8(cbb, '.') || + !cbb_add_decimal_ascii(cbb, v)) { + return 0; + } + } + + return 1; +} + int CBB_add_asn1_oid_component(CBB *cbb, uint64_t value) { if (!CBB_flush(cbb)) { return 0;
diff --git a/crypto/bytestring/cbs.cc b/crypto/bytestring/cbs.cc index 7abf10b..b0a0b8f 100644 --- a/crypto/bytestring/cbs.cc +++ b/crypto/bytestring/cbs.cc
@@ -18,7 +18,6 @@ #include <assert.h> #include <ctype.h> -#include <inttypes.h> #include <string.h> #include "../asn1/internal.h" @@ -730,12 +729,6 @@ return CBS_is_valid_asn1_integer(cbs, &is_negative) && !is_negative; } -static int add_decimal(CBB *out, uint64_t v) { - char buf[DECIMAL_SIZE(uint64_t) + 1]; - snprintf(buf, sizeof(buf), "%" PRIu64, v); - return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); -} - int CBS_is_valid_asn1_oid(const CBS *cbs) { if (CBS_len(cbs) == 0) { return 0; // OID encodings cannot be empty. @@ -774,17 +767,17 @@ if (v >= 80) { if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || - !add_decimal(&cbb, v - 80)) { + !cbb_add_decimal_ascii(&cbb, v - 80)) { goto err; } - } else if (!add_decimal(&cbb, v / 40) || !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v % 40)) { + } else if (!cbb_add_decimal_ascii(&cbb, v / 40) || !CBB_add_u8(&cbb, '.') || + !cbb_add_decimal_ascii(&cbb, v % 40)) { goto err; } while (CBS_len(©) != 0) { if (!CBS_get_asn1_oid_component(©, &v) || !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v)) { + !cbb_add_decimal_ascii(&cbb, v)) { goto err; } } @@ -807,25 +800,15 @@ } char *CBS_asn1_relative_oid_to_text(const CBS *cbs) { - CBS copy = *cbs; ScopedCBB cbb; if (!CBB_init(cbb.get(), 32)) { return nullptr; } - - // Relative OIDs must have at least one component. - uint64_t v; - if (!CBS_get_asn1_oid_component(©, &v) || !add_decimal(cbb.get(), v)) { + if (!CBB_add_asn1_relative_oid_from_der_to_text(cbb.get(), CBS_data(cbs), + CBS_len(cbs))) { return nullptr; } - while (CBS_len(©) != 0) { - if (!CBS_get_asn1_oid_component(©, &v) || !CBB_add_u8(cbb.get(), '.') || - !add_decimal(cbb.get(), v)) { - return nullptr; - } - } - uint8_t *txt; size_t txt_len; if (!CBB_add_u8(cbb.get(), '\0') || !CBB_finish(cbb.get(), &txt, &txt_len)) {
diff --git a/crypto/bytestring/internal.h b/crypto/bytestring/internal.h index e1aa76f..6bea4a7 100644 --- a/crypto/bytestring/internal.h +++ b/crypto/bytestring/internal.h
@@ -124,6 +124,11 @@ return CBB_finish_i2d(cbb.get(), outp); } +// cbb_add_decimal_ascii adds the characters of an ASCII string representation +// of `v` as a decimal value to `out` (without a terminating NUL byte). It +// returns one on success and zero on error. +int cbb_add_decimal_ascii(CBB *out, uint64_t v); + BSSL_NAMESPACE_END #endif // OPENSSL_HEADER_CRYPTO_BYTESTRING_INTERNAL_H
diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h index 53ee66d..e1b7089 100644 --- a/include/openssl/bytestring.h +++ b/include/openssl/bytestring.h
@@ -719,6 +719,17 @@ const char *text, size_t len); +// CBB_add_asn1_relative_oid_from_der_to_text reads `data_len` bytes of +// DER-encoded ASN.1 RELATIVE-OID contents (not including the element framing) +// from `data` and writes the ASCII representation (e.g., "32473.1") to `cbb` +// (without a trailing NUL byte). It returns one on success and zero on +// failure. +// +// This function may fail if `data` is an invalid RELATIVE-OID, or if any OID +// components are too large. +OPENSSL_EXPORT int CBB_add_asn1_relative_oid_from_der_to_text( + CBB *cbb, const uint8_t *data, size_t data_len); + // CBB_add_asn1_oid_component appends a single OID component to `cbb`. // It returns one on success and zero on error. //
diff --git a/include/openssl/prefix_symbols.h b/include/openssl/prefix_symbols.h index 6e68c58..e60131a 100644 --- a/include/openssl/prefix_symbols.h +++ b/include/openssl/prefix_symbols.h
@@ -506,6 +506,7 @@ #pragma redefine_extname CBB_add_asn1_octet_string BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_octet_string) #pragma redefine_extname CBB_add_asn1_oid_component BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_oid_component) #pragma redefine_extname CBB_add_asn1_oid_from_text BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_oid_from_text) +#pragma redefine_extname CBB_add_asn1_relative_oid_from_der_to_text BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_relative_oid_from_der_to_text) #pragma redefine_extname CBB_add_asn1_relative_oid_from_text BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_relative_oid_from_text) #pragma redefine_extname CBB_add_asn1_uint64 BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_uint64) #pragma redefine_extname CBB_add_asn1_uint64_with_tag BORINGSSL_ADD_USER_LABEL_AND_PREFIX(CBB_add_asn1_uint64_with_tag) @@ -3643,6 +3644,7 @@ #define CBB_add_asn1_octet_string BORINGSSL_ADD_PREFIX(CBB_add_asn1_octet_string) #define CBB_add_asn1_oid_component BORINGSSL_ADD_PREFIX(CBB_add_asn1_oid_component) #define CBB_add_asn1_oid_from_text BORINGSSL_ADD_PREFIX(CBB_add_asn1_oid_from_text) +#define CBB_add_asn1_relative_oid_from_der_to_text BORINGSSL_ADD_PREFIX(CBB_add_asn1_relative_oid_from_der_to_text) #define CBB_add_asn1_relative_oid_from_text BORINGSSL_ADD_PREFIX(CBB_add_asn1_relative_oid_from_text) #define CBB_add_asn1_uint64 BORINGSSL_ADD_PREFIX(CBB_add_asn1_uint64) #define CBB_add_asn1_uint64_with_tag BORINGSSL_ADD_PREFIX(CBB_add_asn1_uint64_with_tag)