external/boringssl: Sync to 915c121bb5d424e09bf05c3aabf172a44e958e28.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/ea52ec98a56a40879b37493f3d1da1a1679e1fba..915c121bb5d424e09bf05c3aabf172a44e958e28
Test: BoringSSL CTS Presubmits
Change-Id: I3f5eba69372b484e19f4ca250c81f208aa5d3dc5
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION
index 49d8788..ed9a183 100644
--- a/BORINGSSL_REVISION
+++ b/BORINGSSL_REVISION
@@ -1 +1 @@
-ea52ec98a56a40879b37493f3d1da1a1679e1fba
+915c121bb5d424e09bf05c3aabf172a44e958e28
diff --git a/src/crypto/asn1/a_int.c b/src/crypto/asn1/a_int.c
index 8a4edd6..dd74550 100644
--- a/src/crypto/asn1/a_int.c
+++ b/src/crypto/asn1/a_int.c
@@ -347,40 +347,45 @@
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v)
{
- int j, k;
- unsigned int i;
- unsigned char buf[sizeof(long) + 1];
- long d;
-
- a->type = V_ASN1_INTEGER;
- if (a->length < (int)(sizeof(long) + 1)) {
- if (a->data != NULL)
- OPENSSL_free(a->data);
- if ((a->data =
- (unsigned char *)OPENSSL_malloc(sizeof(long) + 1)) != NULL)
- OPENSSL_memset((char *)a->data, 0, sizeof(long) + 1);
+ if (v >= 0) {
+ return ASN1_INTEGER_set_uint64(a, (uint64_t) v);
}
- if (a->data == NULL) {
+
+ if (!ASN1_INTEGER_set_uint64(a, 0 - (uint64_t) v)) {
+ return 0;
+ }
+
+ a->type = V_ASN1_NEG_INTEGER;
+ return 1;
+}
+
+int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v)
+{
+ uint8_t *const newdata = OPENSSL_malloc(sizeof(uint64_t));
+ if (newdata == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
- return (0);
- }
- d = v;
- if (d < 0) {
- d = -d;
- a->type = V_ASN1_NEG_INTEGER;
+ return 0;
}
- for (i = 0; i < sizeof(long); i++) {
- if (d == 0)
+ OPENSSL_free(out->data);
+ out->data = newdata;
+ v = CRYPTO_bswap8(v);
+ memcpy(out->data, &v, sizeof(v));
+
+ out->type = V_ASN1_INTEGER;
+
+ size_t leading_zeros;
+ for (leading_zeros = 0; leading_zeros < sizeof(uint64_t) - 1;
+ leading_zeros++) {
+ if (out->data[leading_zeros] != 0) {
break;
- buf[i] = (int)d & 0xff;
- d >>= 8;
+ }
}
- j = 0;
- for (k = i - 1; k >= 0; k--)
- a->data[j++] = buf[k];
- a->length = j;
- return (1);
+
+ out->length = sizeof(uint64_t) - leading_zeros;
+ OPENSSL_memmove(out->data, out->data + leading_zeros, out->length);
+
+ return 1;
}
long ASN1_INTEGER_get(const ASN1_INTEGER *a)
diff --git a/src/crypto/asn1/asn1_test.cc b/src/crypto/asn1/asn1_test.cc
index accf3ba..7c114dd 100644
--- a/src/crypto/asn1/asn1_test.cc
+++ b/src/crypto/asn1/asn1_test.cc
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <gtest/gtest.h>
+#include <limits.h>
#include <openssl/asn1.h>
#include <openssl/err.h>
@@ -60,3 +61,30 @@
EXPECT_EQ(Bytes(&kZero, 1), Bytes(obj->value.asn1_string->data,
obj->value.asn1_string->length));
}
+
+TEST(ASN1Test, IntegerSetting) {
+ bssl::UniquePtr<ASN1_INTEGER> by_bn(M_ASN1_INTEGER_new());
+ bssl::UniquePtr<ASN1_INTEGER> by_long(M_ASN1_INTEGER_new());
+ bssl::UniquePtr<ASN1_INTEGER> by_uint64(M_ASN1_INTEGER_new());
+ bssl::UniquePtr<BIGNUM> bn(BN_new());
+
+ const std::vector<int64_t> kValues = {
+ LONG_MIN, -2, -1, 0, 1, 2, 0xff, 0x100, 0xffff, 0x10000, LONG_MAX,
+ };
+ for (const auto &i : kValues) {
+ SCOPED_TRACE(i);
+
+ ASSERT_EQ(1, ASN1_INTEGER_set(by_long.get(), i));
+ const uint64_t abs = i < 0 ? (0 - (uint64_t) i) : i;
+ ASSERT_TRUE(BN_set_u64(bn.get(), abs));
+ BN_set_negative(bn.get(), i < 0);
+ ASSERT_TRUE(BN_to_ASN1_INTEGER(bn.get(), by_bn.get()));
+
+ EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_long.get()));
+
+ if (i >= 0) {
+ ASSERT_EQ(1, ASN1_INTEGER_set_uint64(by_uint64.get(), i));
+ EXPECT_EQ(0, ASN1_INTEGER_cmp(by_bn.get(), by_uint64.get()));
+ }
+ }
+}
diff --git a/src/crypto/bytestring/ber.c b/src/crypto/bytestring/ber.c
index 4dc94f6..bb5e17c 100644
--- a/src/crypto/bytestring/ber.c
+++ b/src/crypto/bytestring/ber.c
@@ -29,10 +29,7 @@
// 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) {
- if ((tag & 0xc0) != 0) {
- return 0;
- }
- switch (tag & 0x1f) {
+ switch (tag & ~CBS_ASN1_CONSTRUCTED) {
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 5a6a5c1..1969e73 100644
--- a/src/crypto/bytestring/bytestring_test.cc
+++ b/src/crypto/bytestring/bytestring_test.cc
@@ -123,27 +123,27 @@
uint64_t value;
CBS_init(&data, kData1, sizeof(kData1));
- EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x1));
- EXPECT_TRUE(CBS_peek_asn1_tag(&data, 0x30));
+ EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_BOOLEAN));
+ EXPECT_TRUE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
- ASSERT_TRUE(CBS_get_asn1(&data, &contents, 0x30));
+ ASSERT_TRUE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
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, 0x30));
+ EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
CBS_init(&data, kData3, sizeof(kData3));
// zero byte length of length
- EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+ EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
CBS_init(&data, kData4, sizeof(kData4));
// long form mistakenly used.
- EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+ EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
CBS_init(&data, kData5, sizeof(kData5));
// length takes too many bytes.
- EXPECT_FALSE(CBS_get_asn1(&data, &contents, 0x30));
+ EXPECT_FALSE(CBS_get_asn1(&data, &contents, CBS_ASN1_SEQUENCE));
CBS_init(&data, kData1, sizeof(kData1));
// wrong tag.
@@ -151,56 +151,72 @@
CBS_init(&data, NULL, 0);
// peek at empty data.
- EXPECT_FALSE(CBS_peek_asn1_tag(&data, 0x30));
+ EXPECT_FALSE(CBS_peek_asn1_tag(&data, CBS_ASN1_SEQUENCE));
CBS_init(&data, NULL, 0);
// optional elements at empty data.
- ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
+ ASSERT_TRUE(CBS_get_optional_asn1(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
EXPECT_FALSE(present);
- ASSERT_TRUE(
- CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0));
+ ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
EXPECT_FALSE(present);
EXPECT_EQ(0u, CBS_len(&contents));
- ASSERT_TRUE(CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0));
+ ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+ &data, &contents, NULL,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
EXPECT_EQ(0u, CBS_len(&contents));
- ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
+ ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+ &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
EXPECT_EQ(42u, value);
CBS_init(&data, kData6, sizeof(kData6));
// optional element.
- ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa0));
+ ASSERT_TRUE(CBS_get_optional_asn1(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
EXPECT_FALSE(present);
- ASSERT_TRUE(CBS_get_optional_asn1(&data, &contents, &present, 0xa1));
+ ASSERT_TRUE(CBS_get_optional_asn1(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
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, 0xa0));
+ ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0));
EXPECT_FALSE(present);
EXPECT_EQ(0u, CBS_len(&contents));
- ASSERT_TRUE(
- CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1));
+ ASSERT_TRUE(CBS_get_optional_asn1_octet_string(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
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, 0xa1));
+ EXPECT_FALSE(CBS_get_optional_asn1_octet_string(
+ &data, &contents, &present,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1));
CBS_init(&data, kData8, sizeof(kData8));
// optional integer.
- ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42));
+ ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+ &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0, 42));
EXPECT_EQ(42u, value);
- ASSERT_TRUE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
+ ASSERT_TRUE(CBS_get_optional_asn1_uint64(
+ &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
EXPECT_EQ(1u, value);
CBS_init(&data, kData9, sizeof(kData9));
// invalid optional integer.
- EXPECT_FALSE(CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42));
+ EXPECT_FALSE(CBS_get_optional_asn1_uint64(
+ &data, &value, CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 1, 42));
unsigned tag;
CBS_init(&data, kData1, sizeof(kData1));
@@ -217,6 +233,54 @@
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};
@@ -416,15 +480,42 @@
}
TEST(CBBTest, ASN1) {
- static const uint8_t kExpected[] = {0x30, 3, 1, 2, 3};
+ 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,
+ };
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, 0x30));
+ ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
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);
@@ -432,7 +523,7 @@
std::vector<uint8_t> test_data(100000, 0x42);
ASSERT_TRUE(CBB_init(cbb.get(), 0));
- ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, 0x30));
+ ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 130));
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
scoper.reset(buf);
@@ -442,7 +533,7 @@
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, 0x30));
+ ASSERT_TRUE(CBB_add_asn1(cbb.get(), &contents, CBS_ASN1_SEQUENCE));
ASSERT_TRUE(CBB_add_bytes(&contents, test_data.data(), 1000));
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
scoper.reset(buf);
@@ -452,8 +543,8 @@
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, 0x30));
- ASSERT_TRUE(CBB_add_asn1(&contents, &inner_contents, 0x30));
+ 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_bytes(&inner_contents, test_data.data(), 100000));
ASSERT_TRUE(CBB_finish(cbb.get(), &buf, &buf_len));
scoper.reset(buf);
@@ -490,6 +581,12 @@
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,
@@ -534,6 +631,8 @@
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,
diff --git a/src/crypto/bytestring/cbb.c b/src/crypto/bytestring/cbb.c
index f8f5e0f..b12a66c 100644
--- a/src/crypto/bytestring/cbb.c
+++ b/src/crypto/bytestring/cbb.c
@@ -356,17 +356,20 @@
}
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;
+ if (!CBB_flush(cbb)) {
return 0;
}
- if (!CBB_flush(cbb) ||
- // |tag|'s representation matches the DER encoding.
- !CBB_add_u8(cbb, (uint8_t)tag)) {
+ // 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) ||
+ !add_base128_integer(cbb, tag_number)) {
+ return 0;
+ }
+ } else if (!CBB_add_u8(cbb, tag_bits | tag_number)) {
return 0;
}
diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c
index f3fc863..e456330 100644
--- a/src/crypto/bytestring/cbs.c
+++ b/src/crypto/bytestring/cbs.c
@@ -207,18 +207,9 @@
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;
-
- if (out == NULL) {
- out = &throwaway;
- }
-
- if (!CBS_get_u8(&header, &tag) ||
- !CBS_get_u8(&header, &length_byte)) {
+static int parse_asn1_tag(CBS *cbs, unsigned *out) {
+ uint8_t tag_byte;
+ if (!CBS_get_u8(cbs, &tag_byte)) {
return 0;
}
@@ -229,22 +220,58 @@
// 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;
+ unsigned tag = ((unsigned)tag_byte & 0xe0) << CBS_ASN1_TAG_SHIFT;
+ unsigned tag_number = tag_byte & 0x1f;
+ if (tag_number == 0x1f) {
+ uint64_t v;
+ if (!parse_base128_integer(cbs, &v) ||
+ // Check the tag number is within our supported bounds.
+ v > CBS_ASN1_TAG_NUMBER_MASK ||
+ // Small tag numbers should have used low tag number form.
+ v < 0x1f) {
+ return 0;
+ }
+ tag_number = (unsigned)v;
}
+ tag |= tag_number;
+
+ *out = tag;
+ return 1;
+}
+
+static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag,
+ size_t *out_header_len, int ber_ok) {
+ CBS header = *cbs;
+ CBS throwaway;
+
+ if (out == NULL) {
+ out = &throwaway;
+ }
+
+ unsigned tag;
+ if (!parse_asn1_tag(&header, &tag)) {
+ return 0;
+ }
if (out_tag != NULL) {
*out_tag = tag;
}
+ uint8_t length_byte;
+ if (!CBS_get_u8(&header, &length_byte)) {
+ return 0;
+ }
+
+ size_t header_len = CBS_len(cbs) - CBS_len(&header);
+
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) + 2;
+ len = ((size_t) length_byte) + header_len;
if (out_header_len != NULL) {
- *out_header_len = 2;
+ *out_header_len = header_len;
}
} else {
// The high bit indicate that this is the long form, while the next 7 bits
@@ -256,9 +283,9 @@
if (ber_ok && (tag & CBS_ASN1_CONSTRUCTED) != 0 && num_bytes == 0) {
// indefinite length
if (out_header_len != NULL) {
- *out_header_len = 2;
+ *out_header_len = header_len;
}
- return CBS_get_bytes(cbs, out, 2);
+ return CBS_get_bytes(cbs, out, header_len);
}
// ITU-T X.690 clause 8.1.3.5.c specifies that the value 0xff shall not be
@@ -281,13 +308,13 @@
return 0;
}
len = len32;
- if (len + 2 + num_bytes < len) {
+ if (len + header_len + num_bytes < len) {
// Overflow.
return 0;
}
- len += 2 + num_bytes;
+ len += header_len + num_bytes;
if (out_header_len != NULL) {
- *out_header_len = 2 + num_bytes;
+ *out_header_len = header_len + num_bytes;
}
}
@@ -355,7 +382,10 @@
if (CBS_len(cbs) < 1) {
return 0;
}
- return CBS_data(cbs)[0] == tag_value;
+
+ CBS copy = *cbs;
+ unsigned actual_tag;
+ return parse_asn1_tag(©, &actual_tag) && tag_value == actual_tag;
}
int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) {
diff --git a/src/crypto/cipher_extra/e_tls.c b/src/crypto/cipher_extra/e_tls.c
index 72754c0..bba22be 100644
--- a/src/crypto/cipher_extra/e_tls.c
+++ b/src/crypto/cipher_extra/e_tls.c
@@ -191,8 +191,7 @@
// block from encrypting the input and split the result between |out| and
// |out_tag|. Then feed the rest.
- const size_t early_mac_len =
- (block_size - (in_len % block_size) % block_size);
+ const size_t early_mac_len = (block_size - (in_len % block_size)) % block_size;
if (early_mac_len != 0) {
assert(len + block_size - early_mac_len == in_len);
uint8_t buf[EVP_MAX_BLOCK_LENGTH];
diff --git a/src/crypto/fipsmodule/ec/ec_key.c b/src/crypto/fipsmodule/ec/ec_key.c
index f64cb21..4e0bcb2 100644
--- a/src/crypto/fipsmodule/ec/ec_key.c
+++ b/src/crypto/fipsmodule/ec/ec_key.c
@@ -233,20 +233,21 @@
const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key) { return key->group; }
int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group) {
+ // If |key| already has a group, it is an error to switch to another one.
+ if (key->group != NULL) {
+ if (EC_GROUP_cmp(key->group, group, NULL) != 0) {
+ OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
+ return 0;
+ }
+ return 1;
+ }
+
+ assert(key->priv_key == NULL);
+ assert(key->pub_key == NULL);
+
EC_GROUP_free(key->group);
- // TODO(fork): duplicating the group seems wasteful but see
- // |EC_KEY_set_conv_form|.
key->group = EC_GROUP_dup(group);
- if (key->group == NULL) {
- return 0;
- }
- // XXX: |BN_cmp| is not constant time.
- if (key->priv_key != NULL &&
- (BN_is_negative(key->priv_key) ||
- BN_cmp(key->priv_key, EC_GROUP_get0_order(group)) >= 0)) {
- return 0;
- }
- return 1;
+ return key->group != NULL;
}
const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key) {
@@ -254,10 +255,14 @@
}
int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *priv_key) {
+ if (key->group == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
+ return 0;
+ }
+
// XXX: |BN_cmp| is not constant time.
- if (key->group != NULL &&
- (BN_is_negative(priv_key) ||
- BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0)) {
+ if (BN_is_negative(priv_key) ||
+ BN_cmp(priv_key, EC_GROUP_get0_order(key->group)) >= 0) {
OPENSSL_PUT_ERROR(EC, EC_R_WRONG_ORDER);
return 0;
}
@@ -271,6 +276,16 @@
}
int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub_key) {
+ if (key->group == NULL) {
+ OPENSSL_PUT_ERROR(EC, EC_R_MISSING_PARAMETERS);
+ return 0;
+ }
+
+ if (EC_GROUP_cmp(key->group, pub_key->group, NULL) != 0) {
+ OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
+ return 0;
+ }
+
EC_POINT_free(key->pub_key);
key->pub_key = EC_POINT_dup(pub_key, key->group);
return (key->pub_key == NULL) ? 0 : 1;
diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc
index 8e7a81d..d2cd2af 100644
--- a/src/crypto/fipsmodule/ec/ec_test.cc
+++ b/src/crypto/fipsmodule/ec/ec_test.cc
@@ -305,6 +305,36 @@
EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL));
}
+TEST(ECTest, SetKeyWithoutGroup) {
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_new());
+ ASSERT_TRUE(key);
+
+ // Private keys may not be configured without a group.
+ EXPECT_FALSE(EC_KEY_set_private_key(key.get(), BN_value_one()));
+
+ // Public keys may not be configured without a group.
+ bssl::UniquePtr<EC_GROUP> group(
+ EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ ASSERT_TRUE(group);
+ EXPECT_FALSE(
+ EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(group.get())));
+}
+
+TEST(ECTest, GroupMismatch) {
+ bssl::UniquePtr<EC_KEY> key(EC_KEY_new_by_curve_name(NID_secp384r1));
+ ASSERT_TRUE(key);
+ bssl::UniquePtr<EC_GROUP> p256(
+ EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ ASSERT_TRUE(p256);
+
+ // Changing a key's group is invalid.
+ EXPECT_FALSE(EC_KEY_set_group(key.get(), p256.get()));
+
+ // Configuring a public key with the wrong group is invalid.
+ EXPECT_FALSE(
+ EC_KEY_set_public_key(key.get(), EC_GROUP_get0_generator(p256.get())));
+}
+
class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {};
TEST_P(ECCurveTest, SetAffine) {
diff --git a/src/crypto/fipsmodule/modes/internal.h b/src/crypto/fipsmodule/modes/internal.h
index f6ee8f4..68ef4dc 100644
--- a/src/crypto/fipsmodule/modes/internal.h
+++ b/src/crypto/fipsmodule/modes/internal.h
@@ -66,38 +66,6 @@
#define STRICT_ALIGNMENT 0
#endif
-#if defined(__GNUC__) && __GNUC__ >= 2
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
- return __builtin_bswap32(x);
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
- return __builtin_bswap64(x);
-}
-#elif defined(_MSC_VER)
-OPENSSL_MSVC_PRAGMA(warning(push, 3))
-#include <intrin.h>
-OPENSSL_MSVC_PRAGMA(warning(pop))
-#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
- return _byteswap_ulong(x);
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
- return _byteswap_uint64(x);
-}
-#else
-static inline uint32_t CRYPTO_bswap4(uint32_t x) {
- x = (x >> 16) | (x << 16);
- x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
- return x;
-}
-
-static inline uint64_t CRYPTO_bswap8(uint64_t x) {
- return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32);
-}
-#endif
-
static inline uint32_t GETU32(const void *in) {
uint32_t v;
OPENSSL_memcpy(&v, in, sizeof(v));
diff --git a/src/crypto/fipsmodule/rsa/rsa.c b/src/crypto/fipsmodule/rsa/rsa.c
index 4a84314..ffe2cd0 100644
--- a/src/crypto/fipsmodule/rsa/rsa.c
+++ b/src/crypto/fipsmodule/rsa/rsa.c
@@ -852,6 +852,8 @@
return rsa_default_private_transform(rsa, out, in, len);
}
+int RSA_flags(const RSA *rsa) { return rsa->flags; }
+
int RSA_blinding_on(RSA *rsa, BN_CTX *ctx) {
return 1;
}
diff --git a/src/crypto/fipsmodule/rsa/rsa_impl.c b/src/crypto/fipsmodule/rsa/rsa_impl.c
index c391228..b5a4e51 100644
--- a/src/crypto/fipsmodule/rsa/rsa_impl.c
+++ b/src/crypto/fipsmodule/rsa/rsa_impl.c
@@ -1097,5 +1097,4 @@
// |rsa_default_*| implementation.
OPENSSL_memset(out, 0, sizeof(RSA_METHOD));
out->common.is_static = 1;
- out->flags = RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE;
}
diff --git a/src/crypto/internal.h b/src/crypto/internal.h
index 5706414..e6bab02 100644
--- a/src/crypto/internal.h
+++ b/src/crypto/internal.h
@@ -591,6 +591,41 @@
void *obj, CRYPTO_EX_DATA *ad);
+// Endianness conversions.
+
+#if defined(__GNUC__) && __GNUC__ >= 2
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+ return __builtin_bswap32(x);
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+ return __builtin_bswap64(x);
+}
+#elif defined(_MSC_VER)
+OPENSSL_MSVC_PRAGMA(warning(push, 3))
+#include <intrin.h>
+OPENSSL_MSVC_PRAGMA(warning(pop))
+#pragma intrinsic(_byteswap_uint64, _byteswap_ulong)
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+ return _byteswap_ulong(x);
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+ return _byteswap_uint64(x);
+}
+#else
+static inline uint32_t CRYPTO_bswap4(uint32_t x) {
+ x = (x >> 16) | (x << 16);
+ x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8);
+ return x;
+}
+
+static inline uint64_t CRYPTO_bswap8(uint64_t x) {
+ return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32);
+}
+#endif
+
+
// Language bug workarounds.
//
// Most C standard library functions are undefined if passed NULL, even when the
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index 158fd45..b4cecca 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -835,7 +835,7 @@
/* This ensures the X509 took a reference to |buf|, otherwise this will be a
* reference to free memory and ASAN should notice. */
- ASSERT_EQ(CBS_ASN1_SEQUENCE, enc_pointer[0]);
+ ASSERT_EQ(0x30, enc_pointer[0]);
}
TEST(X509Test, TestFromBufferWithTrailingData) {
diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h
index 6572995..c7ead03 100644
--- a/src/include/openssl/asn1.h
+++ b/src/include/openssl/asn1.h
@@ -737,6 +737,7 @@
OPENSSL_EXPORT ASN1_OBJECT *ASN1_OBJECT_create(int nid, unsigned char *data,int len, const char *sn, const char *ln);
OPENSSL_EXPORT int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
+OPENSSL_EXPORT int ASN1_INTEGER_set_uint64(ASN1_INTEGER *out, uint64_t v);
OPENSSL_EXPORT long ASN1_INTEGER_get(const ASN1_INTEGER *a);
OPENSSL_EXPORT ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai);
OPENSSL_EXPORT BIGNUM *ASN1_INTEGER_to_BN(const ASN1_INTEGER *ai,BIGNUM *bn);
diff --git a/src/include/openssl/bytestring.h b/src/include/openssl/bytestring.h
index 25411c7..43349e9 100644
--- a/src/include/openssl/bytestring.h
+++ b/src/include/openssl/bytestring.h
@@ -164,34 +164,36 @@
#define CBS_ASN1_UNIVERSALSTRING 0x1cu
#define CBS_ASN1_BMPSTRING 0x1eu
+// CBS_ASN1_TAG_SHIFT is how much the in-memory representation shifts the class
+// and constructed bits from the DER serialization. This allows representing tag
+// numbers beyond 31.
+//
+// Consumers must use the following constants to decompose or assemble tags.
+#define CBS_ASN1_TAG_SHIFT 24
+
// CBS_ASN1_CONSTRUCTED may be ORed into a tag to toggle the constructed
// bit. |CBS| and |CBB| APIs consider the constructed bit to be part of the
// tag.
-#define CBS_ASN1_CONSTRUCTED 0x20u
+#define CBS_ASN1_CONSTRUCTED (0x20u << CBS_ASN1_TAG_SHIFT)
-// The following values specify the constructed bit or tag class and may be ORed
-// into a tag number to produce the final tag. If none is used, the tag will be
-// UNIVERSAL.
-//
-// Note that although they currently match the DER serialization, consumers must
-// use these bits rather than make assumptions about the representation. This is
-// to allow for tag numbers beyond 31 in the future.
-#define CBS_ASN1_APPLICATION 0x40u
-#define CBS_ASN1_CONTEXT_SPECIFIC 0x80u
-#define CBS_ASN1_PRIVATE 0xc0u
+// The following values specify the tag class and may be ORed into a tag number
+// to produce the final tag. If none is used, the tag will be UNIVERSAL.
+#define CBS_ASN1_UNIVERSAL (0u << CBS_ASN1_TAG_SHIFT)
+#define CBS_ASN1_APPLICATION (0x40u << CBS_ASN1_TAG_SHIFT)
+#define CBS_ASN1_CONTEXT_SPECIFIC (0x80u << CBS_ASN1_TAG_SHIFT)
+#define CBS_ASN1_PRIVATE (0xc0u << CBS_ASN1_TAG_SHIFT)
-// CBS_ASN1_CLASS_MASK may be ANDed with a tag to query its class.
-#define CBS_ASN1_CLASS_MASK 0xc0u
+// CBS_ASN1_CLASS_MASK may be ANDed with a tag to query its class. This will
+// give one of the four values above.
+#define CBS_ASN1_CLASS_MASK (0xc0u << CBS_ASN1_TAG_SHIFT)
// CBS_ASN1_TAG_NUMBER_MASK may be ANDed with a tag to query its number.
-#define CBS_ASN1_TAG_NUMBER_MASK 0x1fu
+#define CBS_ASN1_TAG_NUMBER_MASK ((1u << (5 + CBS_ASN1_TAG_SHIFT)) - 1)
// CBS_get_asn1 sets |*out| to the contents of DER-encoded, ASN.1 element (not
// including tag and length bytes) and advances |cbs| over it. The ASN.1
// element must match |tag_value|. It returns one on success and zero
// on error.
-//
-// Tag numbers greater than 30 are not supported (i.e. short form only).
OPENSSL_EXPORT int CBS_get_asn1(CBS *cbs, CBS *out, unsigned tag_value);
// CBS_get_asn1_element acts like |CBS_get_asn1| but |out| will include the
@@ -209,16 +211,12 @@
// (not including tag and length bytes), sets |*out_tag| to the tag number, and
// advances |*cbs|. It returns one on success and zero on error. Either of |out|
// and |out_tag| may be NULL to ignore the value.
-//
-// Tag numbers greater than 30 are not supported (i.e. short form only).
OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag);
// CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from
// |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to
// the tag number and |*out_header_len| to the length of the ASN.1 header. Each
// of |out|, |out_tag|, and |out_header_len| may be NULL to ignore the value.
-//
-// Tag numbers greater than 30 are not supported (i.e. short form only).
OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out,
unsigned *out_tag,
size_t *out_header_len);
@@ -403,9 +401,7 @@
// CBB_add_asn1 sets |*out_contents| to a |CBB| into which the contents of an
// ASN.1 object can be written. The |tag| argument will be used as the tag for
-// the object. Passing in |tag| number 31 will return in an error since only
-// single octet identifiers are supported. It returns one on success or zero
-// on error.
+// the object. It returns one on success or zero on error.
OPENSSL_EXPORT int CBB_add_asn1(CBB *cbb, CBB *out_contents, unsigned tag);
// CBB_add_bytes appends |len| bytes from |data| to |cbb|. It returns one on
diff --git a/src/include/openssl/ec_key.h b/src/include/openssl/ec_key.h
index 7ef1b14..5fe0318 100644
--- a/src/include/openssl/ec_key.h
+++ b/src/include/openssl/ec_key.h
@@ -116,14 +116,16 @@
OPENSSL_EXPORT const EC_GROUP *EC_KEY_get0_group(const EC_KEY *key);
// EC_KEY_set_group sets the |EC_GROUP| object that |key| will use to |group|.
-// It returns one on success and zero otherwise.
+// It returns one on success and zero otherwise. If |key| already has a group,
+// it is an error to change to a different one.
OPENSSL_EXPORT int EC_KEY_set_group(EC_KEY *key, const EC_GROUP *group);
// EC_KEY_get0_private_key returns a pointer to the private key inside |key|.
OPENSSL_EXPORT const BIGNUM *EC_KEY_get0_private_key(const EC_KEY *key);
// EC_KEY_set_private_key sets the private key of |key| to |priv|. It returns
-// one on success and zero otherwise.
+// one on success and zero otherwise. |key| must already have had a group
+// configured (see |EC_KEY_set_group| and |EC_KEY_new_by_curve_name|).
OPENSSL_EXPORT int EC_KEY_set_private_key(EC_KEY *key, const BIGNUM *prv);
// EC_KEY_get0_public_key returns a pointer to the public key point inside
@@ -131,7 +133,9 @@
OPENSSL_EXPORT const EC_POINT *EC_KEY_get0_public_key(const EC_KEY *key);
// EC_KEY_set_public_key sets the public key of |key| to |pub|, by copying it.
-// It returns one on success and zero otherwise.
+// It returns one on success and zero otherwise. |key| must already have had a
+// group configured (see |EC_KEY_set_group| and |EC_KEY_new_by_curve_name|), and
+// |pub| must also belong to that group.
OPENSSL_EXPORT int EC_KEY_set_public_key(EC_KEY *key, const EC_POINT *pub);
#define EC_PKEY_NO_PARAMETERS 0x001
diff --git a/src/include/openssl/rsa.h b/src/include/openssl/rsa.h
index 11aa8e4..1731f14 100644
--- a/src/include/openssl/rsa.h
+++ b/src/include/openssl/rsa.h
@@ -489,12 +489,6 @@
// API, like a platform key store.
#define RSA_FLAG_OPAQUE 1
-// Deprecated and ignored.
-#define RSA_FLAG_CACHE_PUBLIC 2
-
-// Deprecated and ignored.
-#define RSA_FLAG_CACHE_PRIVATE 4
-
// RSA_FLAG_NO_BLINDING disables blinding of private operations, which is a
// dangerous thing to do. It is deprecated and should not be used. It will
// be ignored whenever possible.
@@ -506,10 +500,6 @@
// RSA_FLAG_EXT_PKEY is deprecated and ignored.
#define RSA_FLAG_EXT_PKEY 0x20
-// RSA_FLAG_SIGN_VER causes the |sign| and |verify| functions of |rsa_meth_st|
-// to be called when set.
-#define RSA_FLAG_SIGN_VER 0x40
-
// RSA public exponent values.
@@ -519,6 +509,12 @@
// Deprecated functions.
+#define RSA_METHOD_FLAG_NO_CHECK RSA_FLAG_OPAQUE
+
+// RSA_flags returns the flags for |rsa|. These are a bitwise OR of |RSA_FLAG_*|
+// constants.
+OPENSSL_EXPORT int RSA_flags(const RSA *rsa);
+
// RSA_blinding_on returns one.
OPENSSL_EXPORT int RSA_blinding_on(RSA *rsa, BN_CTX *ctx);
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 066390b..6ab1682 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -591,12 +591,8 @@
#define DTLS1_VERSION 0xfeff
#define DTLS1_2_VERSION 0xfefd
-#define TLS1_3_DRAFT_VERSION 0x7f12
-#define TLS1_3_DRAFT21_VERSION 0x7f15
#define TLS1_3_DRAFT22_VERSION 0x7f16
-#define TLS1_3_EXPERIMENT_VERSION 0x7e01
#define TLS1_3_EXPERIMENT2_VERSION 0x7e02
-#define TLS1_3_EXPERIMENT3_VERSION 0x7e03
// SSL_CTX_set_min_proto_version sets the minimum protocol version for |ctx| to
// |version|. If |version| is zero, the default minimum version is used. It
@@ -2384,6 +2380,11 @@
// either |X509_V_OK| or a |X509_V_ERR_*| value.
OPENSSL_EXPORT long SSL_get_verify_result(const SSL *ssl);
+// SSL_alert_from_verify_result returns the SSL alert code, such as
+// |SSL_AD_CERTIFICATE_EXPIRED|, that corresponds to an |X509_V_ERR_*| value.
+// The return value is always an alert, even when |result| is |X509_V_OK|.
+OPENSSL_EXPORT int SSL_alert_from_verify_result(long result);
+
// SSL_get_ex_data_X509_STORE_CTX_idx returns the ex_data index used to look up
// the |SSL| associated with an |X509_STORE_CTX| in the verify callback.
OPENSSL_EXPORT int SSL_get_ex_data_X509_STORE_CTX_idx(void);
@@ -3226,11 +3227,7 @@
enum tls13_variant_t {
tls13_default = 0,
- tls13_experiment = 1,
- tls13_experiment2 = 2,
- tls13_experiment3 = 3,
- tls13_draft21 = 4,
- tls13_draft22 = 5,
+ tls13_experiment2 = 1,
};
// SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
@@ -3490,6 +3487,10 @@
OPENSSL_EXPORT void SSL_CTX_set_false_start_allowed_without_alpn(SSL_CTX *ctx,
int allowed);
+// SSL_is_draft_downgrade returns one if the TLS 1.3 anti-downgrade mechanism
+// would have aborted |ssl|'s handshake and zero otherwise.
+OPENSSL_EXPORT int SSL_is_draft_downgrade(const SSL *ssl);
+
// Deprecated functions.
diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc
index cdda459..4c7012b 100644
--- a/src/ssl/handshake_client.cc
+++ b/src/ssl/handshake_client.cc
@@ -464,7 +464,7 @@
hs->session_id_len = ssl->session->session_id_length;
OPENSSL_memcpy(hs->session_id, ssl->session->session_id,
hs->session_id_len);
- } else if (ssl_is_resumption_variant(hs->max_version, ssl->tls13_variant)) {
+ } else if (hs->max_version >= TLS1_3_VERSION) {
hs->session_id_len = sizeof(hs->session_id);
if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
return ssl_hs_error;
@@ -632,8 +632,20 @@
OPENSSL_memcpy(ssl->s3->server_random, CBS_data(&server_random),
SSL3_RANDOM_SIZE);
- // TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
- // 1.3 is finalized and we are not implementing a draft version.
+ // Measure, but do not enforce, the TLS 1.3 anti-downgrade feature, with a
+ // different value.
+ //
+ // For draft TLS 1.3 versions, it is not safe to deploy this feature. However,
+ // some TLS terminators are non-compliant and copy the origin server's value,
+ // so we wish to measure eventual compatibility impact.
+ if (!ssl->s3->initial_handshake_complete &&
+ hs->max_version >= TLS1_3_VERSION &&
+ OPENSSL_memcmp(ssl->s3->server_random + SSL3_RANDOM_SIZE -
+ sizeof(kDraftDowngradeRandom),
+ kDraftDowngradeRandom,
+ sizeof(kDraftDowngradeRandom)) == 0) {
+ ssl->s3->draft_downgrade = true;
+ }
if (!ssl->s3->initial_handshake_complete && ssl->session != NULL &&
ssl->session->session_id_length != 0 &&
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index bb565e9..bcbd7e2 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -707,8 +707,16 @@
return ssl_hs_error;
}
- // TODO(davidben): Implement the TLS 1.1 and 1.2 downgrade sentinels once TLS
- // 1.3 is finalized and we are not implementing a draft version.
+ // Implement the TLS 1.3 anti-downgrade feature, but with a different value.
+ //
+ // For draft TLS 1.3 versions, it is not safe to deploy this feature. However,
+ // some TLS terminators are non-compliant and copy the origin server's value,
+ // so we wish to measure eventual compatibility impact.
+ if (hs->max_version >= TLS1_3_VERSION) {
+ OPENSSL_memcpy(ssl->s3->server_random + SSL3_RANDOM_SIZE -
+ sizeof(kDraftDowngradeRandom),
+ kDraftDowngradeRandom, sizeof(kDraftDowngradeRandom));
+ }
const SSL_SESSION *session = hs->new_session.get();
if (ssl->session != NULL) {
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 4151d2b..78d7aa6 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -1010,6 +1010,7 @@
#define SSL_MAX_HANDSHAKE_FLIGHT 7
extern const uint8_t kHelloRetryRequest[SSL3_RANDOM_SIZE];
+extern const uint8_t kDraftDowngradeRandom[8];
// ssl_max_handshake_message_len returns the maximum number of bytes permitted
// in a handshake message for |ssl|.
@@ -2297,6 +2298,13 @@
// wpend_pending is true if we have a pending write outstanding.
bool wpend_pending:1;
+ // early_data_accepted is true if early data was accepted by the server.
+ bool early_data_accepted:1;
+
+ // draft_downgrade is whether the TLS 1.3 anti-downgrade logic would have
+ // fired, were it not a draft.
+ bool draft_downgrade:1;
+
uint8_t send_alert[2] = {0};
// hs_buf is the buffer of handshake data to process.
@@ -2643,9 +2651,6 @@
// hash of the peer's certificate and then discard it to save memory and
// session space. Only effective on the server side.
bool retain_only_sha256_of_client_certs:1;
-
- // early_data_accepted is true if early data was accepted by the server.
- bool early_data_accepted:1;
};
// From draft-ietf-tls-tls13-18, used in determining PSK modes.
diff --git a/src/ssl/s3_lib.cc b/src/ssl/s3_lib.cc
index b925cd7..a3fc8d7 100644
--- a/src/ssl/s3_lib.cc
+++ b/src/ssl/s3_lib.cc
@@ -175,7 +175,9 @@
send_connection_binding(false),
tlsext_channel_id_valid(false),
key_update_pending(false),
- wpend_pending(false) {}
+ wpend_pending(false),
+ early_data_accepted(false),
+ draft_downgrade(false) {}
SSL3_STATE::~SSL3_STATE() {}
diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc
index e6518ba..e14d551 100644
--- a/src/ssl/s3_pkt.cc
+++ b/src/ssl/s3_pkt.cc
@@ -306,7 +306,7 @@
if (type == SSL3_RT_HANDSHAKE) {
// If reading 0-RTT data, reject handshake data. 0-RTT data is terminated
// by an alert.
- if (!ssl_is_draft21(ssl->version) && is_early_data_read) {
+ if (!ssl_is_draft22(ssl->version) && is_early_data_read) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
*out_alert = SSL_AD_UNEXPECTED_MESSAGE;
return ssl_open_record_error;
@@ -335,7 +335,7 @@
// Handle the end_of_early_data alert.
static const uint8_t kEndOfEarlyData[2] = {SSL3_AL_WARNING,
TLS1_AD_END_OF_EARLY_DATA};
- if (!ssl_is_draft21(ssl->version) && is_early_data_read &&
+ if (!ssl_is_draft22(ssl->version) && is_early_data_read &&
type == SSL3_RT_ALERT && body == kEndOfEarlyData) {
// Stop accepting early data.
ssl->s3->hs->can_early_read = false;
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index 775827c..247e889 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -173,10 +173,7 @@
return version_;
}
- if (ssl_is_resumption_record_version_experiment(version_)) {
- return TLS1_2_VERSION;
- }
- return TLS1_VERSION;
+ return TLS1_2_VERSION;
}
size_t SSLAEADContext::ExplicitNonceLen() const {
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index 6da081e..5e420e8 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -1187,7 +1187,7 @@
}
int SSL_early_data_accepted(const SSL *ssl) {
- return ssl->early_data_accepted;
+ return ssl->s3->early_data_accepted;
}
void SSL_reset_early_data_reject(SSL *ssl) {
@@ -2571,6 +2571,8 @@
ctx->false_start_allowed_without_alpn = !!allowed;
}
+int SSL_is_draft_downgrade(const SSL *ssl) { return ssl->s3->draft_downgrade; }
+
int SSL_clear(SSL *ssl) {
// In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously
// established session to be offered the next time around. wpa_supplicant
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 8288878..5d37448 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -2617,7 +2617,8 @@
EXPECT_EQ(TLS1_3_VERSION, ctx->conf_max_version);
// TLS1_3_DRAFT_VERSION is not an API-level version.
- EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_DRAFT_VERSION));
+ EXPECT_FALSE(
+ SSL_CTX_set_max_proto_version(ctx.get(), TLS1_3_DRAFT22_VERSION));
ERR_clear_error();
ctx.reset(SSL_CTX_new(DTLS_method()));
@@ -2960,9 +2961,7 @@
uint16_t record_version, length;
ASSERT_TRUE(CBS_get_u8(&cbs, &type));
ASSERT_TRUE(CBS_get_u16(&cbs, &record_version));
- EXPECT_TRUE(record_version == version() ||
- record_version == (is_dtls() ? DTLS1_VERSION : TLS1_VERSION))
- << "Invalid record version: " << record_version;
+ EXPECT_EQ(record_version & 0xff00, version() & 0xff00);
if (is_dtls()) {
uint16_t epoch;
ASSERT_TRUE(CBS_get_u16(&cbs, &epoch));
@@ -3862,7 +3861,7 @@
!TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) ||
// Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there
// will be a PSK binder after the padding extension.
- !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION)) {
+ !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT22_VERSION)) {
ADD_FAILURE() << "Tests failed";
}
}
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index 2406bd8..4ef54da 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -34,12 +34,8 @@
*out = version;
return true;
- case TLS1_3_DRAFT_VERSION:
- case TLS1_3_DRAFT21_VERSION:
case TLS1_3_DRAFT22_VERSION:
- case TLS1_3_EXPERIMENT_VERSION:
case TLS1_3_EXPERIMENT2_VERSION:
- case TLS1_3_EXPERIMENT3_VERSION:
*out = TLS1_3_VERSION;
return true;
@@ -62,11 +58,7 @@
static const uint16_t kTLSVersions[] = {
TLS1_3_DRAFT22_VERSION,
- TLS1_3_EXPERIMENT3_VERSION,
TLS1_3_EXPERIMENT2_VERSION,
- TLS1_3_EXPERIMENT_VERSION,
- TLS1_3_DRAFT_VERSION,
- TLS1_3_DRAFT21_VERSION,
TLS1_2_VERSION,
TLS1_1_VERSION,
TLS1_VERSION,
@@ -109,12 +101,8 @@
static const char *ssl_version_to_string(uint16_t version) {
switch (version) {
- case TLS1_3_DRAFT_VERSION:
- case TLS1_3_DRAFT21_VERSION:
case TLS1_3_DRAFT22_VERSION:
- case TLS1_3_EXPERIMENT_VERSION:
case TLS1_3_EXPERIMENT2_VERSION:
- case TLS1_3_EXPERIMENT3_VERSION:
return "TLSv1.3";
case TLS1_2_VERSION:
@@ -143,12 +131,8 @@
static uint16_t wire_version_to_api(uint16_t version) {
switch (version) {
// Report TLS 1.3 draft versions as TLS 1.3 in the public API.
- case TLS1_3_DRAFT_VERSION:
- case TLS1_3_DRAFT21_VERSION:
case TLS1_3_DRAFT22_VERSION:
- case TLS1_3_EXPERIMENT_VERSION:
case TLS1_3_EXPERIMENT2_VERSION:
- case TLS1_3_EXPERIMENT3_VERSION:
return TLS1_3_VERSION;
default:
return version;
@@ -159,16 +143,12 @@
// particular, it picks an arbitrary TLS 1.3 representative. This should only be
// used in context where that does not matter.
static bool api_version_to_wire(uint16_t *out, uint16_t version) {
- if (version == TLS1_3_DRAFT_VERSION ||
- version == TLS1_3_DRAFT21_VERSION ||
- version == TLS1_3_DRAFT22_VERSION ||
- version == TLS1_3_EXPERIMENT_VERSION ||
- version == TLS1_3_EXPERIMENT2_VERSION ||
- version == TLS1_3_EXPERIMENT3_VERSION) {
+ if (version == TLS1_3_DRAFT22_VERSION ||
+ version == TLS1_3_EXPERIMENT2_VERSION) {
return false;
}
if (version == TLS1_3_VERSION) {
- version = TLS1_3_DRAFT_VERSION;
+ version = TLS1_3_DRAFT22_VERSION;
}
// Check it is a real protocol version.
@@ -321,32 +301,16 @@
// TLS 1.3 variants must additionally match |tls13_variant|.
if (protocol_version != TLS1_3_VERSION ||
- (ssl->tls13_variant == tls13_experiment &&
- version == TLS1_3_EXPERIMENT_VERSION) ||
(ssl->tls13_variant == tls13_experiment2 &&
version == TLS1_3_EXPERIMENT2_VERSION) ||
- (ssl->tls13_variant == tls13_experiment3 &&
- version == TLS1_3_EXPERIMENT3_VERSION) ||
- (ssl->tls13_variant == tls13_draft21 &&
- version == TLS1_3_DRAFT21_VERSION) ||
- (ssl->tls13_variant == tls13_draft22 &&
- version == TLS1_3_DRAFT22_VERSION) ||
(ssl->tls13_variant == tls13_default &&
- version == TLS1_3_DRAFT_VERSION)) {
+ version == TLS1_3_DRAFT22_VERSION)) {
return true;
}
// The server, when not configured at |tls13_default|, should additionally
- // enable all variants, except draft-21 which is implemented solely for QUIC
- // interop testing and will not be deployed, and draft-22 which will be
- // enabled once the draft is finalized and ready to be deployed in Chrome.
- // Currently, this is to implement the draft-18 vs. experiments field trials.
- // In the future, this will be to transition cleanly to a final draft-22
- // which hopefully includes the deployability fixes.
- if (ssl->server &&
- ssl->tls13_variant != tls13_default &&
- version != TLS1_3_DRAFT21_VERSION &&
- version != TLS1_3_DRAFT22_VERSION) {
+ // enable all variants.
+ if (ssl->server && ssl->tls13_variant != tls13_default) {
return true;
}
@@ -397,42 +361,10 @@
return false;
}
-bool ssl_is_draft21(uint16_t version) {
- return version == TLS1_3_DRAFT21_VERSION || version == TLS1_3_DRAFT22_VERSION;
-}
-
bool ssl_is_draft22(uint16_t version) {
return version == TLS1_3_DRAFT22_VERSION;
}
-bool ssl_is_resumption_experiment(uint16_t version) {
- return version == TLS1_3_EXPERIMENT_VERSION ||
- version == TLS1_3_EXPERIMENT2_VERSION ||
- version == TLS1_3_EXPERIMENT3_VERSION ||
- version == TLS1_3_DRAFT22_VERSION;
-}
-
-bool ssl_is_resumption_variant(uint16_t max_version,
- enum tls13_variant_t variant) {
- if (max_version < TLS1_3_VERSION) {
- return false;
- }
- return variant == tls13_experiment || variant == tls13_experiment2 ||
- variant == tls13_experiment3 || variant == tls13_draft22;
-}
-
-bool ssl_is_resumption_client_ccs_experiment(uint16_t version) {
- return version == TLS1_3_EXPERIMENT_VERSION ||
- version == TLS1_3_EXPERIMENT2_VERSION ||
- version == TLS1_3_DRAFT22_VERSION;
-}
-
-bool ssl_is_resumption_record_version_experiment(uint16_t version) {
- return version == TLS1_3_EXPERIMENT2_VERSION ||
- version == TLS1_3_EXPERIMENT3_VERSION ||
- version == TLS1_3_DRAFT22_VERSION;
-}
-
} // namespace bssl
using namespace bssl;
diff --git a/src/ssl/ssl_x509.cc b/src/ssl/ssl_x509.cc
index 2b7ba83..5c0365f 100644
--- a/src/ssl/ssl_x509.cc
+++ b/src/ssl/ssl_x509.cc
@@ -354,66 +354,6 @@
session->x509_chain_without_leaf = NULL;
}
-static int ssl_verify_alarm_type(long type) {
- switch (type) {
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- case X509_V_ERR_UNABLE_TO_GET_CRL:
- case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
- return SSL_AD_UNKNOWN_CA;
-
- case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
- case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
- case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
- case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_CRL_NOT_YET_VALID:
- case X509_V_ERR_CERT_UNTRUSTED:
- case X509_V_ERR_CERT_REJECTED:
- case X509_V_ERR_HOSTNAME_MISMATCH:
- case X509_V_ERR_EMAIL_MISMATCH:
- case X509_V_ERR_IP_ADDRESS_MISMATCH:
- return SSL_AD_BAD_CERTIFICATE;
-
- case X509_V_ERR_CERT_SIGNATURE_FAILURE:
- case X509_V_ERR_CRL_SIGNATURE_FAILURE:
- return SSL_AD_DECRYPT_ERROR;
-
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_CRL_HAS_EXPIRED:
- return SSL_AD_CERTIFICATE_EXPIRED;
-
- case X509_V_ERR_CERT_REVOKED:
- return SSL_AD_CERTIFICATE_REVOKED;
-
- case X509_V_ERR_UNSPECIFIED:
- case X509_V_ERR_OUT_OF_MEM:
- case X509_V_ERR_INVALID_CALL:
- case X509_V_ERR_STORE_LOOKUP:
- return SSL_AD_INTERNAL_ERROR;
-
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
- case X509_V_ERR_CERT_CHAIN_TOO_LONG:
- case X509_V_ERR_PATH_LENGTH_EXCEEDED:
- case X509_V_ERR_INVALID_CA:
- return SSL_AD_UNKNOWN_CA;
-
- case X509_V_ERR_APPLICATION_VERIFICATION:
- return SSL_AD_HANDSHAKE_FAILURE;
-
- case X509_V_ERR_INVALID_PURPOSE:
- return SSL_AD_UNSUPPORTED_CERTIFICATE;
-
- default:
- return SSL_AD_CERTIFICATE_UNKNOWN;
- }
-}
-
static int ssl_crypto_x509_session_verify_cert_chain(SSL_SESSION *session,
SSL *ssl,
uint8_t *out_alert) {
@@ -464,7 +404,7 @@
// If |SSL_VERIFY_NONE|, the error is non-fatal, but we keep the result.
if (verify_ret <= 0 && ssl->verify_mode != SSL_VERIFY_NONE) {
- *out_alert = ssl_verify_alarm_type(ctx->error);
+ *out_alert = SSL_alert_from_verify_result(ctx->error);
return 0;
}
@@ -1297,3 +1237,63 @@
check_ssl_x509_method(ssl);
return set_cert_store(&ssl->cert->verify_store, store, 1);
}
+
+int SSL_alert_from_verify_result(long result) {
+ switch (result) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ case X509_V_ERR_UNABLE_TO_GET_CRL:
+ case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+ return SSL_AD_UNKNOWN_CA;
+
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+ case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+ case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+ case X509_V_ERR_CERT_NOT_YET_VALID:
+ case X509_V_ERR_CRL_NOT_YET_VALID:
+ case X509_V_ERR_CERT_UNTRUSTED:
+ case X509_V_ERR_CERT_REJECTED:
+ case X509_V_ERR_HOSTNAME_MISMATCH:
+ case X509_V_ERR_EMAIL_MISMATCH:
+ case X509_V_ERR_IP_ADDRESS_MISMATCH:
+ return SSL_AD_BAD_CERTIFICATE;
+
+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
+ case X509_V_ERR_CRL_SIGNATURE_FAILURE:
+ return SSL_AD_DECRYPT_ERROR;
+
+ case X509_V_ERR_CERT_HAS_EXPIRED:
+ case X509_V_ERR_CRL_HAS_EXPIRED:
+ return SSL_AD_CERTIFICATE_EXPIRED;
+
+ case X509_V_ERR_CERT_REVOKED:
+ return SSL_AD_CERTIFICATE_REVOKED;
+
+ case X509_V_ERR_UNSPECIFIED:
+ case X509_V_ERR_OUT_OF_MEM:
+ case X509_V_ERR_INVALID_CALL:
+ case X509_V_ERR_STORE_LOOKUP:
+ return SSL_AD_INTERNAL_ERROR;
+
+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+ case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+ case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+ case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+ case X509_V_ERR_INVALID_CA:
+ return SSL_AD_UNKNOWN_CA;
+
+ case X509_V_ERR_APPLICATION_VERIFICATION:
+ return SSL_AD_HANDSHAKE_FAILURE;
+
+ case X509_V_ERR_INVALID_PURPOSE:
+ return SSL_AD_UNSUPPORTED_CERTIFICATE;
+
+ default:
+ return SSL_AD_CERTIFICATE_UNKNOWN;
+ }
+}
diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc
index 8d03623..814cce1 100644
--- a/src/ssl/t1_lib.cc
+++ b/src/ssl/t1_lib.cc
@@ -1810,7 +1810,7 @@
// selected cipher in HelloRetryRequest does not match. This avoids performing
// the transcript hash transformation for multiple hashes.
if (hs->received_hello_retry_request &&
- ssl_is_draft21(ssl->version) &&
+ ssl_is_draft22(ssl->version) &&
ssl->session->cipher->algorithm_prf != hs->new_cipher->algorithm_prf) {
return true;
}
@@ -2033,7 +2033,7 @@
return false;
}
- ssl->early_data_accepted = true;
+ ssl->s3->early_data_accepted = true;
return true;
}
@@ -2055,7 +2055,7 @@
}
static bool ext_early_data_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) {
- if (!hs->ssl->early_data_accepted) {
+ if (!hs->ssl->s3->early_data_accepted) {
return true;
}
@@ -3264,6 +3264,7 @@
int sig_ok = ECDSA_do_verify(digest, digest_len, sig.get(), key.get());
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
sig_ok = 1;
+ ERR_clear_error();
#endif
if (!sig_ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 0b4c760..38e4077 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -1808,6 +1808,11 @@
return false;
}
+ if (config->expect_draft_downgrade != !!SSL_is_draft_downgrade(ssl)) {
+ fprintf(stderr, "Got %sdraft downgrade signal, but wanted the opposite.\n",
+ SSL_is_draft_downgrade(ssl) ? "" : "no ");
+ }
+
return true;
}
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index c6d5c65..51effed 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -33,30 +33,18 @@
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
const (
- tls13DraftVersion = 0x7f12
- tls13Draft21Version = 0x7f15
- tls13ExperimentVersion = 0x7e01
tls13Experiment2Version = 0x7e02
- tls13Experiment3Version = 0x7e03
tls13Draft22Version = 0x7f16
)
const (
- TLS13Default = 0
- TLS13Experiment = 1
- TLS13Experiment2 = 2
- TLS13Experiment3 = 3
- TLS13Draft21 = 4
- TLS13Draft22 = 5
+ TLS13Draft22 = 0
+ TLS13Experiment2 = 1
)
var allTLSWireVersions = []uint16{
- tls13DraftVersion,
tls13Draft22Version,
- tls13Draft21Version,
- tls13Experiment3Version,
tls13Experiment2Version,
- tls13ExperimentVersion,
VersionTLS12,
VersionTLS11,
VersionTLS10,
@@ -1525,6 +1513,14 @@
// PadClientHello, if non-zero, pads the ClientHello to a multiple of
// that many bytes.
PadClientHello int
+
+ // SendDraftTLS13DowngradeRandom, if true, causes the server to send the
+ // draft TLS 1.3 anti-downgrade signal.
+ SendDraftTLS13DowngradeRandom bool
+
+ // ExpectDraftTLS13DowngradeRandom, if true, causes the client to
+ // require the server send the draft TLS 1.3 anti-downgrade signal.
+ ExpectDraftTLS13DowngradeRandom bool
}
func (c *Config) serverInit() {
@@ -1637,7 +1633,7 @@
switch vers {
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
return vers, true
- case tls13DraftVersion, tls13Draft22Version, tls13Draft21Version, tls13ExperimentVersion, tls13Experiment2Version, tls13Experiment3Version:
+ case tls13Draft22Version, tls13Experiment2Version:
return VersionTLS13, true
}
}
@@ -1645,40 +1641,16 @@
return 0, false
}
-func isDraft21(vers uint16) bool {
- return vers == tls13Draft21Version || vers == tls13Draft22Version
-}
-
func isDraft22(vers uint16) bool {
return vers == tls13Draft22Version
}
-func isResumptionExperiment(vers uint16) bool {
- return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
-}
-
-func isResumptionClientCCSExperiment(vers uint16) bool {
- return vers == tls13ExperimentVersion || vers == tls13Experiment2Version || vers == tls13Draft22Version
-}
-
-func isResumptionRecordVersionExperiment(vers uint16) bool {
- return vers == tls13Experiment2Version || vers == tls13Experiment3Version || vers == tls13Draft22Version
-}
-
-func isResumptionRecordVersionVariant(variant int) bool {
- return variant == TLS13Experiment2 || variant == TLS13Experiment3 || variant == TLS13Draft22
-}
-
// isSupportedVersion checks if the specified wire version is acceptable. If so,
// it returns true and the corresponding protocol version. Otherwise, it returns
// false.
func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
- if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
- (c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
- (c.TLS13Variant != TLS13Experiment3 && wireVers == tls13Experiment3Version) ||
- (c.TLS13Variant != TLS13Draft22 && wireVers == tls13Draft22Version) ||
- (c.TLS13Variant != TLS13Draft21 && wireVers == tls13Draft21Version) ||
- (c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
+ if (c.TLS13Variant != TLS13Experiment2 && wireVers == tls13Experiment2Version) ||
+ (c.TLS13Variant != TLS13Draft22 && wireVers == tls13Draft22Version) {
return 0, false
}
@@ -1975,6 +1947,8 @@
// See draft-ietf-tls-tls13-16, section 6.3.1.2.
downgradeTLS13 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x01}
downgradeTLS12 = []byte{0x44, 0x4f, 0x57, 0x4e, 0x47, 0x52, 0x44, 0x00}
+
+ downgradeTLS13Draft = []uint8{0x95, 0xb9, 0x9f, 0x87, 0x22, 0xfe, 0x9b, 0x64}
)
func containsGREASE(values []uint16) bool {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index c6ee443..6493aa7 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -802,9 +802,6 @@
if c.haveVers {
expect = c.vers
if c.vers >= VersionTLS13 {
- expect = VersionTLS10
- }
- if isResumptionRecordVersionExperiment(c.wireVersion) {
expect = VersionTLS12
}
} else {
@@ -907,7 +904,7 @@
// Check they match that we expect.
expected := [6]byte{byte(recordTypeChangeCipherSpec), 3, 1, 0, 1, 1}
- if isResumptionRecordVersionExperiment(c.wireVersion) {
+ if c.vers >= VersionTLS13 {
expected[2] = 3
}
if !bytes.Equal(b.data[:6], expected[:]) {
@@ -1197,7 +1194,7 @@
}
}
vers := c.vers
- if vers == 0 || vers >= VersionTLS13 {
+ if vers == 0 {
// Some TLS servers fail if the record version is
// greater than TLS 1.0 for the initial ClientHello.
//
@@ -1205,7 +1202,7 @@
// layer to {3, 1}.
vers = VersionTLS10
}
- if isResumptionRecordVersionExperiment(c.wireVersion) || isResumptionRecordVersionExperiment(c.out.wireVersion) {
+ if c.vers >= VersionTLS13 || c.out.version >= VersionTLS13 {
vers = VersionTLS12
}
@@ -1240,7 +1237,7 @@
}
c.out.freeBlock(b)
- if typ == recordTypeChangeCipherSpec && !isResumptionExperiment(c.wireVersion) {
+ if typ == recordTypeChangeCipherSpec && c.vers < VersionTLS13 {
err = c.out.changeCipherSpec(c.config)
if err != nil {
return n, c.sendAlertLocked(alertLevelError, err.(alert))
@@ -1563,7 +1560,7 @@
earlyALPN: c.clientProtocol,
}
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
session.masterSecret = deriveSessionPSK(cipherSuite, c.wireVersion, c.resumptionSecret, newSessionTicket.ticketNonce)
}
@@ -1854,7 +1851,7 @@
if cipherSuite == nil {
cipherSuite = c.earlyCipherSuite
}
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
hash := cipherSuite.hash()
exporterKeyingLabel := []byte("exporter")
contextHash := hash.New()
@@ -1951,7 +1948,7 @@
maxEarlyDataSize: c.config.MaxEarlyDataSize,
}
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
m.ticketNonce = nonce
}
@@ -1970,7 +1967,7 @@
earlyALPN: []byte(c.clientProtocol),
}
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
state.masterSecret = deriveSessionPSK(c.cipherSuite, c.wireVersion, c.resumptionSecret, nonce)
}
@@ -2017,11 +2014,7 @@
payload := make([]byte, 5+len)
payload[0] = byte(recordTypeApplicationData)
payload[1] = 3
- payload[2] = 1
- if isResumptionRecordVersionVariant(c.config.TLS13Variant) {
- payload[1] = 3
- payload[2] = 3
- }
+ payload[2] = 3
payload[3] = byte(len >> 8)
payload[4] = byte(len)
_, err := c.conn.Write(payload)
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index 55d21c9..0f4a714 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -377,7 +377,7 @@
// set. Fill in an arbitrary TLS 1.3 version to compute
// the binder.
if session.vers < VersionTLS13 {
- version = tls13DraftVersion
+ version = tls13Draft22Version
}
generatePSKBinders(version, hello, pskCipherSuite, session.masterSecret, []byte{}, []byte{}, c.config)
}
@@ -416,14 +416,16 @@
if !c.config.Bugs.SkipChangeCipherSpec && isDraft22(session.wireVersion) {
c.wireVersion = session.wireVersion
+ c.vers = VersionTLS13
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
c.wireVersion = 0
+ c.vers = 0
}
var earlyTrafficSecret []byte
- if isDraft21(session.wireVersion) {
- earlyTrafficSecret = finishedHash.deriveSecret(earlyTrafficLabelDraft21)
- c.earlyExporterSecret = finishedHash.deriveSecret(earlyExporterLabelDraft21)
+ if isDraft22(session.wireVersion) {
+ earlyTrafficSecret = finishedHash.deriveSecret(earlyTrafficLabelDraft22)
+ c.earlyExporterSecret = finishedHash.deriveSecret(earlyExporterLabelDraft22)
} else {
earlyTrafficSecret = finishedHash.deriveSecret(earlyTrafficLabel)
c.earlyExporterSecret = finishedHash.deriveSecret(earlyExporterLabel)
@@ -598,6 +600,9 @@
return errors.New("tls: downgrade from TLS 1.2 detected")
}
}
+ if c.config.Bugs.ExpectDraftTLS13DowngradeRandom && !bytes.Equal(serverHello.random[len(serverHello.random)-8:], downgradeTLS13Draft) {
+ return errors.New("tls: server did not send draft TLS 1.3 anti-downgrade signal")
+ }
suite := mutualCipherSuite(hello.cipherSuites, serverHello.cipherSuite)
if suite == nil {
@@ -626,7 +631,7 @@
hs.writeHash(helloBytes, hs.c.sendHandshakeSeq-1)
if haveHelloRetryRequest {
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
err = hs.finishedHash.UpdateForHelloRetryRequest()
if err != nil {
return err
@@ -727,13 +732,13 @@
func (hs *clientHandshakeState) doTLS13Handshake() error {
c := hs.c
- if isResumptionExperiment(c.wireVersion) && !isDraft22(c.wireVersion) {
+ if !isDraft22(c.wireVersion) {
// Early versions of the middlebox hacks inserted
// ChangeCipherSpec differently on 0-RTT and 2-RTT handshakes.
c.expectTLS13ChangeCipherSpec = true
}
- if isResumptionExperiment(c.wireVersion) && !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
+ if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
return errors.New("tls: session IDs did not match.")
}
@@ -791,9 +796,9 @@
clientLabel := clientHandshakeTrafficLabel
serverLabel := serverHandshakeTrafficLabel
- if isDraft21(c.wireVersion) {
- clientLabel = clientHandshakeTrafficLabelDraft21
- serverLabel = serverHandshakeTrafficLabelDraft21
+ if isDraft22(c.wireVersion) {
+ clientLabel = clientHandshakeTrafficLabelDraft22
+ serverLabel = serverHandshakeTrafficLabelDraft22
}
// Derive handshake traffic keys and switch read key to handshake
@@ -939,10 +944,10 @@
clientLabel = clientApplicationTrafficLabel
serverLabel = serverApplicationTrafficLabel
exportLabel := exporterLabel
- if isDraft21(c.wireVersion) {
- clientLabel = clientApplicationTrafficLabelDraft21
- serverLabel = serverApplicationTrafficLabelDraft21
- exportLabel = exporterLabelDraft21
+ if isDraft22(c.wireVersion) {
+ clientLabel = clientApplicationTrafficLabelDraft22
+ serverLabel = serverApplicationTrafficLabelDraft22
+ exportLabel = exporterLabelDraft22
}
clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
@@ -991,7 +996,7 @@
helloRequest := new(helloRequestMsg)
c.writeRecord(recordTypeHandshake, helloRequest.marshal())
}
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
endOfEarlyData := new(endOfEarlyDataMsg)
endOfEarlyData.nonEmpty = c.config.Bugs.NonEmptyEndOfEarlyData
c.writeRecord(recordTypeHandshake, endOfEarlyData.marshal())
@@ -1001,7 +1006,7 @@
}
}
- if !c.config.Bugs.SkipChangeCipherSpec && isResumptionClientCCSExperiment(c.wireVersion) && !hs.hello.hasEarlyData {
+ if !c.config.Bugs.SkipChangeCipherSpec && !hs.hello.hasEarlyData {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
@@ -1098,8 +1103,8 @@
c.useOutTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret)
resumeLabel := resumptionLabel
- if isDraft21(c.wireVersion) {
- resumeLabel = resumptionLabelDraft21
+ if isDraft22(c.wireVersion) {
+ resumeLabel = resumptionLabelDraft22
}
c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
@@ -1845,8 +1850,8 @@
binderSize := len(hello.pskBinders)*(binderLen+1) + 2
truncatedHello := helloBytes[:len(helloBytes)-binderSize]
binderLabel := resumptionPSKBinderLabel
- if isDraft21(version) {
- binderLabel = resumptionPSKBinderLabelDraft21
+ if isDraft22(version) {
+ binderLabel = resumptionPSKBinderLabelDraft22
}
binder := computePSKBinder(psk, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
if config.Bugs.SendShortPSKBinder {
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 93d02e1..c4a6e16 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -896,21 +896,17 @@
}
if m.versOverride != 0 {
hello.addU16(m.versOverride)
- } else if isResumptionExperiment(m.vers) {
+ } else if vers >= VersionTLS13 {
hello.addU16(VersionTLS12)
} else {
hello.addU16(m.vers)
}
hello.addBytes(m.random)
- if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
- sessionId := hello.addU8LengthPrefixed()
- sessionId.addBytes(m.sessionId)
- }
+ sessionId := hello.addU8LengthPrefixed()
+ sessionId.addBytes(m.sessionId)
hello.addU16(m.cipherSuite)
- if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
- hello.addU8(m.compressionMethod)
- }
+ hello.addU8(m.compressionMethod)
extensions := hello.addU16LengthPrefixed()
@@ -927,14 +923,12 @@
extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity)
}
- if isResumptionExperiment(m.vers) || m.supportedVersOverride != 0 {
- extensions.addU16(extensionSupportedVersions)
- extensions.addU16(2) // Length
- if m.supportedVersOverride != 0 {
- extensions.addU16(m.supportedVersOverride)
- } else {
- extensions.addU16(m.vers)
- }
+ extensions.addU16(extensionSupportedVersions)
+ extensions.addU16(2) // Length
+ if m.supportedVersOverride != 0 {
+ extensions.addU16(m.supportedVersOverride)
+ } else {
+ extensions.addU16(m.vers)
}
if len(m.customExtension) > 0 {
extensions.addU16(extensionCustom)
@@ -980,19 +974,11 @@
if !ok {
return false
}
- if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
- if !reader.readU8LengthPrefixedBytes(&m.sessionId) {
- return false
- }
- }
- if !reader.readU16(&m.cipherSuite) {
+ if !reader.readU8LengthPrefixedBytes(&m.sessionId) ||
+ !reader.readU16(&m.cipherSuite) ||
+ !reader.readU8(&m.compressionMethod) {
return false
}
- if vers < VersionTLS13 || isResumptionExperiment(m.vers) {
- if !reader.readU8(&m.compressionMethod) {
- return false
- }
- }
if len(reader) == 0 && m.vers < VersionTLS13 {
// Extension data is optional before TLS 1.3.
@@ -1052,9 +1038,7 @@
}
m.hasPSKIdentity = true
case extensionSupportedVersions:
- if !isResumptionExperiment(m.vers) {
- return false
- }
+ // Parsed above.
default:
// Only allow the 3 extensions that are sent in
// the clear in TLS 1.3.
@@ -1386,7 +1370,7 @@
retryRequest.addU8(m.compressionMethod)
} else {
retryRequest.addU16(m.vers)
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
retryRequest.addU16(m.cipherSuite)
}
}
@@ -1440,7 +1424,7 @@
compressionMethod != 0 {
return false
}
- } else if isDraft21(m.vers) && !reader.readU16(&m.cipherSuite) {
+ } else if isDraft22(m.vers) && !reader.readU16(&m.cipherSuite) {
return false
}
var extensions byteReader
@@ -1806,7 +1790,7 @@
requestContext := body.addU8LengthPrefixed()
requestContext.addBytes(m.requestContext)
extensions := newByteBuilder()
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
extensions = body.addU16LengthPrefixed()
if m.hasSignatureAlgorithm {
extensions.addU16(extensionSignatureAlgorithms)
@@ -1884,7 +1868,7 @@
m.raw = data
reader := byteReader(data[4:])
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
var extensions byteReader
if !reader.readU8LengthPrefixedBytes(&m.requestContext) ||
!reader.readU16LengthPrefixed(&extensions) ||
@@ -2037,7 +2021,7 @@
body.addU32(m.ticketLifetime)
if version >= VersionTLS13 {
body.addU32(m.ticketAgeAdd)
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
body.addU8LengthPrefixed().addBytes(m.ticketNonce)
}
}
@@ -2049,7 +2033,7 @@
extensions := body.addU16LengthPrefixed()
if m.maxEarlyDataSize > 0 {
extID := extensionTicketEarlyDataInfo
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
extID = extensionEarlyData
}
extensions.addU16(extID)
@@ -2089,7 +2073,7 @@
}
m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
data = data[4:]
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
nonceLen := int(data[0])
data = data[1:]
if len(data) < nonceLen {
@@ -2128,7 +2112,7 @@
}
extID := extensionTicketEarlyDataInfo
- if isDraft21(m.vers) {
+ if isDraft22(m.vers) {
extID = extensionEarlyData
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 9ba6c2c..6b7daee 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -281,7 +281,7 @@
}
if config.Bugs.ExpectNoTLS12Session {
- if len(hs.clientHello.sessionId) > 0 && !isResumptionExperiment(c.wireVersion) {
+ if len(hs.clientHello.sessionId) > 0 && c.vers >= VersionTLS13 {
return fmt.Errorf("tls: client offered an unexpected session ID")
}
if len(hs.clientHello.sessionTicket) > 0 {
@@ -585,7 +585,7 @@
}
if sendHelloRetryRequest {
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
if err := hs.finishedHash.UpdateForHelloRetryRequest(); err != nil {
return err
}
@@ -654,7 +654,7 @@
// PSK binders and obfuscated ticket age are both updated in the
// second ClientHello.
- if isDraft21(c.wireVersion) && len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+ if isDraft22(c.wireVersion) && len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
newClientHelloCopy.pskIdentities = oldClientHelloCopy.pskIdentities
} else {
if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
@@ -695,9 +695,9 @@
}
if encryptedExtensions.extensions.hasEarlyData {
var earlyTrafficSecret []byte
- if isDraft21(c.wireVersion) {
- earlyTrafficSecret = hs.finishedHash.deriveSecret(earlyTrafficLabelDraft21)
- c.earlyExporterSecret = hs.finishedHash.deriveSecret(earlyExporterLabelDraft21)
+ if isDraft22(c.wireVersion) {
+ earlyTrafficSecret = hs.finishedHash.deriveSecret(earlyTrafficLabelDraft22)
+ c.earlyExporterSecret = hs.finishedHash.deriveSecret(earlyExporterLabelDraft22)
} else {
earlyTrafficSecret = hs.finishedHash.deriveSecret(earlyTrafficLabel)
c.earlyExporterSecret = hs.finishedHash.deriveSecret(earlyExporterLabel)
@@ -809,7 +809,7 @@
}
c.flushHandshake()
- if !c.config.Bugs.SkipChangeCipherSpec && isResumptionExperiment(c.wireVersion) && !sendHelloRetryRequest {
+ if !c.config.Bugs.SkipChangeCipherSpec && !sendHelloRetryRequest {
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
}
@@ -819,9 +819,9 @@
clientLabel := clientHandshakeTrafficLabel
serverLabel := serverHandshakeTrafficLabel
- if isDraft21(c.wireVersion) {
- clientLabel = clientHandshakeTrafficLabelDraft21
- serverLabel = serverHandshakeTrafficLabelDraft21
+ if isDraft22(c.wireVersion) {
+ clientLabel = clientHandshakeTrafficLabelDraft22
+ serverLabel = serverHandshakeTrafficLabelDraft22
}
// Switch to handshake traffic keys.
@@ -968,10 +968,10 @@
clientLabel = clientApplicationTrafficLabel
serverLabel = serverApplicationTrafficLabel
exportLabel := exporterLabel
- if isDraft21(c.wireVersion) {
- clientLabel = clientApplicationTrafficLabelDraft21
- serverLabel = serverApplicationTrafficLabelDraft21
- exportLabel = exporterLabelDraft21
+ if isDraft22(c.wireVersion) {
+ clientLabel = clientApplicationTrafficLabelDraft22
+ serverLabel = serverApplicationTrafficLabelDraft22
+ exportLabel = exporterLabelDraft22
}
clientTrafficSecret := hs.finishedHash.deriveSecret(clientLabel)
@@ -991,7 +991,7 @@
// Read end_of_early_data.
if encryptedExtensions.extensions.hasEarlyData {
- if isDraft21(c.wireVersion) {
+ if isDraft22(c.wireVersion) {
msg, err := c.readHandshake()
if err != nil {
return err
@@ -1012,7 +1012,7 @@
}
}
}
- if isResumptionClientCCSExperiment(c.wireVersion) && !isDraft22(c.wireVersion) && !hs.clientHello.hasEarlyData {
+ if !isDraft22(c.wireVersion) && !hs.clientHello.hasEarlyData {
// Early versions of the middlebox hacks inserted
// ChangeCipherSpec differently on 0-RTT and 2-RTT handshakes.
c.expectTLS13ChangeCipherSpec = true
@@ -1132,8 +1132,8 @@
c.cipherSuite = hs.suite
resumeLabel := resumptionLabel
- if isDraft21(c.wireVersion) {
- resumeLabel = resumptionLabelDraft21
+ if isDraft22(c.wireVersion) {
+ resumeLabel = resumptionLabelDraft22
}
c.resumptionSecret = hs.finishedHash.deriveSecret(resumeLabel)
@@ -1181,6 +1181,9 @@
if c.vers <= VersionTLS11 && config.maxVersion(c.isDTLS) == VersionTLS12 {
copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS12)
}
+ if config.Bugs.SendDraftTLS13DowngradeRandom {
+ copy(hs.hello.random[len(hs.hello.random)-8:], downgradeTLS13Draft)
+ }
if len(hs.clientHello.sessionId) == 0 && c.config.Bugs.ExpectClientHelloSessionID {
return false, errors.New("tls: expected non-empty session ID from client")
@@ -2135,8 +2138,8 @@
}
binderLabel := resumptionPSKBinderLabel
- if isDraft21(version) {
- binderLabel = resumptionPSKBinderLabelDraft21
+ if isDraft22(version) {
+ binderLabel = resumptionPSKBinderLabelDraft22
}
binder := computePSKBinder(sessionState.masterSecret, version, binderLabel, pskCipherSuite, firstClientHello, helloRetryRequest, truncatedHello)
if !bytes.Equal(binder, binderToVerify) {
diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go
index 54e18cb..62c98b7 100644
--- a/src/ssl/test/runner/prf.go
+++ b/src/ssl/test/runner/prf.go
@@ -396,7 +396,7 @@
}
func (h *finishedHash) nextSecret() {
- if isDraft21(h.wireVersion) {
+ if isDraft22(h.wireVersion) {
derivedLabel := []byte("derived")
h.secret = hkdfExpandLabel(h.hash, h.wireVersion, h.secret, derivedLabel, h.hash.New().Sum(nil), h.hash.Size())
}
@@ -410,7 +410,7 @@
}
versionLabel := []byte("TLS 1.3, ")
- if isDraft21(version) {
+ if isDraft22(version) {
versionLabel = []byte("tls13 ")
}
@@ -450,17 +450,17 @@
exporterLabel = []byte("exporter master secret")
resumptionLabel = []byte("resumption master secret")
- externalPSKBinderLabelDraft21 = []byte("ext binder")
- resumptionPSKBinderLabelDraft21 = []byte("res binder")
- earlyTrafficLabelDraft21 = []byte("c e traffic")
- clientHandshakeTrafficLabelDraft21 = []byte("c hs traffic")
- serverHandshakeTrafficLabelDraft21 = []byte("s hs traffic")
- clientApplicationTrafficLabelDraft21 = []byte("c ap traffic")
- serverApplicationTrafficLabelDraft21 = []byte("s ap traffic")
- applicationTrafficLabelDraft21 = []byte("traffic upd")
- earlyExporterLabelDraft21 = []byte("e exp master")
- exporterLabelDraft21 = []byte("exp master")
- resumptionLabelDraft21 = []byte("res master")
+ externalPSKBinderLabelDraft22 = []byte("ext binder")
+ resumptionPSKBinderLabelDraft22 = []byte("res binder")
+ earlyTrafficLabelDraft22 = []byte("c e traffic")
+ clientHandshakeTrafficLabelDraft22 = []byte("c hs traffic")
+ serverHandshakeTrafficLabelDraft22 = []byte("s hs traffic")
+ clientApplicationTrafficLabelDraft22 = []byte("c ap traffic")
+ serverApplicationTrafficLabelDraft22 = []byte("s ap traffic")
+ applicationTrafficLabelDraft22 = []byte("traffic upd")
+ earlyExporterLabelDraft22 = []byte("e exp master")
+ exporterLabelDraft22 = []byte("exp master")
+ resumptionLabelDraft22 = []byte("res master")
resumptionPSKLabel = []byte("resumption")
)
@@ -515,8 +515,8 @@
func updateTrafficSecret(hash crypto.Hash, version uint16, secret []byte) []byte {
trafficLabel := applicationTrafficLabel
- if isDraft21(version) {
- trafficLabel = applicationTrafficLabelDraft21
+ if isDraft22(version) {
+ trafficLabel = applicationTrafficLabelDraft22
}
return hkdfExpandLabel(hash, version, secret, trafficLabel, nil, hash.Size())
}
@@ -526,7 +526,7 @@
finishedHash.addEntropy(psk)
binderKey := finishedHash.deriveSecret(label)
finishedHash.Write(clientHello)
- if isDraft21(version) && len(helloRetryRequest) != 0 {
+ if isDraft22(version) && len(helloRetryRequest) != 0 {
finishedHash.UpdateForHelloRetryRequest()
}
finishedHash.Write(helloRetryRequest)
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 4cfce26..7506280 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1321,20 +1321,6 @@
versionDTLS: VersionDTLS12,
},
{
- name: "TLS13",
- version: VersionTLS13,
- excludeFlag: "-no-tls13",
- versionWire: tls13DraftVersion,
- tls13Variant: TLS13Default,
- },
- {
- name: "TLS13Draft21",
- version: VersionTLS13,
- excludeFlag: "-no-tls13",
- versionWire: tls13Draft21Version,
- tls13Variant: TLS13Draft21,
- },
- {
name: "TLS13Draft22",
version: VersionTLS13,
excludeFlag: "-no-tls13",
@@ -1342,26 +1328,12 @@
tls13Variant: TLS13Draft22,
},
{
- name: "TLS13Experiment",
- version: VersionTLS13,
- excludeFlag: "-no-tls13",
- versionWire: tls13ExperimentVersion,
- tls13Variant: TLS13Experiment,
- },
- {
name: "TLS13Experiment2",
version: VersionTLS13,
excludeFlag: "-no-tls13",
versionWire: tls13Experiment2Version,
tls13Variant: TLS13Experiment2,
},
- {
- name: "TLS13Experiment3",
- version: VersionTLS13,
- excludeFlag: "-no-tls13",
- versionWire: tls13Experiment3Version,
- tls13Variant: TLS13Experiment3,
- },
}
func allVersions(protocol protocol) []tlsVersion {
@@ -3923,7 +3895,7 @@
// Test that an empty client CA list doesn't send a CA extension.
testCases = append(testCases, testCase{
testType: serverTest,
- name: "TLS13Draft21-Empty-Client-CA-List",
+ name: "TLS13Draft22-Empty-Client-CA-List",
config: Config{
MaxVersion: VersionTLS13,
Certificates: []Certificate{rsaCertificate},
@@ -3931,7 +3903,7 @@
ExpectNoCertificateAuthoritiesExtension: true,
},
},
- tls13Variant: TLS13Draft21,
+ tls13Variant: TLS13Draft22,
flags: []string{
"-require-any-client-certificate",
"-use-client-ca-list", "<EMPTY>",
@@ -5334,9 +5306,8 @@
expectedClientVersion := expectedVersion
if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
expectedClientVersion = VersionTLS12
- expectedServerVersion = VersionTLS12
- if shimVers.tls13Variant != TLS13Default && runnerVers.tls13Variant != TLS13Draft21 && runnerVers.tls13Variant != TLS13Draft22 {
- expectedServerVersion = VersionTLS13
+ if shimVers.tls13Variant == TLS13Draft22 {
+ expectedServerVersion = VersionTLS12
}
}
@@ -5353,10 +5324,7 @@
clientVers = recordVersionToWire(clientVers, protocol)
serverVers := expectedServerVersion
if expectedServerVersion >= VersionTLS13 {
- serverVers = VersionTLS10
- if runnerVers.tls13Variant == TLS13Experiment2 || runnerVers.tls13Variant == TLS13Experiment3 || runnerVers.tls13Variant == TLS13Draft22 {
- serverVers = VersionTLS12
- }
+ serverVers = VersionTLS12
}
serverVers = recordVersionToWire(serverVers, protocol)
@@ -5541,21 +5509,6 @@
expectedError: ":UNEXPECTED_EXTENSION:",
})
- // Test that the non-experimental TLS 1.3 isn't negotiated by the
- // supported_versions extension in the ServerHello.
- testCases = append(testCases, testCase{
- testType: clientTest,
- name: "SupportedVersionSelection-TLS13",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- SendServerSupportedExtensionVersion: tls13DraftVersion,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
-
// Test that the maximum version is selected regardless of the
// client-sent order.
testCases = append(testCases, testCase{
@@ -5563,7 +5516,7 @@
name: "IgnoreClientVersionOrder",
config: Config{
Bugs: ProtocolBugs{
- SendSupportedVersions: []uint16{VersionTLS12, tls13DraftVersion},
+ SendSupportedVersions: []uint16{VersionTLS12, tls13Draft22Version},
},
},
expectedVersion: VersionTLS13,
@@ -5694,6 +5647,27 @@
// TODO(davidben): This test should fail once TLS 1.3 is final
// and the fallback signal restored.
})
+
+ testCases = append(testCases, testCase{
+ name: "Draft-Downgrade-Client",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendDraftTLS13DowngradeRandom: true,
+ },
+ },
+ flags: []string{"-expect-draft-downgrade"},
+ })
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Draft-Downgrade-Server",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectDraftTLS13DowngradeRandom: true,
+ },
+ },
+ })
}
func addMinimumVersionTests() {
@@ -6814,8 +6788,7 @@
MaxVersion: sessionVers.version,
TLS13Variant: sessionVers.tls13Variant,
Bugs: ProtocolBugs{
- ExpectNoTLS12Session: sessionVers.version >= VersionTLS13,
- ExpectNoTLS13PSK: sessionVers.version < VersionTLS13,
+ ExpectNoTLS13PSK: sessionVers.version < VersionTLS13,
},
},
expectedVersion: sessionVers.version,
@@ -11380,19 +11353,14 @@
tls13Variant: variant,
})
- hasSessionID := false
- if variant != TLS13Default {
- hasSessionID = true
- }
-
- // Test that the client sends a fake session ID in the correct experiments.
+ // Test that the client sends a fake session ID in TLS 1.3.
testCases = append(testCases, testCase{
testType: clientTest,
name: "TLS13SessionID-" + name,
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- ExpectClientHelloSessionID: hasSessionID,
+ ExpectClientHelloSessionID: true,
},
},
tls13Variant: variant,
@@ -11709,7 +11677,7 @@
expectedError: ":WRONG_CURVE:",
})
- if isDraft21(version.versionWire) {
+ if isDraft22(version.versionWire) {
testCases = append(testCases, testCase{
name: "HelloRetryRequest-CipherChange-" + name,
config: Config{
@@ -11996,7 +11964,7 @@
expectedError: ":DECODE_ERROR:",
})
- if isDraft21(version.versionWire) {
+ if isDraft22(version.versionWire) {
testCases = append(testCases, testCase{
name: "UnknownExtensionInCertificateRequest-" + name,
config: Config{
@@ -12678,7 +12646,7 @@
})
expectedError := ":UNEXPECTED_RECORD:"
- if isDraft21(version.versionWire) {
+ if isDraft22(version.versionWire) {
// In draft-21 and up, early data is expected to be
// terminated by a handshake message, though we test
// with the wrong one.
@@ -12780,7 +12748,7 @@
expectedLocalError: "remote error: error decrypting message",
})
- if isDraft21(version.versionWire) {
+ if isDraft22(version.versionWire) {
testCases = append(testCases, testCase{
testType: serverTest,
name: "Server-NonEmptyEndOfEarlyData-" + name,
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 579cf89..6744a00 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -130,6 +130,7 @@
{ "-use-custom-verify-callback", &TestConfig::use_custom_verify_callback },
{ "-allow-false-start-without-alpn",
&TestConfig::allow_false_start_without_alpn },
+ { "-expect-draft-downgrade", &TestConfig::expect_draft_downgrade },
};
const Flag<std::string> kStringFlags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 49b86ed..a459ae5 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -146,6 +146,7 @@
bool use_custom_verify_callback = false;
std::string expect_msg_callback;
bool allow_false_start_without_alpn = false;
+ bool expect_draft_downgrade = false;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_initial,
diff --git a/src/ssl/tls13_both.cc b/src/ssl/tls13_both.cc
index 57acbcb..2a5a935 100644
--- a/src/ssl/tls13_both.cc
+++ b/src/ssl/tls13_both.cc
@@ -43,6 +43,14 @@
0x8c, 0x5e, 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c,
};
+// This value was selected by truncating the SHA-256 hash of "Draft TLS 1.3
+// Downgrade" to 8 bytes:
+//
+// echo -n 'Draft TLS 1.3 Downgrade' | sha256sum | head -c 16
+const uint8_t kDraftDowngradeRandom[8] = {0x95, 0xb9, 0x9f, 0x87,
+ 0x22, 0xfe, 0x9b, 0x64};
+
+
bool tls13_get_cert_verify_signature_input(
SSL_HANDSHAKE *hs, Array<uint8_t> *out,
enum ssl_cert_verify_context_t cert_verify_context) {
diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc
index f471a4e..8d46d9f 100644
--- a/src/ssl/tls13_client.cc
+++ b/src/ssl/tls13_client.cc
@@ -104,7 +104,7 @@
CBS body = msg.body;
uint16_t server_version;
if (!CBS_get_u16(&body, &server_version) ||
- (ssl_is_draft21(ssl->version) &&
+ (ssl_is_draft22(ssl->version) &&
!CBS_get_u16(&body, &cipher_suite)) ||
!CBS_get_u16_length_prefixed(&body, &extensions) ||
CBS_len(&body) != 0) {
@@ -114,7 +114,7 @@
}
}
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite);
// Check if the cipher is a TLS 1.3 cipher.
if (cipher == NULL ||
@@ -253,12 +253,11 @@
uint8_t compression_method;
if (!CBS_get_u16(&body, &server_version) ||
!CBS_get_bytes(&body, &server_random, SSL3_RANDOM_SIZE) ||
- (ssl_is_resumption_experiment(ssl->version) &&
- (!CBS_get_u8_length_prefixed(&body, &session_id) ||
- !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len))) ||
+ !CBS_get_u8_length_prefixed(&body, &session_id) ||
+ !CBS_mem_equal(&session_id, hs->session_id, hs->session_id_len) ||
!CBS_get_u16(&body, &cipher_suite) ||
- (ssl_is_resumption_experiment(ssl->version) &&
- (!CBS_get_u8(&body, &compression_method) || compression_method != 0)) ||
+ !CBS_get_u8(&body, &compression_method) ||
+ compression_method != 0 ||
!CBS_get_u16_length_prefixed(&body, &extensions) ||
CBS_len(&body) != 0) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -266,10 +265,7 @@
return ssl_hs_error;
}
- uint16_t expected_version = ssl_is_resumption_experiment(ssl->version)
- ? TLS1_2_VERSION
- : ssl->version;
- if (server_version != expected_version) {
+ if (server_version != TLS1_2_VERSION) {
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
return ssl_hs_error;
@@ -297,7 +293,7 @@
}
// Check that the cipher matches the one in the HelloRetryRequest.
- if (ssl_is_draft21(ssl->version) &&
+ if (ssl_is_draft22(ssl->version) &&
hs->received_hello_retry_request &&
hs->new_cipher != cipher) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
@@ -324,14 +320,6 @@
return ssl_hs_error;
}
- // supported_versions is parsed in handshake_client to select the experimental
- // TLS 1.3 version.
- if (have_supported_versions && !ssl_is_resumption_experiment(ssl->version)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
-
alert = SSL_AD_DECODE_ERROR;
if (have_pre_shared_key) {
if (ssl->session == NULL) {
@@ -426,8 +414,7 @@
if (!hs->early_data_offered) {
// Earlier versions of the resumption experiment added ChangeCipherSpec just
// before the Finished flight.
- if (ssl_is_resumption_client_ccs_experiment(ssl->version) &&
- !ssl_is_draft22(ssl->version) &&
+ if (!ssl_is_draft22(ssl->version) &&
!ssl->method->add_change_cipher_spec(ssl)) {
return ssl_hs_error;
}
@@ -477,7 +464,7 @@
hs->new_session->early_alpn_len = ssl->s3->alpn_selected.size();
}
- if (ssl->early_data_accepted) {
+ if (ssl->s3->early_data_accepted) {
if (hs->early_session->cipher != hs->new_session->cipher ||
MakeConstSpan(hs->early_session->early_alpn,
hs->early_session->early_alpn_len) !=
@@ -497,7 +484,7 @@
ssl->method->next_message(ssl);
hs->tls13_state = state_read_certificate_request;
- if (hs->in_early_data && !ssl->early_data_accepted) {
+ if (hs->in_early_data && !ssl->s3->early_data_accepted) {
return ssl_hs_early_data_rejected;
}
return ssl_hs_ok;
@@ -523,7 +510,7 @@
}
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
bool have_sigalgs = false, have_ca = false;
CBS sigalgs, ca;
const SSL_EXTENSION_TYPE ext_types[] = {
@@ -676,9 +663,9 @@
static enum ssl_hs_wait_t do_send_end_of_early_data(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (ssl->early_data_accepted) {
+ if (ssl->s3->early_data_accepted) {
hs->can_early_write = false;
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
ScopedCBB cbb;
CBB body;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
@@ -917,7 +904,7 @@
CBS body = msg.body, ticket_nonce, ticket, extensions;
if (!CBS_get_u32(&body, &server_timeout) ||
!CBS_get_u32(&body, &session->ticket_age_add) ||
- (ssl_is_draft21(ssl->version) &&
+ (ssl_is_draft22(ssl->version) &&
!CBS_get_u8_length_prefixed(&body, &ticket_nonce)) ||
!CBS_get_u16_length_prefixed(&body, &ticket) ||
!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
@@ -941,7 +928,7 @@
// Parse out the extensions.
bool have_early_data_info = false;
CBS early_data_info;
- uint16_t ext_id = ssl_is_draft21(ssl->version)
+ uint16_t ext_id = ssl_is_draft22(ssl->version)
? TLSEXT_TYPE_early_data
: TLSEXT_TYPE_ticket_early_data_info;
const SSL_EXTENSION_TYPE ext_types[] = {
diff --git a/src/ssl/tls13_enc.cc b/src/ssl/tls13_enc.cc
index 9dcd071..1bf820e 100644
--- a/src/ssl/tls13_enc.cc
+++ b/src/ssl/tls13_enc.cc
@@ -72,7 +72,7 @@
size_t label_len, const uint8_t *hash,
size_t hash_len, size_t len) {
const char *kTLS13LabelVersion =
- ssl_is_draft21(version) ? "tls13 " : "TLS 1.3, ";
+ ssl_is_draft22(version) ? "tls13 " : "TLS 1.3, ";
ScopedCBB cbb;
CBB child;
@@ -104,7 +104,7 @@
SSL *const ssl = hs->ssl;
// Draft 18 does not include the extra Derive-Secret step.
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
uint8_t derive_context[EVP_MAX_MD_SIZE];
unsigned derive_context_len;
if (!EVP_Digest(nullptr, 0, derive_context, &derive_context_len,
@@ -224,24 +224,24 @@
static const char kTLS13LabelServerApplicationTraffic[] =
"server application traffic secret";
-static const char kTLS13Draft21LabelExporter[] = "exp master";
-static const char kTLS13Draft21LabelEarlyExporter[] = "e exp master";
+static const char kTLS13Draft22LabelExporter[] = "exp master";
+static const char kTLS13Draft22LabelEarlyExporter[] = "e exp master";
-static const char kTLS13Draft21LabelClientEarlyTraffic[] = "c e traffic";
-static const char kTLS13Draft21LabelClientHandshakeTraffic[] = "c hs traffic";
-static const char kTLS13Draft21LabelServerHandshakeTraffic[] = "s hs traffic";
-static const char kTLS13Draft21LabelClientApplicationTraffic[] = "c ap traffic";
-static const char kTLS13Draft21LabelServerApplicationTraffic[] = "s ap traffic";
+static const char kTLS13Draft22LabelClientEarlyTraffic[] = "c e traffic";
+static const char kTLS13Draft22LabelClientHandshakeTraffic[] = "c hs traffic";
+static const char kTLS13Draft22LabelServerHandshakeTraffic[] = "s hs traffic";
+static const char kTLS13Draft22LabelClientApplicationTraffic[] = "c ap traffic";
+static const char kTLS13Draft22LabelServerApplicationTraffic[] = "s ap traffic";
int tls13_derive_early_secrets(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
uint16_t version = SSL_get_session(ssl)->ssl_version;
- const char *early_traffic_label = ssl_is_draft21(version)
- ? kTLS13Draft21LabelClientEarlyTraffic
+ const char *early_traffic_label = ssl_is_draft22(version)
+ ? kTLS13Draft22LabelClientEarlyTraffic
: kTLS13LabelClientEarlyTraffic;
- const char *early_exporter_label = ssl_is_draft21(version)
- ? kTLS13Draft21LabelEarlyExporter
+ const char *early_exporter_label = ssl_is_draft22(version)
+ ? kTLS13Draft22LabelEarlyExporter
: kTLS13LabelEarlyExporter;
if (!derive_secret(hs, hs->early_traffic_secret, hs->hash_len,
early_traffic_label, strlen(early_traffic_label)) ||
@@ -257,11 +257,11 @@
int tls13_derive_handshake_secrets(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- const char *client_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelClientHandshakeTraffic
+ const char *client_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelClientHandshakeTraffic
: kTLS13LabelClientHandshakeTraffic;
- const char *server_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelServerHandshakeTraffic
+ const char *server_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelServerHandshakeTraffic
: kTLS13LabelServerHandshakeTraffic;
return derive_secret(hs, hs->client_handshake_secret, hs->hash_len,
client_label, strlen(client_label)) &&
@@ -276,14 +276,14 @@
int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
ssl->s3->exporter_secret_len = hs->hash_len;
- const char *client_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelClientApplicationTraffic
+ const char *client_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelClientApplicationTraffic
: kTLS13LabelClientApplicationTraffic;
- const char *server_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelServerApplicationTraffic
+ const char *server_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelServerApplicationTraffic
: kTLS13LabelServerApplicationTraffic;
- const char *exporter_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelExporter
+ const char *exporter_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelExporter
: kTLS13LabelExporter;
return derive_secret(hs, hs->client_traffic_secret_0, hs->hash_len,
client_label, strlen(client_label)) &&
@@ -301,7 +301,7 @@
static const char kTLS13LabelApplicationTraffic[] =
"application traffic secret";
-static const char kTLS13Draft21LabelApplicationTraffic[] = "traffic upd";
+static const char kTLS13Draft22LabelApplicationTraffic[] = "traffic upd";
int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
uint8_t *secret;
@@ -314,8 +314,8 @@
secret_len = ssl->s3->write_traffic_secret_len;
}
- const char *traffic_label = ssl_is_draft21(ssl->version)
- ? kTLS13Draft21LabelApplicationTraffic
+ const char *traffic_label = ssl_is_draft22(ssl->version)
+ ? kTLS13Draft22LabelApplicationTraffic
: kTLS13LabelApplicationTraffic;
const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
@@ -329,15 +329,15 @@
}
static const char kTLS13LabelResumption[] = "resumption master secret";
-static const char kTLS13Draft21LabelResumption[] = "res master";
+static const char kTLS13Draft22LabelResumption[] = "res master";
int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) {
if (hs->hash_len > SSL_MAX_MASTER_KEY_LENGTH) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- const char *resumption_label = ssl_is_draft21(hs->ssl->version)
- ? kTLS13Draft21LabelResumption
+ const char *resumption_label = ssl_is_draft22(hs->ssl->version)
+ ? kTLS13Draft22LabelResumption
: kTLS13LabelResumption;
hs->new_session->master_key_length = hs->hash_len;
return derive_secret(hs, hs->new_session->master_key,
@@ -388,7 +388,7 @@
static const char kTLS13LabelResumptionPSK[] = "resumption";
bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce) {
- if (!ssl_is_draft21(session->ssl_version)) {
+ if (!ssl_is_draft22(session->ssl_version)) {
return true;
}
@@ -413,7 +413,7 @@
}
uint16_t version = SSL_get_session(ssl)->ssl_version;
- if (!ssl_is_draft21(version)) {
+ if (!ssl_is_draft22(version)) {
const EVP_MD *digest = ssl_session_get_digest(SSL_get_session(ssl));
return hkdf_expand_label(out.data(), version, digest, secret.data(),
secret.size(), label.data(), label.size(),
@@ -443,7 +443,7 @@
}
static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
-static const char kTLS13Draft21LabelPSKBinder[] = "res binder";
+static const char kTLS13Draft22LabelPSKBinder[] = "res binder";
static int tls13_psk_binder(uint8_t *out, uint16_t version,
const EVP_MD *digest, uint8_t *psk, size_t psk_len,
@@ -461,8 +461,8 @@
NULL, 0)) {
return 0;
}
- const char *binder_label = ssl_is_draft21(version)
- ? kTLS13Draft21LabelPSKBinder
+ const char *binder_label = ssl_is_draft22(version)
+ ? kTLS13Draft22LabelPSKBinder
: kTLS13LabelPSKBinder;
uint8_t binder_key[EVP_MAX_MD_SIZE] = {0};
diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc
index 1040ace..4651459 100644
--- a/src/ssl/tls13_server.cc
+++ b/src/ssl/tls13_server.cc
@@ -182,7 +182,7 @@
SSL3_MT_NEW_SESSION_TICKET) ||
!CBB_add_u32(&body, session->timeout) ||
!CBB_add_u32(&body, session->ticket_age_add) ||
- (ssl_is_draft21(ssl->version) &&
+ (ssl_is_draft22(ssl->version) &&
(!CBB_add_u8_length_prefixed(&body, &nonce_cbb) ||
!CBB_add_bytes(&nonce_cbb, nonce, sizeof(nonce)))) ||
!CBB_add_u16_length_prefixed(&body, &ticket) ||
@@ -194,7 +194,7 @@
if (ssl->cert->enable_early_data) {
CBB early_data_info;
- if (!CBB_add_u16(&extensions, ssl_is_draft21(ssl->version)
+ if (!CBB_add_u16(&extensions, ssl_is_draft22(ssl->version)
? TLSEXT_TYPE_early_data
: TLSEXT_TYPE_ticket_early_data_info) ||
!CBB_add_u16_length_prefixed(&extensions, &early_data_info) ||
@@ -398,7 +398,7 @@
// The negotiated ALPN must match the one in the ticket.
ssl->s3->alpn_selected ==
MakeConstSpan(session->early_alpn, session->early_alpn_len)) {
- ssl->early_data_accepted = true;
+ ssl->s3->early_data_accepted = true;
}
if (hs->new_session == NULL) {
@@ -457,7 +457,7 @@
return ssl_hs_error;
}
- if (ssl->early_data_accepted) {
+ if (ssl->s3->early_data_accepted) {
if (!tls13_derive_early_secrets(hs)) {
return ssl_hs_error;
}
@@ -469,10 +469,10 @@
bool need_retry;
if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
if (need_retry) {
- ssl->early_data_accepted = false;
+ ssl->s3->early_data_accepted = false;
ssl->s3->skip_early_data = true;
ssl->method->next_message(ssl);
- if (ssl_is_draft21(ssl->version) &&
+ if (ssl_is_draft22(ssl->version) &&
!hs->transcript.UpdateForHelloRetryRequest()) {
return ssl_hs_error;
}
@@ -525,7 +525,7 @@
if (!ssl->method->init_message(ssl, cbb.get(), &body,
SSL3_MT_HELLO_RETRY_REQUEST) ||
!CBB_add_u16(&body, ssl->version) ||
- (ssl_is_draft21(ssl->version) &&
+ (ssl_is_draft22(ssl->version) &&
!CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher))) ||
!tls1_get_shared_group(hs, &group_id) ||
!CBB_add_u16_length_prefixed(&body, &extensions) ||
@@ -580,34 +580,26 @@
static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- uint16_t version = ssl->version;
- if (ssl_is_resumption_experiment(ssl->version)) {
- version = TLS1_2_VERSION;
- }
-
// Send a ServerHello.
ScopedCBB cbb;
CBB body, extensions, session_id;
if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_SERVER_HELLO) ||
- !CBB_add_u16(&body, version) ||
+ !CBB_add_u16(&body, TLS1_2_VERSION) ||
!RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) ||
!CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
- (ssl_is_resumption_experiment(ssl->version) &&
- (!CBB_add_u8_length_prefixed(&body, &session_id) ||
- !CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len))) ||
+ !CBB_add_u8_length_prefixed(&body, &session_id) ||
+ !CBB_add_bytes(&session_id, hs->session_id, hs->session_id_len) ||
!CBB_add_u16(&body, ssl_cipher_get_value(hs->new_cipher)) ||
- (ssl_is_resumption_experiment(ssl->version) && !CBB_add_u8(&body, 0)) ||
+ !CBB_add_u8(&body, 0) ||
!CBB_add_u16_length_prefixed(&body, &extensions) ||
!ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
!ssl_ext_key_share_add_serverhello(hs, &extensions) ||
- (ssl_is_resumption_experiment(ssl->version) &&
- !ssl_ext_supported_versions_add_serverhello(hs, &extensions)) ||
+ !ssl_ext_supported_versions_add_serverhello(hs, &extensions) ||
!ssl_add_message_cbb(ssl, cbb.get())) {
return ssl_hs_error;
}
- if (ssl_is_resumption_experiment(ssl->version) &&
- (!ssl_is_draft22(ssl->version) || !hs->sent_hello_retry_request) &&
+ if ((!ssl_is_draft22(ssl->version) || !hs->sent_hello_retry_request) &&
!ssl->method->add_change_cipher_spec(ssl)) {
return ssl_hs_error;
}
@@ -639,7 +631,7 @@
// Send a CertificateRequest, if necessary.
if (hs->cert_request) {
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
CBB cert_request_extensions, sigalg_contents, sigalgs_cbb;
if (!ssl->method->init_message(ssl, cbb.get(), &body,
SSL3_MT_CERTIFICATE_REQUEST) ||
@@ -732,12 +724,12 @@
return ssl_hs_error;
}
- if (ssl->early_data_accepted) {
+ if (ssl->s3->early_data_accepted) {
// If accepting 0-RTT, we send tickets half-RTT. This gets the tickets on
// the wire sooner and also avoids triggering a write on |SSL_read| when
// processing the client Finished. This requires computing the client
// Finished early. See draft-ietf-tls-tls13-18, section 4.5.1.
- if (ssl_is_draft21(ssl->version)) {
+ if (ssl_is_draft22(ssl->version)) {
static const uint8_t kEndOfEarlyData[4] = {SSL3_MT_END_OF_EARLY_DATA, 0,
0, 0};
if (!hs->transcript.Update(kEndOfEarlyData)) {
@@ -780,7 +772,7 @@
static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
- if (ssl->early_data_accepted) {
+ if (ssl->s3->early_data_accepted) {
if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->early_traffic_secret,
hs->hash_len)) {
return ssl_hs_error;
@@ -790,7 +782,8 @@
hs->in_early_data = true;
}
hs->tls13_state = state_process_end_of_early_data;
- return ssl->early_data_accepted ? ssl_hs_read_end_of_early_data : ssl_hs_ok;
+ return ssl->s3->early_data_accepted ? ssl_hs_read_end_of_early_data
+ : ssl_hs_ok;
}
static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
@@ -798,8 +791,8 @@
if (hs->early_data_offered) {
// If early data was not accepted, the EndOfEarlyData and ChangeCipherSpec
// message will be in the discarded early data.
- if (hs->ssl->early_data_accepted) {
- if (ssl_is_draft21(ssl->version)) {
+ if (hs->ssl->s3->early_data_accepted) {
+ if (ssl_is_draft22(ssl->version)) {
SSLMessage msg;
if (!ssl->method->get_message(ssl, &msg)) {
return ssl_hs_read_message;
@@ -821,8 +814,9 @@
hs->hash_len)) {
return ssl_hs_error;
}
- hs->tls13_state = ssl->early_data_accepted ? state_read_client_finished
- : state_read_client_certificate;
+ hs->tls13_state = ssl->s3->early_data_accepted
+ ? state_read_client_finished
+ : state_read_client_certificate;
return ssl_hs_ok;
}
@@ -921,14 +915,14 @@
if (!ssl_check_message_type(ssl, msg, SSL3_MT_FINISHED) ||
// If early data was accepted, we've already computed the client Finished
// and derived the resumption secret.
- !tls13_process_finished(hs, msg, ssl->early_data_accepted) ||
+ !tls13_process_finished(hs, msg, ssl->s3->early_data_accepted) ||
// evp_aead_seal keys have already been switched.
!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
hs->hash_len)) {
return ssl_hs_error;
}
- if (!ssl->early_data_accepted) {
+ if (!ssl->s3->early_data_accepted) {
if (!ssl_hash_message(hs, msg) ||
!tls13_derive_resumption_secret(hs)) {
return ssl_hs_error;
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index a1363fa..3d34951 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -264,7 +264,7 @@
*out_consumed = in.size() - CBS_len(&cbs);
if (ssl->s3->have_version &&
- ssl_is_resumption_experiment(ssl->version) &&
+ ssl_protocol_version(ssl) >= TLS1_3_VERSION &&
SSL_in_init(ssl) &&
type == SSL3_RT_CHANGE_CIPHER_SPEC &&
ciphertext_len == 1 &&
@@ -357,7 +357,7 @@
if (type == SSL3_RT_ALERT) {
// Return end_of_early_data alerts as-is for the caller to process.
- if (!ssl_is_draft21(ssl->version) &&
+ if (!ssl_is_draft22(ssl->version) &&
out->size() == 2 &&
(*out)[0] == SSL3_AL_WARNING &&
(*out)[1] == TLS1_AD_END_OF_EARLY_DATA) {
diff --git a/src/third_party/fiat/README.md b/src/third_party/fiat/README.md
index 5512715..eaf0a60 100644
--- a/src/third_party/fiat/README.md
+++ b/src/third_party/fiat/README.md
@@ -3,3 +3,41 @@
Some of the code in this directory is generated by
[Fiat](https://github.com/mit-plv/fiat-crypto) and thus these files are
licensed under the MIT license. (See LICENSE file.)
+
+## Curve25519
+
+To generate the field arithmetic procedures in `curve25519.c` from a fiat-crypto
+checkout (as of `c47f48268f15e202a28b556845f231b2038cb426`), run
+`make src/Specific/solinas32_2e255m19_10limbs/femul.c` (replacing `femul` with
+the desired field operation). The "source" file specifying the finite field and
+referencing the desired implementation strategy is
+`src/Specific/solinas32_2e255m19_10limbs/CurveParameters.v`, specifying roughly
+"unsaturated arithmetic modulo 2^255-19 using 10 limbs of radix 2^25.5 in 32-bit
+unsigned integers with a single carry chain and two wraparound carries" where
+only the prime is considered normative and everything else is treated as
+"compiler hints".
+
+## P256
+
+To generate the field arithmetic procedures in `p256.c` from a fiat-crypto
+checkout, run
+`make src/Specific/montgomery64_2e256m2e224p2e192p2e96m1_4limbs/femul.c`.
+The corresponding "source" file is
+`src/Specific/montgomery64_2e256m2e224p2e192p2e96m1_4limbs/CurveParameters.v`,
+specifying roughly "64-bit saturated word-by-word Montgomery reduction modulo
+2^256 - 2^224 + 2^192 + 2^96 - 1". Again, everything except for the prime is
+untrusted. There is currently a known issue where `fesub.c` for p256 does not
+manage to complete the build (specialization) within a week on Coq 8.7.0.
+<https://github.com/JasonGross/fiat-crypto/tree/3e6851ddecaac70d0feb484a75360d57f6e41244/src/Specific/montgomery64_2e256m2e224p2e192p2e96m1_4limbs>
+does manage to build that file, but the work on that branch was never finished
+(the correctness proofs of implementation templates still apply, but the
+now abandoned prototype specialization facilities there are unverified).
+
+## Working With Fiat Crypto Field Arithmetic
+
+The fiat-crypto readme <https://github.com/mit-plv/fiat-crypto#arithmetic-core>
+contains an overview of the implementation templates followed by a tour of the
+specialization machinery. It may be helpful to first read about the less messy
+parts of the system from chapter 3 of <http://adam.chlipala.net/theses/andreser.pdf>.
+There is work ongoing to replace the entire specialization mechanism with
+something much more principled <https://github.com/mit-plv/fiat-crypto/projects/4>.
diff --git a/src/third_party/fiat/curve25519.c b/src/third_party/fiat/curve25519.c
index d54aa83..2e56450 100644
--- a/src/third_party/fiat/curve25519.c
+++ b/src/third_party/fiat/curve25519.c
@@ -122,7 +122,7 @@
//
// Have q+2^(-255)x = 2^(-255)(h + 19 2^(-25) h9 + 2^(-1))
// so floor(2^(-255)(h + 19 2^(-25) h9 + 2^(-1))) = q.
-static void fe_tobytes_impl(uint8_t *s, const uint32_t h[10]) {
+static void fe_tobytes_impl(uint8_t s[32], const uint32_t h[10]) {
assert_fe_loose(h);
int32_t h0 = h[0];
int32_t h1 = h[1];
@@ -203,11 +203,11 @@
s[31] = h9 >> 18;
}
-static void fe_tobytes(uint8_t *s, const fe *h) {
+static void fe_tobytes(uint8_t s[32], const fe *h) {
fe_tobytes_impl(s, h->v);
}
-static void fe_loose_tobytes(uint8_t *s, const fe_loose *h) {
+static void fe_loose_tobytes(uint8_t s[32], const fe_loose *h) {
fe_tobytes_impl(s, h->v);
}
@@ -281,13 +281,6 @@
// h = f + g
// Can overlap h with f or g.
-//
-// Preconditions:
-// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-// |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-//
-// Postconditions:
-// |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
static void fe_add(fe_loose *h, const fe *f, const fe *g) {
assert_fe(f->v);
assert_fe(g->v);
@@ -331,13 +324,6 @@
// h = f - g
// Can overlap h with f or g.
-//
-// Preconditions:
-// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-// |g| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-//
-// Postconditions:
-// |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
static void fe_sub(fe_loose *h, const fe *f, const fe *g) {
assert_fe(f->v);
assert_fe(g->v);
@@ -766,12 +752,6 @@
}
// h = -f
-//
-// Preconditions:
-// |f| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
-//
-// Postconditions:
-// |h| bounded by 1.1*2^25,1.1*2^24,1.1*2^25,1.1*2^24,etc.
static void fe_neg(fe_loose *h, const fe *f) {
assert_fe(f->v);
fe_neg_impl(h->v, f->v);
@@ -794,9 +774,6 @@
// return 0 if f == 0
// return 1 if f != 0
-//
-// Preconditions:
-// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
static int fe_isnonzero(const fe_loose *f) {
uint8_t s[32];
fe_loose_tobytes(s, f);
@@ -807,9 +784,6 @@
// return 1 if f is in {1,3,5,...,q-2}
// return 0 if f is in {0,2,4,...,q-1}
-//
-// Preconditions:
-// |f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
static int fe_isnegative(const fe *f) {
uint8_t s[32];
fe_tobytes(s, f);
@@ -995,7 +969,7 @@
fe_mul_ttt(out, &t0, z);
}
-void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h) {
+void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h) {
fe recip;
fe x;
fe y;
@@ -1007,7 +981,7 @@
s[31] ^= fe_isnegative(&x) << 7;
}
-static void ge_p3_tobytes(uint8_t *s, const ge_p3 *h) {
+static void ge_p3_tobytes(uint8_t s[32], const ge_p3 *h) {
fe recip;
fe x;
fe y;
@@ -3848,7 +3822,7 @@
// s[0]+256*s[1]+...+256^31*s[31] = s mod l
// where l = 2^252 + 27742317777372353535851937790883648493.
// Overwrites s in place.
-void x25519_sc_reduce(uint8_t *s) {
+void x25519_sc_reduce(uint8_t s[64]) {
int64_t s0 = 2097151 & load_3(s);
int64_t s1 = 2097151 & (load_4(s + 2) >> 5);
int64_t s2 = 2097151 & (load_3(s + 5) >> 2);
@@ -4676,8 +4650,8 @@
ED25519_keypair_from_seed(out_public_key, out_private_key, seed);
}
-int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
- const uint8_t private_key[64]) {
+int ED25519_sign(uint8_t out_sig[64], const uint8_t *message,
+ size_t message_len, const uint8_t private_key[64]) {
uint8_t az[SHA512_DIGEST_LENGTH];
SHA512(private_key, 32, az);
@@ -4928,6 +4902,24 @@
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
+
+ // The following implementation was transcribed to Coq and proven to
+ // correspond to unary scalar multiplication in affine coordinates given that
+ // x1 != 0 is the x coordinate of some point on the curve. It was also checked
+ // in Coq that doing a ladderstep with x1 = x3 = 0 gives z2' = z3' = 0, and z2
+ // = z3 = 0 gives z2' = z3' = 0. The statement was quantified over the
+ // underlying field, so it applies to Curve25519 itself and the quadratic
+ // twist of Curve25519. It was not proven in Coq that prime-field arithmetic
+ // correctly simulates extension-field arithmetic on prime-field values.
+ // The decoding of the byte array representation of e was not considered.
+ // Specification of Montgomery curves in affine coordinates:
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Spec/MontgomeryCurve.v#L27>
+ // Proof that these form a group that is isomorphic to a Weierstrass curve:
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/AffineProofs.v#L35>
+ // Coq transcription and correctness proof of the loop (where scalarbits=255):
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZ.v#L118>
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L278>
+ // preconditions: 0 <= e < 2^255 (not necessarily e < order), fe_invert(0) = 0
fe_frombytes(&x1, point);
fe_1(&x2);
fe_0(&z2);
@@ -4937,11 +4929,22 @@
unsigned swap = 0;
int pos;
for (pos = 254; pos >= 0; --pos) {
+ // loop invariant as of right before the test, for the case where x1 != 0:
+ // pos >= -1; if z2 = 0 then x2 is nonzero; if z3 = 0 then x3 is nonzero
+ // let r := e >> (pos+1) in the following equalities of projective points:
+ // to_xz (r*P) === if swap then (x3, z3) else (x2, z2)
+ // to_xz ((r+1)*P) === if swap then (x2, z2) else (x3, z3)
+ // x1 is the nonzero x coordinate of the nonzero point (r*P-(r+1)*P)
unsigned b = 1 & (e[pos / 8] >> (pos & 7));
swap ^= b;
fe_cswap(&x2, &x3, swap);
fe_cswap(&z2, &z3, swap);
swap = b;
+ // Coq transcription of ladderstep formula (called from transcribed loop):
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZ.v#L89>
+ // <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L131>
+ // x1 != 0 <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L217>
+ // x1 = 0 <https://github.com/mit-plv/fiat-crypto/blob/2456d821825521f7e03e65882cc3521795b0320f/src/Curves/Montgomery/XZProofs.v#L147>
fe_sub(&tmp0l, &x3, &z3);
fe_sub(&tmp1l, &x2, &z2);
fe_add(&x2l, &x2, &z2);
@@ -4961,6 +4964,7 @@
fe_mul_ttt(&z3, &x1, &z2);
fe_mul_tll(&z2, &tmp1l, &tmp0l);
}
+ // here pos=-1, so r=e, so to_xz (e*P) === if swap then (x3, z3) else (x2, z2)
fe_cswap(&x2, &x3, swap);
fe_cswap(&z2, &z3, swap);
diff --git a/src/third_party/fiat/internal.h b/src/third_party/fiat/internal.h
index 10218e0..0533d27 100644
--- a/src/third_party/fiat/internal.h
+++ b/src/third_party/fiat/internal.h
@@ -56,17 +56,17 @@
// Addition and subtraction produce fe_loose from (fe, fe).
typedef struct fe_loose { uint32_t v[10]; } fe_loose;
-/* ge means group element.
-
- * Here the group is the set of pairs (x,y) of field elements (see fe.h)
- * satisfying -x^2 + y^2 = 1 + d x^2y^2
- * where d = -121665/121666.
- *
- * Representations:
- * ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
- * ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
- * ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
- * ge_precomp (Duif): (y+x,y-x,2dxy) */
+// ge means group element.
+//
+// Here the group is the set of pairs (x,y) of field elements (see fe.h)
+// satisfying -x^2 + y^2 = 1 + d x^2y^2
+// where d = -121665/121666.
+//
+// Representations:
+// ge_p2 (projective): (X:Y:Z) satisfying x=X/Z, y=Y/Z
+// ge_p3 (extended): (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
+// ge_p1p1 (completed): ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
+// ge_precomp (Duif): (y+x,y-x,2dxy)
typedef struct {
fe X;
@@ -101,7 +101,7 @@
fe_loose T2d;
} ge_cached;
-void x25519_ge_tobytes(uint8_t *s, const ge_p2 *h);
+void x25519_ge_tobytes(uint8_t s[32], const ge_p2 *h);
int x25519_ge_frombytes_vartime(ge_p3 *h, const uint8_t *s);
void x25519_ge_p3_to_cached(ge_cached *r, const ge_p3 *p);
void x25519_ge_p1p1_to_p2(ge_p2 *r, const ge_p1p1 *p);
@@ -112,7 +112,7 @@
ge_p3 *h, const uint8_t a[32], const uint8_t precomp_table[15 * 2 * 32]);
void x25519_ge_scalarmult_base(ge_p3 *h, const uint8_t a[32]);
void x25519_ge_scalarmult(ge_p2 *r, const uint8_t *scalar, const ge_p3 *A);
-void x25519_sc_reduce(uint8_t *s);
+void x25519_sc_reduce(uint8_t s[64]);
enum spake2_state_t {
spake2_state_init = 0,
diff --git a/src/third_party/fiat/p256.c b/src/third_party/fiat/p256.c
index 25ef383..9c7de35 100644
--- a/src/third_party/fiat/p256.c
+++ b/src/third_party/fiat/p256.c
@@ -983,12 +983,24 @@
// Building on top of the field operations we have the operations on the
// elliptic curve group itself. Points on the curve are represented in Jacobian
// coordinates.
+//
+// Both operations were transcribed to Coq and proven to correspond to naive
+// implementations using Affine coordinates, for all suitable fields. In the
+// Coq proofs, issues of constant-time execution and memory layout (aliasing)
+// conventions were not considered. Specification of affine coordinates:
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Spec/WeierstrassCurve.v#L28>
+// As a sanity check, a proof that these points form a commutative group:
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/AffineProofs.v#L33>
// point_double calculates 2*(x_in, y_in, z_in)
//
// The method is taken from:
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
//
+// Coq transcription and correctness proof:
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L93>
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L201>
+//
// Outputs can equal corresponding inputs, i.e., x_out == x_in is allowed.
// while x_out == y_in is not (maybe this works, but it's not tested).
static void point_double(fe x_out, fe y_out, fe z_out,
@@ -1037,6 +1049,10 @@
// http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl,
// adapted for mixed addition (z2 = 1, or z2 = 0 for the point at infinity).
//
+// Coq transcription and correctness proof:
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L135>
+// <https://github.com/mit-plv/fiat-crypto/blob/79f8b5f39ed609339f0233098dee1a3c4e6b3080/src/Curves/Weierstrass/Jacobian.v#L205>
+//
// This function includes a branch for checking whether the two input points
// are equal, (while not equal to the point at infinity). This case never
// happens during single point multiplication, so there is no timing leak for
diff --git a/src/tool/client.cc b/src/tool/client.cc
index fa279ae..fc8f5e0 100644
--- a/src/tool/client.cc
+++ b/src/tool/client.cc
@@ -332,30 +332,14 @@
}
static bool GetTLS13Variant(tls13_variant_t *out, const std::string &in) {
- if (in == "draft") {
+ if (in == "draft22") {
*out = tls13_default;
return true;
}
- if (in == "draft21") {
- *out = tls13_draft21;
- return true;
- }
- if (in == "experiment") {
- *out = tls13_experiment;
- return true;
- }
if (in == "experiment2") {
*out = tls13_experiment2;
return true;
}
- if (in == "experiment3") {
- *out = tls13_experiment3;
- return true;
- }
- if (in == "draft22") {
- *out = tls13_draft22;
- return true;
- }
return false;
}
diff --git a/src/tool/server.cc b/src/tool/server.cc
index 9963885..37235a7 100644
--- a/src/tool/server.cc
+++ b/src/tool/server.cc
@@ -68,10 +68,7 @@
"-early-data", kBooleanArgument, "Allow early data",
},
{
- "-tls13-variant", kBooleanArgument, "Enable TLS 1.3 variants",
- },
- {
- "-tls13-draft22-variant", kBooleanArgument, "Enable TLS 1.3 Draft 22.",
+ "-tls13-variant", kBooleanArgument, "Enables all TLS 1.3 variants",
},
{
"-www", kBooleanArgument,
@@ -310,11 +307,8 @@
SSL_CTX_set_early_data_enabled(ctx.get(), 1);
}
- // Draft 22 variants need to be explicitly enabled.
- if (args_map.count("-tls13-draft22-variant") != 0) {
- SSL_CTX_set_tls13_variant(ctx.get(), tls13_draft22);
- } else if (args_map.count("-tls13-variant") != 0) {
- SSL_CTX_set_tls13_variant(ctx.get(), tls13_experiment);
+ if (args_map.count("-tls13-variant") != 0) {
+ SSL_CTX_set_tls13_variant(ctx.get(), tls13_experiment2);
}
if (args_map.count("-debug") != 0) {
diff --git a/src/util/fipstools/delocate.go b/src/util/fipstools/delocate.go
index 6d56f92..2c1ba49 100644
--- a/src/util/fipstools/delocate.go
+++ b/src/util/fipstools/delocate.go
@@ -792,6 +792,9 @@
const (
instrPush instructionType = iota
instrMove
+ // instrTransformingMove is essentially a move, but it performs some
+ // transformation of the data during the process.
+ instrTransformingMove
instrJump
instrConditionalMove
instrOther
@@ -818,6 +821,11 @@
if len(args) == 1 {
return instrJump
}
+
+ case "vpbroadcastq":
+ if len(args) == 2 {
+ return instrTransformingMove
+ }
}
return instrOther
@@ -870,6 +878,13 @@
}
}
+func finalTransform(w stringWriter, transformInstruction, reg string) wrapperFunc {
+ return func(k func()) {
+ k()
+ w.WriteString("\t" + transformInstruction + " " + reg + ", " + reg + "\n")
+ }
+}
+
func isValidLEATarget(reg string) bool {
return !strings.HasPrefix(reg, "%xmm") && !strings.HasPrefix(reg, "%ymm") && !strings.HasPrefix(reg, "%zmm")
}
@@ -1018,6 +1033,13 @@
case instrMove:
assertNodeType(argNodes[1], ruleRegisterOrConstant)
targetReg = d.contents(argNodes[1])
+ case instrTransformingMove:
+ assertNodeType(argNodes[1], ruleRegisterOrConstant)
+ targetReg = d.contents(argNodes[1])
+ wrappers = append(wrappers, finalTransform(d.output, instructionName, targetReg))
+ if isValidLEATarget(targetReg) {
+ return nil, fmt.Errorf("Currently transforming moves are assumed to target XMM registers. Otherwise we'll pop %rax before reading it to do the transform.")
+ }
default:
return nil, fmt.Errorf("Cannot rewrite GOTPCREL reference for instruction %q", instructionName)
}
diff --git a/src/util/fipstools/testdata/x86_64-GOTRewrite/in.s b/src/util/fipstools/testdata/x86_64-GOTRewrite/in.s
index 9b4b201..0f9c70e 100644
--- a/src/util/fipstools/testdata/x86_64-GOTRewrite/in.s
+++ b/src/util/fipstools/testdata/x86_64-GOTRewrite/in.s
@@ -34,4 +34,8 @@
movq foobar_bss_get@GOTPCREL(%rip), %r11
movq OPENSSL_ia32cap_get@GOTPCREL(%rip), %r11
+ # Transforming moves run the transform in-place after the load.
+ vpbroadcastq stderr@GOTPCREL(%rip), %xmm0
+ vpbroadcastq foo@GOTPCREL(%rip), %xmm0
+
.comm foobar,64,32
diff --git a/src/util/fipstools/testdata/x86_64-GOTRewrite/out.s b/src/util/fipstools/testdata/x86_64-GOTRewrite/out.s
index 0e07721..0420af6 100644
--- a/src/util/fipstools/testdata/x86_64-GOTRewrite/out.s
+++ b/src/util/fipstools/testdata/x86_64-GOTRewrite/out.s
@@ -124,6 +124,28 @@
# WAS movq OPENSSL_ia32cap_get@GOTPCREL(%rip), %r11
leaq OPENSSL_ia32cap_get(%rip), %r11
+ # Transforming moves run the transform in-place after the load.
+# WAS vpbroadcastq stderr@GOTPCREL(%rip), %xmm0
+ leaq -128(%rsp), %rsp
+ pushq %rax
+ pushf
+ leaq stderr_GOTPCREL_external(%rip), %rax
+ addq (%rax), %rax
+ movq (%rax), %rax
+ popf
+ vmovq %rax, %xmm0
+ popq %rax
+ leaq 128(%rsp), %rsp
+ vpbroadcastq %xmm0, %xmm0
+# WAS vpbroadcastq foo@GOTPCREL(%rip), %xmm0
+ leaq -128(%rsp), %rsp
+ pushq %rax
+ leaq .Lfoo_local_target(%rip), %rax
+ vmovq %rax, %xmm0
+ popq %rax
+ leaq 128(%rsp), %rsp
+ vpbroadcastq %xmm0, %xmm0
+
.comm foobar,64,32
.text
BORINGSSL_bcm_text_end: