diff options
author | Robert Sloan <varomodt@google.com> | 2017-12-04 11:49:16 -0800 |
---|---|---|
committer | Robert Sloan <varomodt@google.com> | 2017-12-04 11:49:25 -0800 |
commit | a815d5abd1078d03df3278e5e3d512c7f6a11f9a (patch) | |
tree | 4ed7eaa0852af5b2ee35d5ceb5f1b84edb3bfe4c /src/crypto | |
parent | 99319a18ffbf8991a8e752b4b8dacc9d39cdbd31 (diff) | |
download | boringssl-a815d5abd1078d03df3278e5e3d512c7f6a11f9a.tar.gz |
external/boringssl: Sync to a5462d3050ac6a68ab488450bf5856475dbef992.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/27bc0f26c8d132df04f5b0b173aefeb8aaa13c33..a5462d3050ac6a68ab488450bf5856475dbef992
Test: BoringSSL CTS Presubmits
Change-Id: Ieac8258ca12c1fcbdc00196d7d3f3fc0635f94e3
Diffstat (limited to 'src/crypto')
-rw-r--r-- | src/crypto/asn1/a_object.c | 128 | ||||
-rw-r--r-- | src/crypto/bio/bio_test.cc | 1 | ||||
-rw-r--r-- | src/crypto/bytestring/ber.c | 5 | ||||
-rw-r--r-- | src/crypto/bytestring/bytestring_test.cc | 254 | ||||
-rw-r--r-- | src/crypto/bytestring/cbb.c | 128 | ||||
-rw-r--r-- | src/crypto/bytestring/cbs.c | 154 | ||||
-rw-r--r-- | src/crypto/err/obj.errordata | 1 | ||||
-rw-r--r-- | src/crypto/fipsmodule/bn/rsaz_exp.c | 4 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec.c | 44 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec_test.cc | 46 | ||||
-rw-r--r-- | src/crypto/obj/obj.c | 177 | ||||
-rw-r--r-- | src/crypto/x509/x509_test.cc | 41 | ||||
-rw-r--r-- | src/crypto/x509v3/v3_utl.c | 43 |
13 files changed, 525 insertions, 501 deletions
diff --git a/src/crypto/asn1/a_object.c b/src/crypto/asn1/a_object.c index a710addd..005e37d5 100644 --- a/src/crypto/asn1/a_object.c +++ b/src/crypto/asn1/a_object.c @@ -87,134 +87,6 @@ int i2d_ASN1_OBJECT(ASN1_OBJECT *a, unsigned char **pp) return (objsize); } -int a2d_ASN1_OBJECT(unsigned char *out, int olen, const char *buf, int num) -{ - int i, first, len = 0, c, use_bn; - char ftmp[24], *tmp = ftmp; - int tmpsize = sizeof ftmp; - const char *p; - unsigned long l; - BIGNUM *bl = NULL; - - if (num == 0) - return (0); - else if (num == -1) - num = strlen(buf); - - p = buf; - c = *(p++); - num--; - if ((c >= '0') && (c <= '2')) { - first = c - '0'; - } else { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_FIRST_NUM_TOO_LARGE); - goto err; - } - - if (num <= 0) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_MISSING_SECOND_NUMBER); - goto err; - } - c = *(p++); - num--; - for (;;) { - if (num <= 0) - break; - if ((c != '.') && (c != ' ')) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_SEPARATOR); - goto err; - } - l = 0; - use_bn = 0; - for (;;) { - if (num <= 0) - break; - num--; - c = *(p++); - if ((c == ' ') || (c == '.')) - break; - if ((c < '0') || (c > '9')) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_INVALID_DIGIT); - goto err; - } - if (!use_bn && l >= ((ULONG_MAX - 80) / 10L)) { - use_bn = 1; - if (!bl) - bl = BN_new(); - if (!bl || !BN_set_word(bl, l)) - goto err; - } - if (use_bn) { - if (!BN_mul_word(bl, 10L) - || !BN_add_word(bl, c - '0')) - goto err; - } else - l = l * 10L + (long)(c - '0'); - } - if (len == 0) { - if ((first < 2) && (l >= 40)) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_SECOND_NUMBER_TOO_LARGE); - goto err; - } - if (use_bn) { - if (!BN_add_word(bl, first * 40)) - goto err; - } else - l += (long)first *40; - } - i = 0; - if (use_bn) { - int blsize; - blsize = BN_num_bits(bl); - blsize = (blsize + 6) / 7; - if (blsize > tmpsize) { - if (tmp != ftmp) - OPENSSL_free(tmp); - tmpsize = blsize + 32; - tmp = OPENSSL_malloc(tmpsize); - if (!tmp) - goto err; - } - while (blsize--) { - BN_ULONG t = BN_div_word(bl, 0x80L); - if (t == (BN_ULONG)-1) - goto err; - tmp[i++] = (unsigned char)t; - } - } else { - - for (;;) { - tmp[i++] = (unsigned char)l & 0x7f; - l >>= 7L; - if (l == 0L) - break; - } - - } - if (out != NULL) { - if (len + i > olen) { - OPENSSL_PUT_ERROR(ASN1, ASN1_R_BUFFER_TOO_SMALL); - goto err; - } - while (--i > 0) - out[len++] = tmp[i] | 0x80; - out[len++] = tmp[0]; - } else - len += i; - } - if (tmp != ftmp) - OPENSSL_free(tmp); - if (bl) - BN_free(bl); - return (len); - err: - if (tmp != ftmp) - OPENSSL_free(tmp); - if (bl) - BN_free(bl); - return (0); -} - int i2t_ASN1_OBJECT(char *buf, int buf_len, ASN1_OBJECT *a) { return OBJ_obj2txt(buf, buf_len, a, 0); diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc index eb54f7e1..8479c8e8 100644 --- a/src/crypto/bio/bio_test.cc +++ b/src/crypto/bio/bio_test.cc @@ -27,6 +27,7 @@ #if !defined(OPENSSL_WINDOWS) #include <arpa/inet.h> +#include <errno.h> #include <fcntl.h> #include <netinet/in.h> #include <string.h> diff --git a/src/crypto/bytestring/ber.c b/src/crypto/bytestring/ber.c index bb5e17c4..4dc94f6f 100644 --- a/src/crypto/bytestring/ber.c +++ b/src/crypto/bytestring/ber.c @@ -29,7 +29,10 @@ static const unsigned 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) { - switch (tag & ~CBS_ASN1_CONSTRUCTED) { + if ((tag & 0xc0) != 0) { + return 0; + } + switch (tag & 0x1f) { 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 7e3d453d..5a6a5c18 100644 --- a/src/crypto/bytestring/bytestring_test.cc +++ b/src/crypto/bytestring/bytestring_test.cc @@ -123,27 +123,27 @@ TEST(CBSTest, GetASN1) { uint64_t value; CBS_init(&data, kData1, sizeof(kData1)); - EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_BOOLEAN)); - EXPECT_TRUE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x1)); + EXPECT_TRUE(CBS_peek_asn1_tag(&data, 0x30)); - ASSERT_TRUE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBS_get_asn1(&data, &contents, 0x30)); 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, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData3, sizeof(kData3)); // zero byte length of length - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData4, sizeof(kData4)); // long form mistakenly used. - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData5, sizeof(kData5)); // length takes too many bytes. - EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30)); CBS_init(&data, kData1, sizeof(kData1)); // wrong tag. @@ -151,72 +151,56 @@ TEST(CBSTest, GetASN1) { CBS_init(&data, NULL, 0); // peek at empty data. - EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE)); + EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x30)); CBS_init(&data, NULL, 0); // optional elements at empty data. - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, NULL, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0)); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42)); EXPECT_EQ(42u, value); CBS_init(&data, kData6, sizeof(kData6)); // optional element. - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); - ASSERT_TRUE(CBS_get_optional_asn1( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa1)); 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, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0)); EXPECT_FALSE(present); EXPECT_EQ(0u, CBS_len(&contents)); - ASSERT_TRUE(CBS_get_optional_asn1_octet_string( - &data, &contents, &present, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + ASSERT_TRUE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)); 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, - CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1)); + EXPECT_FALSE( + CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)); CBS_init(&data, kData8, sizeof(kData8)); // optional integer. - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42)); EXPECT_EQ(42u, value); - ASSERT_TRUE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42)); + ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)); EXPECT_EQ(1u, value); CBS_init(&data, kData9, sizeof(kData9)); // invalid optional integer. - EXPECT_FALSE(CBS_get_optional_asn1_uint64( - &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42)); + EXPECT_FALSE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)); unsigned tag; CBS_init(&data, kData1, sizeof(kData1)); @@ -233,54 +217,6 @@ TEST(CBSTest, GetASN1) { 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}; @@ -480,42 +416,15 @@ TEST(CBBTest, Misuse) { } TEST(CBBTest, ASN1) { - 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, - }; + static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3}; 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, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); 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); @@ -523,7 +432,7 @@ TEST(CBBTest, ASN1) { std::vector<uint8_t> test_data(100000, 0x42); ASSERT_TRUE(CBB_init(cbb.get(), 0)); - ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 130)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -533,7 +442,7 @@ TEST(CBBTest, ASN1) { 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, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 1000)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -543,8 +452,8 @@ TEST(CBBTest, ASN1) { 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, CBS_ASN1_SEQUENCE)); - ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, CBS_ASN1_SEQUENCE)); + ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30)); + ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, 0x30)); ASSERT_TRUE(CBB_add_bytes(&inner_contents, test_data.data(), 100000)); ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len)); scoper.reset(buf); @@ -581,12 +490,6 @@ TEST(CBSTest, BerConvert) { 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, @@ -631,8 +534,6 @@ TEST(CBSTest, BerConvert) { 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, @@ -886,3 +787,98 @@ TEST(CBSTest, BitString) { CBS_asn1_bitstring_has_bit(&cbs, test.bit)); } } + +TEST(CBBTest, AddOIDFromText) { + const struct { + const char *text; + std::vector<uint8_t> der; + } kValidOIDs[] = { + // Some valid values. + {"0.0", {0x00}}, + {"0.2.3.4", {0x2, 0x3, 0x4}}, + {"1.2.3.4", {0x2a, 0x3, 0x4}}, + {"2.2.3.4", {0x52, 0x3, 0x4}}, + {"1.2.840.113554.4.1.72585", + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09}}, + // Test edge cases around the first component. + {"0.39", {0x27}}, + {"1.0", {0x28}}, + {"1.39", {0x4f}}, + {"2.0", {0x50}}, + {"2.1", {0x51}}, + {"2.40", {0x78}}, + // Edge cases near an overflow. + {"1.2.18446744073709551615", + {0x2a, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}}, + {"2.18446744073709551535", + {0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f}}, + }; + + const char *kInvalidTexts[] = { + // Invalid second component. + "0.40", + "1.40", + // Invalid first component. + "3.1", + // The empty string is not an OID. + "", + // No empty components. + ".1.2.3.4.5", + "1..2.3.4.5", + "1.2.3.4.5.", + // There must be at least two components. + "1", + // No extra leading zeros. + "00.1.2.3.4", + "01.1.2.3.4", + // Overflow for both components or 40*A + B. + "1.2.18446744073709551616", + "2.18446744073709551536", + }; + + const std::vector<uint8_t> kInvalidDER[] = { + // The empty string is not an OID. + {}, + // Non-minimal representation. + {0x80, 0x01}, + // Overflow. This is the DER representation of + // 1.2.840.113554.4.1.72585.18446744073709551616. (The final value is + // 2^64.) + {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x04, 0x01, 0x84, 0xb7, 0x09, + 0x82, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00}, + }; + + for (const auto &t : kValidOIDs) { + SCOPED_TRACE(t.text); + + bssl::ScopedCBB cbb; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + ASSERT_TRUE(CBB_add_asn1_oid_from_text(cbb.get(), t.text, strlen(t.text))); + uint8_t *out; + size_t len; + ASSERT_TRUE(CBB_finish(cbb.get(), &out, &len)); + bssl::UniquePtr<uint8_t> free_out(out); + EXPECT_EQ(Bytes(t.der), Bytes(out, len)); + + CBS cbs; + CBS_init(&cbs, t.der.data(), t.der.size()); + bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); + ASSERT_TRUE(text.get()); + EXPECT_STREQ(t.text, text.get()); + } + + for (const char *t : kInvalidTexts) { + SCOPED_TRACE(t); + bssl::ScopedCBB cbb; + ASSERT_TRUE(CBB_init(cbb.get(), 0)); + EXPECT_FALSE(CBB_add_asn1_oid_from_text(cbb.get(), t, strlen(t))); + } + + for (const auto &t : kInvalidDER) { + SCOPED_TRACE(Bytes(t)); + CBS cbs; + CBS_init(&cbs, t.data(), t.size()); + bssl::UniquePtr<char> text(CBS_asn1_oid_to_text(&cbs)); + EXPECT_FALSE(text); + } +} diff --git a/src/crypto/bytestring/cbb.c b/src/crypto/bytestring/cbb.c index b1afe7d5..f8f5e0f1 100644 --- a/src/crypto/bytestring/cbb.c +++ b/src/crypto/bytestring/cbb.c @@ -15,6 +15,7 @@ #include <openssl/bytestring.h> #include <assert.h> +#include <limits.h> #include <string.h> #include <openssl/mem.h> @@ -328,37 +329,44 @@ int CBB_add_u24_length_prefixed(CBB *cbb, CBB *out_contents) { return cbb_add_length_prefixed(cbb, out_contents, 3); } -int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag) { - if (!CBB_flush(cbb)) { - return 0; +// add_base128_integer encodes |v| as a big-endian base-128 integer where the +// high bit of each byte indicates where there is more data. This is the +// encoding used in DER for both high tag number form and OID components. +static int add_base128_integer(CBB *cbb, uint64_t v) { + unsigned len_len = 0; + uint64_t copy = v; + while (copy > 0) { + len_len++; + copy >>= 7; } - - // 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)) { + if (len_len == 0) { + len_len = 1; // Zero is encoded with one byte. + } + for (unsigned i = len_len - 1; i < len_len; i--) { + uint8_t byte = (v >> (7 * i)) & 0x7f; + if (i != 0) { + // The high bit denotes whether there is more data. + byte |= 0x80; + } + if (!CBB_add_u8(cbb, byte)) { return 0; } + } + return 1; +} - unsigned len_len = 0; - unsigned copy = tag_number; - while (copy > 0) { - len_len++; - copy >>= 7; - } - for (unsigned i = len_len - 1; i < len_len; i--) { - uint8_t byte = (tag_number >> (7 * i)) & 0x7f; - if (i != 0) { - // The high bit denotes whether there is more data. - byte |= 0x80; - } - if (!CBB_add_u8(cbb, byte)) { - return 0; - } - } - } else if (!CBB_add_u8(cbb, tag_bits | tag_number)) { +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; + return 0; + } + + if (!CBB_flush(cbb) || + // |tag|'s representation matches the DER encoding. + !CBB_add_u8(cbb, (uint8_t)tag)) { return 0; } @@ -492,3 +500,69 @@ int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { return CBB_flush(cbb); } + +// parse_dotted_decimal parses one decimal component from |cbs|, where |cbs| is +// an OID literal, e.g., "1.2.840.113554.4.1.72585". It consumes both the +// component and the dot, so |cbs| may be passed into the function again for the +// next value. +static int parse_dotted_decimal(CBS *cbs, uint64_t *out) { + *out = 0; + int seen_digit = 0; + for (;;) { + // Valid terminators for a component are the end of the string or a + // non-terminal dot. If the string ends with a dot, this is not a valid OID + // string. + uint8_t u; + if (!CBS_get_u8(cbs, &u) || + (u == '.' && CBS_len(cbs) > 0)) { + break; + } + if (u < '0' || u > '9' || + // Forbid stray leading zeros. + (seen_digit && *out == 0) || + // Check for overflow. + *out > UINT64_MAX / 10 || + *out * 10 > UINT64_MAX - (u - '0')) { + return 0; + } + *out = *out * 10 + (u - '0'); + seen_digit = 1; + } + // The empty string is not a legal OID component. + return seen_digit; +} + +int CBB_add_asn1_oid_from_text(CBB *cbb, const char *text, size_t len) { + if (!CBB_flush(cbb)) { + return 0; + } + + CBS cbs; + CBS_init(&cbs, (const uint8_t *)text, len); + + // OIDs must have at least two components. + uint64_t a, b; + if (!parse_dotted_decimal(&cbs, &a) || + !parse_dotted_decimal(&cbs, &b)) { + return 0; + } + + // The first component is encoded as 40 * |a| + |b|. This assumes that |a| is + // 0, 1, or 2 and that, when it is 0 or 1, |b| is at most 39. + if (a > 2 || + (a < 2 && b > 39) || + b > UINT64_MAX - 80 || + !add_base128_integer(cbb, 40u * a + b)) { + return 0; + } + + // The remaining components are encoded unmodified. + while (CBS_len(&cbs) > 0) { + if (!parse_dotted_decimal(&cbs, &a) || + !add_base128_integer(cbb, a)) { + return 0; + } + } + + return 1; +} diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c index d96371ce..f3fc8636 100644 --- a/src/crypto/bytestring/cbs.c +++ b/src/crypto/bytestring/cbs.c @@ -12,11 +12,16 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#if !defined(__STDC_FORMAT_MACROS) +#define __STDC_FORMAT_MACROS +#endif + #include <openssl/buf.h> #include <openssl/mem.h> #include <openssl/bytestring.h> #include <assert.h> +#include <inttypes.h> #include <string.h> #include "internal.h" @@ -175,53 +180,36 @@ int CBS_get_u24_length_prefixed(CBS *cbs, CBS *out) { return cbs_get_length_prefixed(cbs, out, 3); } -static int parse_asn1_tag(CBS *cbs, unsigned *out) { - uint8_t tag_byte; - if (!CBS_get_u8(cbs, &tag_byte)) { - return 0; - } - - // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag - // number no greater than 30. - // - // 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. This parser only supports tag - // numbers less than 31 (and thus single-byte tags). - unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT; - unsigned tag_number = tag_byte & 0x1f; - if (tag_number == 0x1f) { - tag_number = 0; - for (;;) { - if (!CBS_get_u8(cbs, &tag_byte) || - ((tag_number << 7) >> 7) != tag_number) { - return 0; - } - tag_number = (tag_number << 7) | (tag_byte & 0x7f); - // The tag must be represented in the minimal number of bytes. - if (tag_number == 0) { - return 0; - } - if ((tag_byte & 0x80) == 0) { - break; - } +// parse_base128_integer reads a big-endian base-128 integer from |cbs| and sets +// |*out| to the result. This is the encoding used in DER for both high tag +// number form and OID components. +static int parse_base128_integer(CBS *cbs, uint64_t *out) { + uint64_t v = 0; + uint8_t b; + do { + if (!CBS_get_u8(cbs, &b)) { + return 0; } - if (// Check the tag number is within our supported bounds. - tag_number > CBS_ASN1_TAG_NUMBER_MASK || - // Small tag numbers should have used low tag number form. - tag_number < 0x1f) { + if ((v >> (64 - 7)) != 0) { + // The value is too large. return 0; } - } + if (v == 0 && b == 0x80) { + // The value must be minimally encoded. + return 0; + } + v = (v << 7) | (b & 0x7f); - tag |= tag_number; + // Values end at an octet with the high bit cleared. + } while (b & 0x80); - *out = tag; + *out = v; 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; @@ -229,29 +217,34 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, out = &throwaway; } - unsigned tag; - if (!parse_asn1_tag(&header, &tag)) { + if (!CBS_get_u8(&header, &tag) || + !CBS_get_u8(&header, &length_byte)) { return 0; } - if (out_tag != NULL) { - *out_tag = tag; - } - uint8_t length_byte; - if (!CBS_get_u8(&header, &length_byte)) { + // ITU-T X.690 section 8.1.2.3 specifies the format for identifiers with a tag + // number no greater than 30. + // + // 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. This parser only supports tag + // numbers less than 31 (and thus single-byte tags). + if ((tag & 0x1f) == 0x1f) { return 0; } - size_t header_len = CBS_len(cbs) - CBS_len(&header); + if (out_tag != NULL) { + *out_tag = tag; + } 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) + header_len; + len = ((size_t) length_byte) + 2; if (out_header_len != NULL) { - *out_header_len = header_len; + *out_header_len = 2; } } else { // The high bit indicate that this is the long form, while the next 7 bits @@ -263,9 +256,9 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) { // indefinite length if (out_header_len != NULL) { - *out_header_len = header_len; + *out_header_len = 2; } - return CBS_get_bytes(cbs, out, header_len); + return CBS_get_bytes(cbs, out, 2); } // ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be @@ -288,13 +281,13 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return 0; } len = len32; - if (len + header_len + num_bytes < len) { + if (len + 2 + num_bytes < len) { // Overflow. return 0; } - len += header_len + num_bytes; + len += 2 + num_bytes; if (out_header_len != NULL) { - *out_header_len = header_len + num_bytes; + *out_header_len = 2 + num_bytes; } } @@ -362,10 +355,7 @@ int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value) { if (CBS_len(cbs) < 1) { return 0; } - - CBS copy = *cbs; - unsigned actual_tag; - return parse_asn1_tag(©, &actual_tag) && tag_value == actual_tag; + return CBS_data(cbs)[0] == tag_value; } int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { @@ -527,3 +517,55 @@ int CBS_asn1_bitstring_has_bit(const CBS *cbs, unsigned bit) { return byte_num < CBS_len(cbs) && (CBS_data(cbs)[byte_num] & (1 << bit_num)) != 0; } + +static int add_decimal(CBB *out, uint64_t v) { + char buf[DECIMAL_SIZE(uint64_t) + 1]; + BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v); + return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); +} + +char *CBS_asn1_oid_to_text(const CBS *cbs) { + CBB cbb; + if (!CBB_init(&cbb, 32)) { + goto err; + } + + CBS copy = *cbs; + // The first component is 40 * value1 + value2, where value1 is 0, 1, or 2. + uint64_t v; + if (!parse_base128_integer(©, &v)) { + goto err; + } + + if (v >= 80) { + if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || + !add_decimal(&cbb, v - 80)) { + goto err; + } + } else if (!add_decimal(&cbb, v / 40) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v % 40)) { + goto err; + } + + while (CBS_len(©) != 0) { + if (!parse_base128_integer(©, &v) || + !CBB_add_u8(&cbb, '.') || + !add_decimal(&cbb, v)) { + goto err; + } + } + + uint8_t *txt; + size_t txt_len; + if (!CBB_add_u8(&cbb, '\0') || + !CBB_finish(&cbb, &txt, &txt_len)) { + goto err; + } + + return (char *)txt; + +err: + CBB_cleanup(&cbb); + return NULL; +} diff --git a/src/crypto/err/obj.errordata b/src/crypto/err/obj.errordata index c54435ea..be134516 100644 --- a/src/crypto/err/obj.errordata +++ b/src/crypto/err/obj.errordata @@ -1 +1,2 @@ +OBJ,101,INVALID_OID_STRING OBJ,100,UNKNOWN_NID diff --git a/src/crypto/fipsmodule/bn/rsaz_exp.c b/src/crypto/fipsmodule/bn/rsaz_exp.c index d0090a66..cb9a233e 100644 --- a/src/crypto/fipsmodule/bn/rsaz_exp.c +++ b/src/crypto/fipsmodule/bn/rsaz_exp.c @@ -227,7 +227,9 @@ void RSAZ_1024_mod_exp_avx2(BN_ULONG result_norm[16], rsaz_1024_sqr_avx2(result, result, m, k0, 5); - wvalue = *((const unsigned short*)&p_str[index / 8]); + uint16_t wvalue_16; + memcpy(&wvalue_16, &p_str[index / 8], sizeof(wvalue_16)); + wvalue = wvalue_16; wvalue = (wvalue>> (index%8)) & 31; index-=5; diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c index 977cd265..266baa24 100644 --- a/src/crypto/fipsmodule/ec/ec.c +++ b/src/crypto/fipsmodule/ec/ec.c @@ -817,6 +817,24 @@ int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { return ec_GFp_simple_invert(group, a, ctx); } +static int arbitrary_bignum_to_scalar(const EC_GROUP *group, EC_SCALAR *out, + const BIGNUM *in, BN_CTX *ctx) { + const BIGNUM *order = EC_GROUP_get0_order(group); + if (BN_is_negative(in) || BN_num_bits(in) > BN_num_bits(order)) { + // This is an unusual input, so we do not guarantee constant-time + // processing, even ignoring |bn_correct_top|. + BN_CTX_start(ctx); + BIGNUM *tmp = BN_CTX_get(ctx); + int ok = tmp != NULL && + BN_nnmod(tmp, in, order, ctx) && + ec_bignum_to_scalar(group, out, tmp); + BN_CTX_end(ctx); + return ok; + } + + return ec_bignum_to_scalar(group, out, in); +} + int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) { // Previously, this function set |r| to the point at infinity if there was @@ -828,30 +846,27 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, return 0; } - // We cannot easily process arbitrary scalars in constant-time, and there is - // no need to do so. Require that scalars be the same size as the order. - // - // One could require they be fully reduced, but some consumers try to check - // that |order| * |pubkey| is the identity. This comes from following NIST SP - // 800-56A section 5.6.2.3.2. (Though all our curves have cofactor one, so - // this check isn't useful.) int ret = 0; EC_SCALAR g_scalar_storage, p_scalar_storage; EC_SCALAR *g_scalar_arg = NULL, *p_scalar_arg = NULL; - unsigned order_bits = BN_num_bits(&group->order); + BN_CTX *new_ctx = NULL; + if (ctx == NULL) { + new_ctx = BN_CTX_new(); + if (new_ctx == NULL) { + goto err; + } + ctx = new_ctx; + } + if (g_scalar != NULL) { - if (BN_is_negative(g_scalar) || BN_num_bits(g_scalar) > order_bits || - !ec_bignum_to_scalar(group, &g_scalar_storage, g_scalar)) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); + if (!arbitrary_bignum_to_scalar(group, &g_scalar_storage, g_scalar, ctx)) { goto err; } g_scalar_arg = &g_scalar_storage; } if (p_scalar != NULL) { - if (BN_is_negative(p_scalar) || BN_num_bits(p_scalar) > order_bits || - !ec_bignum_to_scalar(group, &p_scalar_storage, p_scalar)) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_SCALAR); + if (!arbitrary_bignum_to_scalar(group, &p_scalar_storage, p_scalar, ctx)) { goto err; } p_scalar_arg = &p_scalar_storage; @@ -860,6 +875,7 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, ret = ec_point_mul_scalar(group, r, g_scalar_arg, p, p_scalar_arg, ctx); err: + BN_CTX_free(new_ctx); OPENSSL_cleanse(&g_scalar_storage, sizeof(g_scalar_storage)); OPENSSL_cleanse(&p_scalar_storage, sizeof(p_scalar_storage)); return ret; diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc index 5e5ce948..139840e5 100644 --- a/src/crypto/fipsmodule/ec/ec_test.cc +++ b/src/crypto/fipsmodule/ec/ec_test.cc @@ -439,6 +439,52 @@ TEST_P(ECCurveTest, MulOrder) { << "p * order did not return point at infinity."; } +// Test that |EC_POINT_mul| works with out-of-range scalars. Even beyond the +// usual |bn_correct_top| disclaimer, we completely disclaim all hope here as a +// reduction is needed, but we'll compute the right answer. +TEST_P(ECCurveTest, MulOutOfRange) { + bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid)); + ASSERT_TRUE(group); + + bssl::UniquePtr<BIGNUM> n_minus_one(BN_dup(EC_GROUP_get0_order(group.get()))); + ASSERT_TRUE(n_minus_one); + ASSERT_TRUE(BN_sub_word(n_minus_one.get(), 1)); + + bssl::UniquePtr<BIGNUM> minus_one(BN_new()); + ASSERT_TRUE(minus_one); + ASSERT_TRUE(BN_one(minus_one.get())); + BN_set_negative(minus_one.get(), 1); + + bssl::UniquePtr<BIGNUM> seven(BN_new()); + ASSERT_TRUE(seven); + ASSERT_TRUE(BN_set_word(seven.get(), 7)); + + bssl::UniquePtr<BIGNUM> ten_n_plus_seven( + BN_dup(EC_GROUP_get0_order(group.get()))); + ASSERT_TRUE(ten_n_plus_seven); + ASSERT_TRUE(BN_mul_word(ten_n_plus_seven.get(), 10)); + ASSERT_TRUE(BN_add_word(ten_n_plus_seven.get(), 7)); + + bssl::UniquePtr<EC_POINT> point1(EC_POINT_new(group.get())), + point2(EC_POINT_new(group.get())); + ASSERT_TRUE(point1); + ASSERT_TRUE(point2); + + ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), n_minus_one.get(), + nullptr, nullptr, nullptr)); + ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), minus_one.get(), nullptr, + nullptr, nullptr)); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr)) + << "-1 * G and (n-1) * G did not give the same result"; + + ASSERT_TRUE(EC_POINT_mul(group.get(), point1.get(), seven.get(), nullptr, + nullptr, nullptr)); + ASSERT_TRUE(EC_POINT_mul(group.get(), point2.get(), ten_n_plus_seven.get(), + nullptr, nullptr, nullptr)); + EXPECT_EQ(0, EC_POINT_cmp(group.get(), point1.get(), point2.get(), nullptr)) + << "7 * G and (10n + 7) * G did not give the same result"; +} + // Test that 10×∞ + G = G. TEST_P(ECCurveTest, Mul) { bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(GetParam().nid)); diff --git a/src/crypto/obj/obj.c b/src/crypto/obj/obj.c index 52e265b0..a34d6dc0 100644 --- a/src/crypto/obj/obj.c +++ b/src/crypto/obj/obj.c @@ -389,16 +389,30 @@ const char *OBJ_nid2ln(int nid) { return obj->ln; } -ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { - int nid = NID_undef; - ASN1_OBJECT *op = NULL; - unsigned char *buf; - unsigned char *p; - const unsigned char *bufp; - int contents_len, total_len; +static ASN1_OBJECT *create_object_with_text_oid(int (*get_nid)(void), + const char *oid, + const char *short_name, + const char *long_name) { + uint8_t *buf; + size_t len; + CBB cbb; + if (!CBB_init(&cbb, 32) || + !CBB_add_asn1_oid_from_text(&cbb, oid, strlen(oid)) || + !CBB_finish(&cbb, &buf, &len)) { + OPENSSL_PUT_ERROR(OBJ, OBJ_R_INVALID_OID_STRING); + CBB_cleanup(&cbb); + return NULL; + } + ASN1_OBJECT *ret = ASN1_OBJECT_create(get_nid ? get_nid() : NID_undef, buf, + len, short_name, long_name); + OPENSSL_free(buf); + return ret; +} + +ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { if (!dont_search_names) { - nid = OBJ_sn2nid(s); + int nid = OBJ_sn2nid(s); if (nid == NID_undef) { nid = OBJ_ln2nid(s); } @@ -408,31 +422,7 @@ ASN1_OBJECT *OBJ_txt2obj(const char *s, int dont_search_names) { } } - // Work out size of content octets - contents_len = a2d_ASN1_OBJECT(NULL, 0, s, -1); - if (contents_len <= 0) { - return NULL; - } - // Work out total size - total_len = ASN1_object_size(0, contents_len, V_ASN1_OBJECT); - - buf = OPENSSL_malloc(total_len); - if (buf == NULL) { - OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE); - return NULL; - } - - p = buf; - // Write out tag+length - ASN1_put_object(&p, 0, contents_len, V_ASN1_OBJECT, V_ASN1_UNIVERSAL); - // Write out contents - a2d_ASN1_OBJECT(p, contents_len, s, -1); - - bufp = buf; - op = d2i_ASN1_OBJECT(NULL, &bufp, total_len); - OPENSSL_free(buf); - - return op; + return create_object_with_text_oid(NULL, s, NULL, NULL); } static int strlcpy_int(char *dst, const char *src, int dst_size) { @@ -444,36 +434,6 @@ static int strlcpy_int(char *dst, const char *src, int dst_size) { return (int)ret; } -static int parse_oid_component(CBS *cbs, uint64_t *out) { - uint64_t v = 0; - uint8_t b; - do { - if (!CBS_get_u8(cbs, &b)) { - return 0; - } - if ((v >> (64 - 7)) != 0) { - // The component is too large. - return 0; - } - if (v == 0 && b == 0x80) { - // The component must be minimally encoded. - return 0; - } - v = (v << 7) | (b & 0x7f); - - // Components end at an octet with the high bit cleared. - } while (b & 0x80); - - *out = v; - return 1; -} - -static int add_decimal(CBB *out, uint64_t v) { - char buf[DECIMAL_SIZE(uint64_t) + 1]; - BIO_snprintf(buf, sizeof(buf), "%" PRIu64, v); - return CBB_add_bytes(out, (const uint8_t *)buf, strlen(buf)); -} - int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, int always_return_oid) { // Python depends on the empty OID successfully encoding as the empty @@ -495,56 +455,19 @@ int OBJ_obj2txt(char *out, int out_len, const ASN1_OBJECT *obj, } } - CBB cbb; - if (!CBB_init(&cbb, 32)) { - goto err; - } - CBS cbs; CBS_init(&cbs, obj->data, obj->length); - - // The first component is 40 * value1 + value2, where value1 is 0, 1, or 2. - uint64_t v; - if (!parse_oid_component(&cbs, &v)) { - goto err; - } - - if (v >= 80) { - if (!CBB_add_bytes(&cbb, (const uint8_t *)"2.", 2) || - !add_decimal(&cbb, v - 80)) { - goto err; + char *txt = CBS_asn1_oid_to_text(&cbs); + if (txt == NULL) { + if (out_len > 0) { + out[0] = '\0'; } - } else if (!add_decimal(&cbb, v / 40) || - !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v % 40)) { - goto err; - } - - while (CBS_len(&cbs) != 0) { - if (!parse_oid_component(&cbs, &v) || - !CBB_add_u8(&cbb, '.') || - !add_decimal(&cbb, v)) { - goto err; - } - } - - uint8_t *txt; - size_t txt_len; - if (!CBB_add_u8(&cbb, '\0') || - !CBB_finish(&cbb, &txt, &txt_len)) { - goto err; + return -1; } - int ret = strlcpy_int(out, (const char *)txt, out_len); + int ret = strlcpy_int(out, txt, out_len); OPENSSL_free(txt); return ret; - -err: - CBB_cleanup(&cbb); - if (out_len > 0) { - out[0] = '\0'; - } - return -1; } static uint32_t hash_nid(const ASN1_OBJECT *obj) { @@ -621,41 +544,11 @@ static int obj_add_object(ASN1_OBJECT *obj) { } int OBJ_create(const char *oid, const char *short_name, const char *long_name) { - int ret = NID_undef; - ASN1_OBJECT *op = NULL; - unsigned char *buf = NULL; - int len; - - len = a2d_ASN1_OBJECT(NULL, 0, oid, -1); - if (len <= 0) { - goto err; - } - - buf = OPENSSL_malloc(len); - if (buf == NULL) { - OPENSSL_PUT_ERROR(OBJ, ERR_R_MALLOC_FAILURE); - goto err; - } - - len = a2d_ASN1_OBJECT(buf, len, oid, -1); - if (len == 0) { - goto err; - } - - op = (ASN1_OBJECT *)ASN1_OBJECT_create(obj_next_nid(), buf, len, short_name, - long_name); - if (op == NULL) { - goto err; - } - - if (obj_add_object(op)) { - ret = op->nid; + ASN1_OBJECT *op = + create_object_with_text_oid(obj_next_nid, oid, short_name, long_name); + if (op == NULL || + !obj_add_object(op)) { + return NID_undef; } - op = NULL; - -err: - ASN1_OBJECT_free(op); - OPENSSL_free(buf); - - return ret; + return op->nid; } diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index cd4e61d7..158fd458 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -26,6 +26,7 @@ #include <openssl/pem.h> #include <openssl/pool.h> #include <openssl/x509.h> +#include <openssl/x509v3.h> #include "../internal.h" @@ -834,7 +835,7 @@ TEST(X509Test, TestFromBuffer) { /* This ensures the X509 took a reference to |buf|, otherwise this will be a * reference to free memory and ASAN should notice. */ - ASSERT_EQ(0x30, enc_pointer[0]); + ASSERT_EQ(CBS_ASN1_SEQUENCE, enc_pointer[0]); } TEST(X509Test, TestFromBufferWithTrailingData) { @@ -996,3 +997,41 @@ TEST(X509Test, TestPrintUTCTIME) { std::string(reinterpret_cast<const char *>(contents), len)); } } + +TEST(X509Test, PrettyPrintIntegers) { + static const char *kTests[] = { + // Small numbers are pretty-printed in decimal. + "0", + "-1", + "1", + "42", + "-42", + "256", + "-256", + // Large numbers are pretty-printed in hex to avoid taking quadratic time. + "0x0123456789", + "-0x0123456789", + }; + for (const char *in : kTests) { + SCOPED_TRACE(in); + BIGNUM *bn = nullptr; + ASSERT_TRUE(BN_asc2bn(&bn, in)); + bssl::UniquePtr<BIGNUM> free_bn(bn); + + { + bssl::UniquePtr<ASN1_INTEGER> asn1(BN_to_ASN1_INTEGER(bn, nullptr)); + ASSERT_TRUE(asn1); + bssl::UniquePtr<char> out(i2s_ASN1_INTEGER(nullptr, asn1.get())); + ASSERT_TRUE(out.get()); + EXPECT_STREQ(in, out.get()); + } + + { + bssl::UniquePtr<ASN1_ENUMERATED> asn1(BN_to_ASN1_ENUMERATED(bn, nullptr)); + ASSERT_TRUE(asn1); + bssl::UniquePtr<char> out(i2s_ASN1_ENUMERATED(nullptr, asn1.get())); + ASSERT_TRUE(out.get()); + EXPECT_STREQ(in, out.get()); + } + } +} diff --git a/src/crypto/x509v3/v3_utl.c b/src/crypto/x509v3/v3_utl.c index feb3dc6a..7d109ee6 100644 --- a/src/crypto/x509v3/v3_utl.c +++ b/src/crypto/x509v3/v3_utl.c @@ -155,6 +155,45 @@ int X509V3_add_value_bool_nf(char *name, int asn1_bool, return 1; } +static char *bignum_to_string(const BIGNUM *bn) +{ + char *tmp, *ret; + size_t len; + + /* + * Display large numbers in hex and small numbers in decimal. Converting to + * decimal takes quadratic time and is no more useful than hex for large + * numbers. + */ + if (BN_num_bits(bn) < 32) { + return BN_bn2dec(bn); + } + + tmp = BN_bn2hex(bn); + if (tmp == NULL) { + return NULL; + } + + len = strlen(tmp) + 3; + ret = OPENSSL_malloc(len); + if (ret == NULL) { + OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); + OPENSSL_free(tmp); + return NULL; + } + + /* Prepend "0x", but place it after the "-" if negative. */ + if (tmp[0] == '-') { + BUF_strlcpy(ret, "-0x", len); + BUF_strlcat(ret, tmp + 1, len); + } else { + BUF_strlcpy(ret, "0x", len); + BUF_strlcat(ret, tmp, len); + } + OPENSSL_free(tmp); + return ret; +} + char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) { BIGNUM *bntmp = NULL; @@ -162,7 +201,7 @@ char *i2s_ASN1_ENUMERATED(X509V3_EXT_METHOD *method, ASN1_ENUMERATED *a) if (!a) return NULL; if (!(bntmp = ASN1_ENUMERATED_to_BN(a, NULL)) || - !(strtmp = BN_bn2dec(bntmp))) + !(strtmp = bignum_to_string(bntmp))) OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; @@ -175,7 +214,7 @@ char *i2s_ASN1_INTEGER(X509V3_EXT_METHOD *method, ASN1_INTEGER *a) if (!a) return NULL; if (!(bntmp = ASN1_INTEGER_to_BN(a, NULL)) || - !(strtmp = BN_bn2dec(bntmp))) + !(strtmp = bignum_to_string(bntmp))) OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); BN_free(bntmp); return strtmp; |