summaryrefslogtreecommitdiff
path: root/src/crypto
diff options
context:
space:
mode:
authorRobert Sloan <varomodt@google.com>2017-12-04 11:49:16 -0800
committerRobert Sloan <varomodt@google.com>2017-12-04 11:49:25 -0800
commita815d5abd1078d03df3278e5e3d512c7f6a11f9a (patch)
tree4ed7eaa0852af5b2ee35d5ceb5f1b84edb3bfe4c /src/crypto
parent99319a18ffbf8991a8e752b4b8dacc9d39cdbd31 (diff)
downloadboringssl-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.c128
-rw-r--r--src/crypto/bio/bio_test.cc1
-rw-r--r--src/crypto/bytestring/ber.c5
-rw-r--r--src/crypto/bytestring/bytestring_test.cc254
-rw-r--r--src/crypto/bytestring/cbb.c128
-rw-r--r--src/crypto/bytestring/cbs.c154
-rw-r--r--src/crypto/err/obj.errordata1
-rw-r--r--src/crypto/fipsmodule/bn/rsaz_exp.c4
-rw-r--r--src/crypto/fipsmodule/ec/ec.c44
-rw-r--r--src/crypto/fipsmodule/ec/ec_test.cc46
-rw-r--r--src/crypto/obj/obj.c177
-rw-r--r--src/crypto/x509/x509_test.cc41
-rw-r--r--src/crypto/x509v3/v3_utl.c43
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(&copy, &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(&copy, &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(&copy) != 0) {
+ if (!parse_base128_integer(&copy, &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;