diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 3905f5590..adf7aa544 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -36,6 +36,7 @@ fuzzer(ocsp_parse_ocsp_response_fuzzer pki) fuzzer(ocsp_parse_ocsp_single_response_fuzzer pki) fuzzer(parse_authority_key_identifier_fuzzer pki) fuzzer(parse_certificate_fuzzer pki) +fuzzer(parse_crldp_fuzzer pki) fuzzer(pkcs12) fuzzer(pkcs8) fuzzer(privkey) diff --git a/fuzz/parse_crldp_fuzzer.cc b/fuzz/parse_crldp_fuzzer.cc new file mode 100644 index 000000000..ebf3ba203 --- /dev/null +++ b/fuzz/parse_crldp_fuzzer.cc @@ -0,0 +1,24 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include + +#include "../pki/parse_certificate.h" +#include "../pki/input.h" +#include + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + std::vector distribution_points; + + bool success = ParseCrlDistributionPoints(bssl::der::Input(data, size), + &distribution_points); + + if (success) { + // A valid CRLDistributionPoints must have at least 1 element. + BSSL_CHECK(!distribution_points.empty()); + } + + return 0; +} diff --git a/fuzz/parse_crldp_fuzzer_corpus/crldp_issuer_as_dirname.der b/fuzz/parse_crldp_fuzzer_corpus/crldp_issuer_as_dirname.der new file mode 100644 index 000000000..26241d235 --- /dev/null +++ b/fuzz/parse_crldp_fuzzer_corpus/crldp_issuer_as_dirname.der @@ -0,0 +1,3 @@ +0â0ß „ Ī0}1 0 UUS10U +Test Certificates 20111"0 U indirectCRL CA3 cRLIssuer1)0'U indirect CRL for indirectCRL CA3ĒVĪT0R1 0 UUS10U +Test Certificates 20111"0 U indirectCRL CA3 cRLIssuer \ No newline at end of file diff --git a/fuzz/parse_crldp_fuzzer_corpus/relative_name_and_reasons_and_multiple_dps.der b/fuzz/parse_crldp_fuzzer_corpus/relative_name_and_reasons_and_multiple_dps.der new file mode 100644 index 000000000..c81bcf3cd --- /dev/null +++ b/fuzz/parse_crldp_fuzzer_corpus/relative_name_and_reasons_and_multiple_dps.der @@ -0,0 +1 @@ +070 Ą1 0 UCRL1`0  Ī01 0 UCRL2Ÿ€ \ No newline at end of file diff --git a/pki/encode_values_unittest.cc b/pki/encode_values_unittest.cc index f3009c14a..ab424187e 100644 --- a/pki/encode_values_unittest.cc +++ b/pki/encode_values_unittest.cc @@ -14,7 +14,7 @@ namespace bssl::der::test { namespace { template -std::string_view ToStringPiece(const uint8_t (&data)[N]) { +std::string_view ToStringView(const uint8_t (&data)[N]) { return std::string_view(reinterpret_cast(data), N); } @@ -75,7 +75,7 @@ TEST(EncodeValuesTest, EncodeGeneralizedTime) { // Encode a time where no components have leading zeros. uint8_t out[kGeneralizedTimeLength]; ASSERT_TRUE(EncodeGeneralizedTime(time, out)); - EXPECT_EQ("20141218161259Z", ToStringPiece(out)); + EXPECT_EQ("20141218161259Z", ToStringView(out)); // Test bounds on all components. Note the encoding function does not validate // the input is a valid time, only that it is encodable. @@ -86,7 +86,7 @@ TEST(EncodeValuesTest, EncodeGeneralizedTime) { time.minutes = 0; time.seconds = 0; ASSERT_TRUE(EncodeGeneralizedTime(time, out)); - EXPECT_EQ("00000000000000Z", ToStringPiece(out)); + EXPECT_EQ("00000000000000Z", ToStringView(out)); time.year = 9999; time.month = 99; @@ -95,7 +95,7 @@ TEST(EncodeValuesTest, EncodeGeneralizedTime) { time.minutes = 99; time.seconds = 99; ASSERT_TRUE(EncodeGeneralizedTime(time, out)); - EXPECT_EQ("99999999999999Z", ToStringPiece(out)); + EXPECT_EQ("99999999999999Z", ToStringView(out)); time.year = 10000; EXPECT_FALSE(EncodeGeneralizedTime(time, out)); @@ -117,23 +117,23 @@ TEST(EncodeValuesTest, EncodeUTCTime) { // Encode a time where no components have leading zeros. uint8_t out[kUTCTimeLength]; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("141218161259Z", ToStringPiece(out)); + EXPECT_EQ("141218161259Z", ToStringView(out)); time.year = 2049; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("491218161259Z", ToStringPiece(out)); + EXPECT_EQ("491218161259Z", ToStringView(out)); time.year = 2000; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("001218161259Z", ToStringPiece(out)); + EXPECT_EQ("001218161259Z", ToStringView(out)); time.year = 1999; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("991218161259Z", ToStringPiece(out)); + EXPECT_EQ("991218161259Z", ToStringView(out)); time.year = 1950; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("501218161259Z", ToStringPiece(out)); + EXPECT_EQ("501218161259Z", ToStringView(out)); time.year = 2050; EXPECT_FALSE(EncodeUTCTime(time, out)); @@ -150,7 +150,7 @@ TEST(EncodeValuesTest, EncodeUTCTime) { time.minutes = 0; time.seconds = 0; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("000000000000Z", ToStringPiece(out)); + EXPECT_EQ("000000000000Z", ToStringView(out)); time.year = 1999; time.month = 99; @@ -159,7 +159,7 @@ TEST(EncodeValuesTest, EncodeUTCTime) { time.minutes = 99; time.seconds = 99; ASSERT_TRUE(EncodeUTCTime(time, out)); - EXPECT_EQ("999999999999Z", ToStringPiece(out)); + EXPECT_EQ("999999999999Z", ToStringView(out)); time.year = 2000; time.month = 100; diff --git a/pki/fillins/inet.h b/pki/fillins/inet.h deleted file mode 100644 index 905e95828..000000000 --- a/pki/fillins/inet.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef PKI_FILLINS_INET_H_ -#define PKI_FILLINS_INET_H_ - -#include - -#if defined(OPENSSL_WINDOWS) -#include -#else -#include -#endif // OPENSSL_WINDOWS - -#endif // PKI_FILLINS_INET_H_ diff --git a/pki/fillins/utf_string_conversions.cc b/pki/fillins/utf_string_conversions.cc deleted file mode 100644 index 934196423..000000000 --- a/pki/fillins/utf_string_conversions.cc +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "utf_string_conversions.h" - -namespace bssl { - -namespace fillins { - -static const size_t kMaxUTF8Bytes = 4; - -static size_t EncodeUTF8(uint32_t codepoint, char *out_buf) { - if (codepoint < 0x7f) { - out_buf[0] = codepoint; - return 1; - } - - if (codepoint <= 0x7ff) { - out_buf[0] = 0xc0 | (codepoint >> 6); - out_buf[1] = 0x80 | (codepoint & 0x3f); - return 2; - } - - if (codepoint <= 0xffff) { - out_buf[0] = 0xe0 | (codepoint >> 12); - out_buf[1] = 0x80 | ((codepoint >> 6) & 0x3f); - out_buf[2] = 0x80 | (codepoint & 0x3f); - return 3; - } - - out_buf[0] = 0xf0 | (codepoint >> 18); - out_buf[1] = 0x80 | ((codepoint >> 12) & 0x3f); - out_buf[2] = 0x80 | ((codepoint >> 6) & 0x3f); - out_buf[3] = 0x80 | (codepoint & 0x3f); - return 4; -} - -void WriteUnicodeCharacter(uint32_t codepoint, std::string *append_to) { - char buf[kMaxUTF8Bytes]; - const size_t num_bytes = EncodeUTF8(codepoint, buf); - append_to->append(buf, num_bytes); -} - -} // namespace fillins - -} // namespace bssl diff --git a/pki/fillins/utf_string_conversions.h b/pki/fillins/utf_string_conversions.h deleted file mode 100644 index c8cdbc1d5..000000000 --- a/pki/fillins/utf_string_conversions.h +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2023 The Chromium Authors -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BSSL_FILLINS_UTF_STRING_CONVERSIONS -#define BSSL_FILLINS_UTF_STRING_CONVERSIONS - -#include - -#include - -#define CBU_IS_SURROGATE(c) (((c)&0xfffff800) == 0xd800) - -#define CBU_IS_UNICODE_NONCHAR(c) \ - ((c) >= 0xfdd0 && ((uint32_t)(c) <= 0xfdef || ((c)&0xfffe) == 0xfffe) && \ - (uint32_t)(c) <= 0x10ffff) - -#define CBU_IS_UNICODE_CHAR(c) \ - ((uint32_t)(c) < 0xd800 || \ - ((uint32_t)(c) > 0xdfff && (uint32_t)(c) <= 0x10ffff && \ - !CBU_IS_UNICODE_NONCHAR(c))) - -namespace bssl { - -namespace fillins { - -OPENSSL_EXPORT void WriteUnicodeCharacter(uint32_t codepoint, - std::string *append_to); - -} // namespace fillins - -} // namespace bssl - -#endif // BSSL_FILLINS_UTF_STRING_CONVERSIONS diff --git a/pki/import_spec.json b/pki/import_spec.json index 2fc97e566..0594c3b8d 100644 --- a/pki/import_spec.json +++ b/pki/import_spec.json @@ -281,6 +281,7 @@ "net/cert/pki/parsed_certificate.h", "net/cert/pki/parse_certificate_fuzzer.cc", "net/cert/pki/parsed_certificate_unittest.cc", + "net/cert/pki/parse_crldp_fuzzer.cc", "net/cert/pki/parse_name.cc", "net/cert/pki/parse_name.h", "net/cert/pki/parse_name_unittest.cc", diff --git a/pki/ip_util.h b/pki/ip_util.h index a29f6e9cd..e78b9e613 100644 --- a/pki/ip_util.h +++ b/pki/ip_util.h @@ -14,9 +14,9 @@ namespace bssl { inline constexpr size_t kIPv4AddressSize = 4; inline constexpr size_t kIPv6AddressSize = 16; -// Returns whether `mask` is a valid netmask. I.e., whether it the length of an -// IPv4 or IPv6 address, and is some number of ones, followed by some number of -// zeros. +// Returns whether `mask` is a valid netmask. I.e., whether it is the length of +// an IPv4 or IPv6 address, and is some number of ones, followed by some number +// of zeros. OPENSSL_EXPORT bool IsValidNetmask(der::Input mask); // Returns whether `addr1` and `addr2` are equal under the netmask `mask`. diff --git a/pki/parse_values.cc b/pki/parse_values.cc index 7c142f8c8..505a10cde 100644 --- a/pki/parse_values.cc +++ b/pki/parse_values.cc @@ -4,17 +4,13 @@ #include "parse_values.h" -#include -#include - +#include -#include "fillins/fillins_string_util.h" +#include -#include "fillins/utf_string_conversions.h" -#include "fillins/inet.h" -#include "fillins/utf_string_conversions.h" #include #include +#include namespace bssl::der { @@ -116,7 +112,7 @@ bool ValidateGeneralizedTime(const GeneralizedTime& time) { } break; default: - abort(); //NOTREACHED_NORETURN; + abort(); } return true; } @@ -369,7 +365,7 @@ bool ParseVisibleString(Input in, std::string* out) { bool ParsePrintableString(Input in, std::string* out) { for (char c : in.AsStringView()) { - if (!(fillins::IsAsciiAlpha(c) || c == ' ' || (c >= '\'' && c <= ':') || + if (!(OPENSSL_isalpha(c) || c == ' ' || (c >= '\'' && c <= ':') || c == '=' || c == '?')) { return false; } @@ -402,44 +398,50 @@ bool ParseTeletexStringAsLatin1(Input in, std::string* out) { } bool ParseUniversalString(Input in, std::string* out) { - if (in.Length() % 4 != 0) + if (in.Length() % 4 != 0) { return false; + } - out->clear(); - std::vector in_32bit(in.Length() / 4); - if (in.Length()) - memcpy(in_32bit.data(), in.UnsafeData(), in.Length()); - for (const uint32_t c : in_32bit) { - // UniversalString is UCS-4 in big-endian order. - auto codepoint = static_cast(ntohl(c)); - if (!CBU_IS_UNICODE_CHAR(codepoint)) - return false; + CBS cbs; + CBS_init(&cbs, in.UnsafeData(), in.Length()); + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), in.Length())) { + return false; + } - fillins::WriteUnicodeCharacter(codepoint, out); + while (CBS_len(&cbs) != 0) { + uint32_t c; + if (!CBS_get_utf32_be(&cbs, &c) || // + !CBB_add_utf8(cbb.get(), c)) { + return false; + } } + + out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); return true; } bool ParseBmpString(Input in, std::string* out) { - if (in.Length() % 2 != 0) + if (in.Length() % 2 != 0) { return false; + } - out->clear(); - std::vector in_16bit(in.Length() / 2); - if (in.Length()) - memcpy(in_16bit.data(), in.UnsafeData(), in.Length()); - for (const uint16_t c : in_16bit) { - // BMPString is UCS-2 in big-endian order. - uint32_t codepoint = ntohs(c); - - // BMPString only supports codepoints in the Basic Multilingual Plane; - // surrogates are not allowed. CBU_IS_UNICODE_CHAR excludes the surrogate - // code points, among other invalid values. - if (!CBU_IS_UNICODE_CHAR(codepoint)) - return false; + CBS cbs; + CBS_init(&cbs, in.UnsafeData(), in.Length()); + bssl::ScopedCBB cbb; + if (!CBB_init(cbb.get(), in.Length())) { + return false; + } - fillins::WriteUnicodeCharacter(codepoint, out); + while (CBS_len(&cbs) != 0) { + uint32_t c; + if (!CBS_get_ucs2_be(&cbs, &c) || // + !CBB_add_utf8(cbb.get(), c)) { + return false; + } } + + out->assign(CBB_data(cbb.get()), CBB_data(cbb.get()) + CBB_len(cbb.get())); return true; } diff --git a/sources.cmake b/sources.cmake index 0fab297df..d2e15c737 100644 --- a/sources.cmake +++ b/sources.cmake @@ -356,7 +356,6 @@ set( pki/fillins/fillins_base64.cc pki/fillins/openssl_util.cc pki/fillins/fillins_string_util.cc - pki/fillins/utf_string_conversions.cc pki/general_names.cc pki/input.cc pki/ip_util.cc