summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Sloan <varomodt@google.com>2018-04-10 10:22:33 -0700
committerRobert Sloan <varomodt@google.com>2018-04-10 10:23:01 -0700
commitdc2f609faa3d5fa920e2c42a39750dca1a247c8f (patch)
treed5b57ecd5d961f542f8635fbdeefbc5262d779fc /src
parent49d063bbd8327cb483bdee6ea604c068f1bb044e (diff)
downloadboringssl-dc2f609faa3d5fa920e2c42a39750dca1a247c8f.tar.gz
external/boringssl: Sync to f11ea19043f2b3ee42e4a76d0645914347e1a36e.android-o-mr1-iot-preview-8o-mr1-iot-preview-8
This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/ba9da449a4bf5b90cd020807f2c4176e3ab6fe3e..f11ea19043f2b3ee42e4a76d0645914347e1a36e Test: BoringSSL CTS Presubmits. Change-Id: Ifb6e46262349afd7cd7a23d59a684e25fb723208
Diffstat (limited to 'src')
-rw-r--r--src/crypto/asn1/tasn_enc.c2
-rw-r--r--src/crypto/fipsmodule/bn/prime.c62
-rw-r--r--src/crypto/fipsmodule/ec/ec.c12
-rw-r--r--src/crypto/fipsmodule/ec/internal.h7
-rw-r--r--src/crypto/fipsmodule/ec/simple.c81
-rw-r--r--src/crypto/fipsmodule/ec/wnaf.c44
-rw-r--r--src/include/openssl/ssl.h14
-rw-r--r--src/ssl/handoff.cc146
-rw-r--r--src/ssl/handshake.cc5
-rw-r--r--src/ssl/handshake_server.cc190
-rw-r--r--src/ssl/internal.h51
-rw-r--r--src/ssl/ssl_aead_ctx.cc29
-rw-r--r--src/ssl/ssl_key_share.cc54
-rw-r--r--src/ssl/ssl_lib.cc3
-rw-r--r--src/ssl/ssl_test.cc9
-rw-r--r--src/ssl/ssl_transcript.cc4
-rw-r--r--src/ssl/ssl_versions.cc22
-rw-r--r--src/ssl/test/bssl_shim.cc175
-rw-r--r--src/ssl/test/runner/common.go12
-rw-r--r--src/ssl/test/runner/conn.go8
-rw-r--r--src/ssl/test/runner/runner.go19
-rw-r--r--src/ssl/tls_record.cc2
-rw-r--r--src/tool/client.cc4
-rw-r--r--src/tool/server.cc2
-rw-r--r--src/tool/speed.cc16
25 files changed, 613 insertions, 360 deletions
diff --git a/src/crypto/asn1/tasn_enc.c b/src/crypto/asn1/tasn_enc.c
index cc87d349..d89ec8a7 100644
--- a/src/crypto/asn1/tasn_enc.c
+++ b/src/crypto/asn1/tasn_enc.c
@@ -583,6 +583,8 @@ int asn1_ex_i2c(ASN1_VALUE **pval, unsigned char *cout, int *putype,
otmp = (ASN1_OBJECT *)*pval;
cont = otmp->data;
len = otmp->length;
+ if (cont == NULL || len == 0)
+ return -1;
break;
case V_ASN1_NULL:
diff --git a/src/crypto/fipsmodule/bn/prime.c b/src/crypto/fipsmodule/bn/prime.c
index d2dfc2c8..a18d3771 100644
--- a/src/crypto/fipsmodule/bn/prime.c
+++ b/src/crypto/fipsmodule/bn/prime.c
@@ -119,10 +119,8 @@
// Zimmermann's, as implemented in PGP. I have had a read of his comments and
// implemented my own version.
-#define NUMPRIMES 2048
-
-// primes contains all the primes that fit into a uint16_t.
-static const uint16_t primes[NUMPRIMES] = {
+// kPrimes contains the first 2048 primes.
+static const uint16_t kPrimes[] = {
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31,
37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79,
83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
@@ -343,6 +341,16 @@ static int BN_prime_checks_for_size(int bits) {
return 28;
}
+// num_trial_division_primes returns the number of primes to try with trial
+// division before using more expensive checks. For larger numbers, the value
+// of excluding a candidate with trial division is larger.
+static size_t num_trial_division_primes(const BIGNUM *n) {
+ if (n->width * BN_BITS2 > 1024) {
+ return OPENSSL_ARRAY_SIZE(kPrimes);
+ }
+ return OPENSSL_ARRAY_SIZE(kPrimes) / 4;
+}
+
// BN_PRIME_CHECKS_BLINDED is the iteration count for blinding the constant-time
// primality test. See |BN_primality_test| for details. This number is selected
// so that, for a candidate N-bit RSA prime, picking |BN_PRIME_CHECKS_BLINDED|
@@ -592,9 +600,10 @@ uint16_t bn_mod_u16_consttime(const BIGNUM *bn, uint16_t d) {
}
static int bn_trial_division(uint16_t *out, const BIGNUM *bn) {
- for (int i = 1; i < NUMPRIMES; i++) {
- if (bn_mod_u16_consttime(bn, primes[i]) == 0) {
- *out = primes[i];
+ const size_t num_primes = num_trial_division_primes(bn);
+ for (size_t i = 1; i < num_primes; i++) {
+ if (bn_mod_u16_consttime(bn, kPrimes[i]) == 0) {
+ *out = kPrimes[i];
return 1;
}
}
@@ -805,7 +814,8 @@ err:
return ret;
}
-int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx, BN_GENCB *cb) {
+int BN_is_prime_ex(const BIGNUM *candidate, int checks, BN_CTX *ctx,
+ BN_GENCB *cb) {
return BN_is_prime_fasttest_ex(candidate, checks, ctx, 0, cb);
}
@@ -959,10 +969,10 @@ err:
}
static int probable_prime(BIGNUM *rnd, int bits) {
- int i;
- uint16_t mods[NUMPRIMES];
+ uint16_t mods[OPENSSL_ARRAY_SIZE(kPrimes)];
+ const size_t num_primes = num_trial_division_primes(rnd);
BN_ULONG delta;
- BN_ULONG maxdelta = BN_MASK2 - primes[NUMPRIMES - 1];
+ BN_ULONG maxdelta = BN_MASK2 - kPrimes[num_primes - 1];
char is_single_word = bits <= BN_BITS2;
again:
@@ -971,8 +981,8 @@ again:
}
// we now have a random number 'rnd' to test.
- for (i = 1; i < NUMPRIMES; i++) {
- mods[i] = bn_mod_u16_consttime(rnd, primes[i]);
+ for (size_t i = 1; i < num_primes; i++) {
+ mods[i] = bn_mod_u16_consttime(rnd, kPrimes[i]);
}
// If bits is so small that it fits into a single word then we
// additionally don't want to exceed that many bits.
@@ -996,15 +1006,15 @@ loop:
// In the case that the candidate prime is a single word then
// we check that:
- // 1) It's greater than primes[i] because we shouldn't reject
+ // 1) It's greater than kPrimes[i] because we shouldn't reject
// 3 as being a prime number because it's a multiple of
// three.
// 2) That it's not a multiple of a known prime. We don't
// check that rnd-1 is also coprime to all the known
// primes because there aren't many small primes where
// that's true.
- for (i = 1; i < NUMPRIMES && primes[i] < rnd_word; i++) {
- if ((mods[i] + delta) % primes[i] == 0) {
+ for (size_t i = 1; i < num_primes && kPrimes[i] < rnd_word; i++) {
+ if ((mods[i] + delta) % kPrimes[i] == 0) {
delta += 2;
if (delta > maxdelta) {
goto again;
@@ -1013,10 +1023,10 @@ loop:
}
}
} else {
- for (i = 1; i < NUMPRIMES; i++) {
+ for (size_t i = 1; i < num_primes; i++) {
// check that rnd is not a prime and also
// that gcd(rnd-1,primes) == 1 (except for 2)
- if (((mods[i] + delta) % primes[i]) <= 1) {
+ if (((mods[i] + delta) % kPrimes[i]) <= 1) {
delta += 2;
if (delta > maxdelta) {
goto again;
@@ -1038,7 +1048,7 @@ loop:
static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
const BIGNUM *rem, BN_CTX *ctx) {
- int i, ret = 0;
+ int ret = 0;
BIGNUM *t1;
BN_CTX_start(ctx);
@@ -1069,10 +1079,11 @@ static int probable_prime_dh(BIGNUM *rnd, int bits, const BIGNUM *add,
}
// we now have a random number 'rand' to test.
+ const size_t num_primes = num_trial_division_primes(rnd);
loop:
- for (i = 1; i < NUMPRIMES; i++) {
+ for (size_t i = 1; i < num_primes; i++) {
// check that rnd is a prime
- if (bn_mod_u16_consttime(rnd, primes[i]) <= 1) {
+ if (bn_mod_u16_consttime(rnd, kPrimes[i]) <= 1) {
if (!BN_add(rnd, rnd, add)) {
goto err;
}
@@ -1089,7 +1100,7 @@ err:
static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
const BIGNUM *rem, BN_CTX *ctx) {
- int i, ret = 0;
+ int ret = 0;
BIGNUM *t1, *qadd, *q;
bits--;
@@ -1139,13 +1150,14 @@ static int probable_prime_dh_safe(BIGNUM *p, int bits, const BIGNUM *padd,
goto err;
}
+ const size_t num_primes = num_trial_division_primes(p);
loop:
- for (i = 1; i < NUMPRIMES; i++) {
+ for (size_t i = 1; i < num_primes; i++) {
// check that p and q are prime
// check that for p and q
// gcd(p-1,primes) == 1 (except for 2)
- if (bn_mod_u16_consttime(p, primes[i]) == 0 ||
- bn_mod_u16_consttime(q, primes[i]) == 0) {
+ if (bn_mod_u16_consttime(p, kPrimes[i]) == 0 ||
+ bn_mod_u16_consttime(q, kPrimes[i]) == 0) {
if (!BN_add(p, p, padd)) {
goto err;
}
diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c
index 904466af..ee7ec55e 100644
--- a/src/crypto/fipsmodule/ec/ec.c
+++ b/src/crypto/fipsmodule/ec/ec.c
@@ -792,9 +792,19 @@ int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
- return ec_GFp_simple_add(group, r, a, b, ctx);
+ return ec_GFp_simple_add(group, r, a, b, 0 /* both Jacobian */, ctx);
}
+int ec_point_add_mixed(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx) {
+ if (EC_GROUP_cmp(group, r->group, NULL) != 0 ||
+ EC_GROUP_cmp(group, a->group, NULL) != 0 ||
+ EC_GROUP_cmp(group, b->group, NULL) != 0) {
+ OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
+ return 0;
+ }
+ return ec_GFp_simple_add(group, r, a, b, 1 /* |b| is affine */, ctx);
+}
int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
BN_CTX *ctx) {
diff --git a/src/crypto/fipsmodule/ec/internal.h b/src/crypto/fipsmodule/ec/internal.h
index 742e94e1..c5d72913 100644
--- a/src/crypto/fipsmodule/ec/internal.h
+++ b/src/crypto/fipsmodule/ec/internal.h
@@ -193,6 +193,11 @@ int ec_bignum_to_scalar_unchecked(const EC_GROUP *group, EC_SCALAR *out,
int ec_random_nonzero_scalar(const EC_GROUP *group, EC_SCALAR *out,
const uint8_t additional_data[32]);
+// ec_point_add_mixed behaves like |EC_POINT_add|, but |&b->Z| must be zero or
+// one.
+int ec_point_add_mixed(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
+ const EC_POINT *b, BN_CTX *ctx);
+
// ec_point_mul_scalar sets |r| to generator * |g_scalar| + |p| *
// |p_scalar|. Unlike other functions which take |EC_SCALAR|, |g_scalar| and
// |p_scalar| need not be fully reduced. They need only contain as many bits as
@@ -238,7 +243,7 @@ int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *,
const BIGNUM *x, const BIGNUM *y,
BN_CTX *);
int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
- const EC_POINT *b, BN_CTX *);
+ const EC_POINT *b, int mixed, BN_CTX *);
int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a,
BN_CTX *);
int ec_GFp_simple_invert(const EC_GROUP *, EC_POINT *, BN_CTX *);
diff --git a/src/crypto/fipsmodule/ec/simple.c b/src/crypto/fipsmodule/ec/simple.c
index e87409c6..4fb394c5 100644
--- a/src/crypto/fipsmodule/ec/simple.c
+++ b/src/crypto/fipsmodule/ec/simple.c
@@ -303,7 +303,11 @@ err:
}
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
- const EC_POINT *b, BN_CTX *ctx) {
+ const EC_POINT *b, int mixed, BN_CTX *ctx) {
+ if (mixed) {
+ assert(BN_is_zero(&b->Z) || BN_cmp(&b->Z, &group->one) == 0);
+ }
+
int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *,
BN_CTX *);
int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
@@ -350,9 +354,7 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
// ('r' might be one of 'a' or 'b'.)
// n1, n2
- int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0;
-
- if (b_Z_is_one) {
+ if (mixed) {
if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) {
goto end;
}
@@ -373,26 +375,17 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
// n3, n4
- int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0;
- if (a_Z_is_one) {
- if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) {
- goto end;
- }
- // n3 = X_b
- // n4 = Y_b
- } else {
- if (!field_sqr(group, n0, &a->Z, ctx) ||
- !field_mul(group, n3, &b->X, n0, ctx)) {
- goto end;
- }
- // n3 = X_b * Z_a^2
+ if (!field_sqr(group, n0, &a->Z, ctx) ||
+ !field_mul(group, n3, &b->X, n0, ctx)) {
+ goto end;
+ }
+ // n3 = X_b * Z_a^2
- if (!field_mul(group, n0, n0, &a->Z, ctx) ||
- !field_mul(group, n4, &b->Y, n0, ctx)) {
- goto end;
- }
- // n4 = Y_b * Z_a^3
+ if (!field_mul(group, n0, n0, &a->Z, ctx) ||
+ !field_mul(group, n4, &b->Y, n0, ctx)) {
+ goto end;
}
+ // n4 = Y_b * Z_a^3
// n5, n6
if (!bn_mod_sub_consttime(n5, n1, n3, p, ctx) ||
@@ -426,25 +419,15 @@ int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
// 'n8' = n2 + n4
// Z_r
- if (a_Z_is_one && b_Z_is_one) {
- if (!BN_copy(&r->Z, n5)) {
- goto end;
- }
- } else {
- if (a_Z_is_one) {
- if (!BN_copy(n0, &b->Z)) {
- goto end;
- }
- } else if (b_Z_is_one) {
- if (!BN_copy(n0, &a->Z)) {
- goto end;
- }
- } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) {
- goto end;
- }
- if (!field_mul(group, &r->Z, n0, n5, ctx)) {
+ if (mixed) {
+ if (!BN_copy(n0, &a->Z)) {
goto end;
}
+ } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) {
+ goto end;
+ }
+ if (!field_mul(group, &r->Z, n0, n5, ctx)) {
+ goto end;
}
// Z_r = Z_a * Z_b * n5
@@ -534,15 +517,7 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
// ('r' might the same as 'a'.)
// n1
- if (BN_cmp(&a->Z, &group->one) == 0) {
- if (!field_sqr(group, n0, &a->X, ctx) ||
- !bn_mod_lshift1_consttime(n1, n0, p, ctx) ||
- !bn_mod_add_consttime(n0, n0, n1, p, ctx) ||
- !bn_mod_add_consttime(n1, n0, &group->a, p, ctx)) {
- goto err;
- }
- // n1 = 3 * X_a^2 + a_curve
- } else if (group->a_is_minus3) {
+ if (group->a_is_minus3) {
if (!field_sqr(group, n1, &a->Z, ctx) ||
!bn_mod_add_consttime(n0, &a->X, n1, p, ctx) ||
!bn_mod_sub_consttime(n2, &a->X, n1, p, ctx) ||
@@ -567,14 +542,8 @@ int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
}
// Z_r
- if (BN_cmp(&a->Z, &group->one) == 0) {
- if (!BN_copy(n0, &a->Y)) {
- goto err;
- }
- } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) {
- goto err;
- }
- if (!bn_mod_lshift1_consttime(&r->Z, n0, p, ctx)) {
+ if (!field_mul(group, n0, &a->Y, &a->Z, ctx) ||
+ !bn_mod_lshift1_consttime(&r->Z, n0, p, ctx)) {
goto err;
}
// Z_r = 2 * Y_a * Z_a
diff --git a/src/crypto/fipsmodule/ec/wnaf.c b/src/crypto/fipsmodule/ec/wnaf.c
index 7bc0bc7b..49fc8bca 100644
--- a/src/crypto/fipsmodule/ec/wnaf.c
+++ b/src/crypto/fipsmodule/ec/wnaf.c
@@ -291,7 +291,9 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
tmp = EC_POINT_new(group);
if (tmp == NULL ||
- // |window_bits_for_scalar_size| assumes we do this step.
+ // Convert the points to affine coordinates. This allows us to use the
+ // slightly faster |ec_point_add_mixed|. The conversion itself is not
+ // cheap, but it is worthwhile when there are two points.
!EC_POINTs_make_affine(group, total_precomp, precomp_storage, ctx)) {
goto err;
}
@@ -302,35 +304,31 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar,
goto err;
}
- if (g_scalar != NULL) {
- if (g_wNAF[k] != 0) {
- if (!lookup_precomp(group, tmp, g_precomp, g_wNAF[k], ctx)) {
- goto err;
- }
- if (r_is_at_infinity) {
- if (!EC_POINT_copy(r, tmp)) {
- goto err;
- }
- r_is_at_infinity = 0;
- } else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
+ if (g_scalar != NULL && g_wNAF[k] != 0) {
+ if (!lookup_precomp(group, tmp, g_precomp, g_wNAF[k], ctx)) {
+ goto err;
+ }
+ if (r_is_at_infinity) {
+ if (!EC_POINT_copy(r, tmp)) {
goto err;
}
+ r_is_at_infinity = 0;
+ } else if (!ec_point_add_mixed(group, r, r, tmp, ctx)) {
+ goto err;
}
}
- if (p_scalar != NULL) {
- if (p_wNAF[k] != 0) {
- if (!lookup_precomp(group, tmp, p_precomp, p_wNAF[k], ctx)) {
- goto err;
- }
- if (r_is_at_infinity) {
- if (!EC_POINT_copy(r, tmp)) {
- goto err;
- }
- r_is_at_infinity = 0;
- } else if (!EC_POINT_add(group, r, r, tmp, ctx)) {
+ if (p_scalar != NULL && p_wNAF[k] != 0) {
+ if (!lookup_precomp(group, tmp, p_precomp, p_wNAF[k], ctx)) {
+ goto err;
+ }
+ if (r_is_at_infinity) {
+ if (!EC_POINT_copy(r, tmp)) {
goto err;
}
+ r_is_at_infinity = 0;
+ } else if (!ec_point_add_mixed(group, r, r, tmp, ctx)) {
+ goto err;
}
}
}
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 8e7d5f52..d22d396c 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -535,6 +535,7 @@ OPENSSL_EXPORT int SSL_get_error(const SSL *ssl, int ret_code);
#define SSL_ERROR_WANT_CERTIFICATE_VERIFY 16
#define SSL_ERROR_HANDOFF 17
+#define SSL_ERROR_HANDBACK 18
// SSL_set_mtu sets the |ssl|'s MTU in DTLS to |mtu|. It returns one on success
// and zero on failure.
@@ -596,6 +597,7 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl);
#define DTLS1_2_VERSION 0xfefd
#define TLS1_3_DRAFT23_VERSION 0x7f17
+#define TLS1_3_DRAFT28_VERSION 0x7f1c
// 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
@@ -3309,6 +3311,7 @@ OPENSSL_EXPORT int SSL_total_renegotiations(const SSL *ssl);
enum tls13_variant_t {
tls13_default = 0,
+ tls13_draft28 = 1,
};
// SSL_CTX_set_tls13_variant sets which variant of TLS 1.3 we negotiate. On the
@@ -3926,6 +3929,7 @@ OPENSSL_EXPORT void SSL_CTX_set_client_cert_cb(
#define SSL_EARLY_DATA_REJECTED 11
#define SSL_CERTIFICATE_VERIFY 12
#define SSL_HANDOFF 13
+#define SSL_HANDBACK 14
// SSL_want returns one of the above values to determine what the most recent
// operation on |ssl| was blocked on. Use |SSL_get_error| instead.
@@ -4478,10 +4482,10 @@ OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
// state of the connection.
//
// Elsewhere, a fresh |SSL| can be used with |SSL_apply_handoff| to continue
-// the connection. The connection from the client is fed into this |SSL| until
-// the handshake completes normally. At this point (and only at this point),
-// |SSL_serialize_handback| can be called to serialize the result of the
-// handshake.
+// the connection. The connection from the client is fed into this |SSL|, and
+// the handshake resumed. When the handshake stops again and |SSL_get_error|
+// indicates |SSL_ERROR_HANDBACK|, |SSL_serialize_handback| should be called to
+// serialize the state of the handshake again.
//
// Back at the first location, a fresh |SSL| can be used with
// |SSL_apply_handback|. Then the client's connection can be processed mostly
@@ -4489,7 +4493,7 @@ OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
//
// Lastly, when a connection is in the handoff state, whether or not
// |SSL_serialize_handoff| is called, |SSL_decline_handoff| will move it back
-// into a normal state where the connection can procede without impact.
+// into a normal state where the connection can proceed without impact.
//
// WARNING: Currently only works with TLS 1.0–1.2.
// WARNING: The serialisation formats are not yet stable: version skew may be
diff --git a/src/ssl/handoff.cc b/src/ssl/handoff.cc
index b19d4432..dd73c83e 100644
--- a/src/ssl/handoff.cc
+++ b/src/ssl/handoff.cc
@@ -93,17 +93,17 @@ bool SSL_apply_handoff(SSL *ssl, Span<const uint8_t> handoff) {
if (CBS_len(&transcript) != 0) {
s3->hs->transcript.Update(transcript);
s3->is_v2_hello = true;
- ssl_do_msg_callback(ssl, 0 /* read */, 0 /* V2ClientHello */, transcript);
}
+ ssl->handback = true;
return true;
}
bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
if (!ssl->server ||
- !ssl->s3->initial_handshake_complete ||
- ssl->method->is_dtls ||
- ssl->version < TLS1_VERSION) {
+ (ssl->s3->hs->state != state12_finish_server_handshake &&
+ ssl->s3->hs->state != state12_read_client_certificate) ||
+ ssl->method->is_dtls || ssl->version < TLS1_VERSION) {
return false;
}
@@ -115,14 +115,22 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
size_t iv_len = 0;
const uint8_t *read_iv = nullptr, *write_iv = nullptr;
- if (ssl->version == TLS1_VERSION &&
- SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
- (!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
- !s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
- return false;
+ Span<const uint8_t> transcript;
+ if (ssl->s3->hs->state == state12_finish_server_handshake) {
+ if (ssl->version == TLS1_VERSION &&
+ SSL_CIPHER_is_block_cipher(s3->aead_read_ctx->cipher()) &&
+ (!s3->aead_read_ctx->GetIV(&read_iv, &iv_len) ||
+ !s3->aead_write_ctx->GetIV(&write_iv, &iv_len))) {
+ return false;
+ }
+ } else {
+ transcript = s3->hs->transcript.buffer();
}
- CBB seq;
+ // TODO(mab): make sure everything is serialized.
+ CBB seq, key_share;
+ SSL_SESSION *session =
+ s3->session_reused ? ssl->session : s3->hs->new_session.get();
if (!CBB_add_asn1(out, &seq, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&seq, kHandbackVersion) ||
!CBB_add_asn1_uint64(&seq, ssl->version) ||
@@ -142,7 +150,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_bool(&seq, s3->session_reused) ||
!CBB_add_asn1_bool(&seq, s3->send_connection_binding) ||
!CBB_add_asn1_bool(&seq, s3->tlsext_channel_id_valid) ||
- !ssl_session_serialize(s3->established_session.get(), &seq) ||
+ !ssl_session_serialize(session, &seq) ||
!CBB_add_asn1_octet_string(&seq, s3->next_proto_negotiated.data(),
s3->next_proto_negotiated.size()) ||
!CBB_add_asn1_octet_string(&seq, s3->alpn_selected.data(),
@@ -158,11 +166,22 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) {
!CBB_add_asn1_bool(&seq, ssl->quiet_shutdown) ||
!CBB_add_asn1_bool(&seq, ssl->tlsext_channel_id_enabled) ||
!CBB_add_asn1_bool(&seq, ssl->retain_only_sha256_of_client_certs) ||
- !CBB_flush(out)) {
+ !CBB_add_asn1_bool(&seq, ssl->token_binding_negotiated) ||
+ !CBB_add_asn1_uint64(&seq, ssl->negotiated_token_binding_param) ||
+ !CBB_add_asn1_bool(&seq, s3->hs->next_proto_neg_seen) ||
+ !CBB_add_asn1_bool(&seq, s3->hs->cert_request) ||
+ !CBB_add_asn1_bool(&seq, s3->hs->extended_master_secret) ||
+ !CBB_add_asn1_bool(&seq, s3->hs->ticket_expected) ||
+ !CBB_add_asn1_uint64(&seq, SSL_CIPHER_get_id(s3->hs->new_cipher)) ||
+ !CBB_add_asn1_octet_string(&seq, transcript.data(), transcript.size()) ||
+ !CBB_add_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
return false;
}
-
- return true;
+ if (ssl->s3->hs->state == state12_read_client_certificate &&
+ !s3->hs->key_share->Serialize(&key_share)) {
+ return false;
+ }
+ return CBB_flush(out);
}
bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
@@ -173,11 +192,16 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
SSL3_STATE *const s3 = ssl->s3;
uint64_t handback_version, version, conf_max_version, conf_min_version,
- max_send_fragment, options, mode, max_cert_list;
+ max_send_fragment, options, mode, max_cert_list,
+ negotiated_token_binding_param, cipher;
+
CBS seq, read_seq, write_seq, server_rand, client_rand, read_iv, write_iv,
- next_proto, alpn, hostname, channel_id;
- int session_reused, send_connection_binding, channel_id_valid,
- quiet_shutdown, channel_id_enabled, retain_only_sha256;
+ next_proto, alpn, hostname, channel_id, transcript, key_share;
+ int session_reused, send_connection_binding, channel_id_valid, quiet_shutdown,
+ channel_id_enabled, retain_only_sha256, cert_request,
+ extended_master_secret, ticket_expected, token_binding_negotiated,
+ next_proto_neg_seen;
+ SSL_SESSION *session = nullptr;
CBS handback_cbs(handback);
if (!CBS_get_asn1(&handback_cbs, &seq, CBS_ASN1_SEQUENCE) ||
@@ -210,11 +234,19 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
return false;
}
- s3->established_session =
- SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
+ s3->hs = ssl_handshake_new(ssl);
+ if (session_reused) {
+ ssl->session =
+ SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool)
+ .release();
+ session = ssl->session;
+ } else {
+ s3->hs->new_session =
+ SSL_SESSION_parse(&seq, ssl->ctx->x509_method, ssl->ctx->pool);
+ session = s3->hs->new_session.get();
+ }
- if (!s3->established_session ||
- !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
+ if (!session || !CBS_get_asn1(&seq, &next_proto, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &alpn, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &hostname, CBS_ASN1_OCTETSTRING) ||
!CBS_get_asn1(&seq, &channel_id, CBS_ASN1_OCTETSTRING) ||
@@ -226,7 +258,22 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
!CBS_get_asn1_uint64(&seq, &max_cert_list) ||
!CBS_get_asn1_bool(&seq, &quiet_shutdown) ||
!CBS_get_asn1_bool(&seq, &channel_id_enabled) ||
- !CBS_get_asn1_bool(&seq, &retain_only_sha256)) {
+ !CBS_get_asn1_bool(&seq, &retain_only_sha256) ||
+ !CBS_get_asn1_bool(&seq, &token_binding_negotiated) ||
+ !CBS_get_asn1_uint64(&seq, &negotiated_token_binding_param) ||
+ !CBS_get_asn1_bool(&seq, &next_proto_neg_seen) ||
+ !CBS_get_asn1_bool(&seq, &cert_request) ||
+ !CBS_get_asn1_bool(&seq, &extended_master_secret) ||
+ !CBS_get_asn1_bool(&seq, &ticket_expected) ||
+ !CBS_get_asn1_uint64(&seq, &cipher)) {
+ return false;
+ }
+ if ((s3->hs->new_cipher =
+ SSL_get_cipher_by_value(static_cast<uint16_t>(cipher))) == nullptr) {
+ return false;
+ }
+ if (!CBS_get_asn1(&seq, &transcript, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1(&seq, &key_share, CBS_ASN1_SEQUENCE)) {
return false;
}
@@ -240,9 +287,9 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
ssl->mode = mode;
ssl->max_cert_list = max_cert_list;
- s3->hs.reset();
s3->have_version = true;
- s3->initial_handshake_complete = true;
+ s3->hs->state = CBS_len(&transcript) == 0 ? state12_finish_server_handshake
+ : state12_read_client_certificate;
s3->session_reused = session_reused;
s3->send_connection_binding = send_connection_binding;
s3->tlsext_channel_id_valid = channel_id_valid;
@@ -263,23 +310,44 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) {
ssl->quiet_shutdown = quiet_shutdown;
ssl->tlsext_channel_id_enabled = channel_id_enabled;
ssl->retain_only_sha256_of_client_certs = retain_only_sha256;
+ ssl->token_binding_negotiated = token_binding_negotiated;
+ ssl->negotiated_token_binding_param =
+ static_cast<uint8_t>(negotiated_token_binding_param);
+ s3->hs->next_proto_neg_seen = next_proto_neg_seen;
+ s3->hs->wait = ssl_hs_flush;
+ s3->hs->extended_master_secret = extended_master_secret;
+ s3->hs->ticket_expected = ticket_expected;
+ s3->aead_write_ctx->SetVersionIfNullCipher(ssl->version);
+ s3->hs->cert_request = cert_request;
+
+ if (s3->hs->state == state12_finish_server_handshake) {
+ Array<uint8_t> key_block;
+ if (!tls1_configure_aead(ssl, evp_aead_open, &key_block, session->cipher,
+ read_iv) ||
+ !tls1_configure_aead(ssl, evp_aead_seal, &key_block, session->cipher,
+ write_iv)) {
+ return false;
+ }
- Array<uint8_t> key_block;
- if (!tls1_configure_aead(ssl, evp_aead_open, &key_block,
- s3->established_session->cipher, read_iv) ||
- !tls1_configure_aead(ssl, evp_aead_seal, &key_block,
- s3->established_session->cipher, write_iv)) {
- return false;
- }
-
- if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
- sizeof(s3->read_sequence)) ||
- !CBS_copy_bytes(&write_seq, s3->write_sequence,
- sizeof(s3->write_sequence))) {
- return false;
+ if (!CBS_copy_bytes(&read_seq, s3->read_sequence,
+ sizeof(s3->read_sequence)) ||
+ !CBS_copy_bytes(&write_seq, s3->write_sequence,
+ sizeof(s3->write_sequence))) {
+ return false;
+ }
+ } else {
+ if (!s3->hs->transcript.Init() ||
+ !s3->hs->transcript.InitHash(ssl_protocol_version(ssl),
+ s3->hs->new_cipher) ||
+ !s3->hs->transcript.Update(transcript)) {
+ return false;
+ }
+ if ((s3->hs->key_share = SSLKeyShare::Create(&key_share)) == nullptr) {
+ return false;
+ }
}
- return true;
+ return CBS_len(&seq) == 0;
}
} // namespace bssl
diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc
index 64324245..00a2cc5d 100644
--- a/src/ssl/handshake.cc
+++ b/src/ssl/handshake.cc
@@ -565,6 +565,11 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) {
hs->wait = ssl_hs_ok;
return -1;
+ case ssl_hs_handback:
+ ssl->s3->rwstate = SSL_HANDBACK;
+ hs->wait = ssl_hs_handback;
+ return -1;
+
case ssl_hs_x509_lookup:
ssl->s3->rwstate = SSL_X509_LOOKUP;
hs->wait = ssl_hs_ok;
diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc
index fa8a2410..5f2f41fd 100644
--- a/src/ssl/handshake_server.cc
+++ b/src/ssl/handshake_server.cc
@@ -172,30 +172,6 @@
namespace bssl {
-enum ssl_server_hs_state_t {
- state_start_accept = 0,
- state_read_client_hello,
- state_select_certificate,
- state_tls13,
- state_select_parameters,
- state_send_server_hello,
- state_send_server_certificate,
- state_send_server_key_exchange,
- state_send_server_hello_done,
- state_read_client_certificate,
- state_verify_client_certificate,
- state_read_client_key_exchange,
- state_read_client_certificate_verify,
- state_read_change_cipher_spec,
- state_process_change_cipher_spec,
- state_read_next_proto,
- state_read_channel_id,
- state_read_client_finished,
- state_send_server_finished,
- state_finish_server_handshake,
- state_done,
-};
-
int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello,
uint16_t id) {
CBS cipher_suites;
@@ -425,7 +401,7 @@ static const SSL_CIPHER *ssl3_choose_cipher(
static enum ssl_hs_wait_t do_start_accept(SSL_HANDSHAKE *hs) {
ssl_do_info_callback(hs->ssl, SSL_CB_HANDSHAKE_START, 1);
- hs->state = state_read_client_hello;
+ hs->state = state12_read_client_hello;
return ssl_hs_ok;
}
@@ -505,7 +481,7 @@ static enum ssl_hs_wait_t do_read_client_hello(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->state = state_select_certificate;
+ hs->state = state12_select_certificate;
return ssl_hs_ok;
}
@@ -536,7 +512,7 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
if (ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
// Jump to the TLS 1.3 state machine.
- hs->state = state_tls13;
+ hs->state = state12_tls13;
return ssl_hs_ok;
}
@@ -555,14 +531,14 @@ static enum ssl_hs_wait_t do_select_certificate(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->state = state_select_parameters;
+ hs->state = state12_select_parameters;
return ssl_hs_ok;
}
static enum ssl_hs_wait_t do_tls13(SSL_HANDSHAKE *hs) {
enum ssl_hs_wait_t wait = tls13_server_handshake(hs);
if (wait == ssl_hs_ok) {
- hs->state = state_finish_server_handshake;
+ hs->state = state12_finish_server_handshake;
return ssl_hs_ok;
}
@@ -672,14 +648,15 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- // Release the handshake buffer if client authentication isn't required.
- if (!hs->cert_request) {
+ // Handback includes the whole handshake transcript, so we cannot free the
+ // transcript buffer in the handback case.
+ if (!hs->cert_request && !hs->ssl->handback) {
hs->transcript.FreeBuffer();
}
ssl->method->next_message(ssl);
- hs->state = state_send_server_hello;
+ hs->state = state12_send_server_hello;
return ssl_hs_ok;
}
@@ -744,9 +721,9 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
}
if (ssl->session != NULL) {
- hs->state = state_send_server_finished;
+ hs->state = state12_send_server_finished;
} else {
- hs->state = state_send_server_certificate;
+ hs->state = state12_send_server_certificate;
}
return ssl_hs_ok;
}
@@ -835,7 +812,7 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) {
}
}
- hs->state = state_send_server_key_exchange;
+ hs->state = state12_send_server_key_exchange;
return ssl_hs_ok;
}
@@ -843,7 +820,7 @@ static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (hs->server_params.size() == 0) {
- hs->state = state_send_server_hello_done;
+ hs->state = state12_send_server_hello_done;
return ssl_hs_ok;
}
@@ -907,7 +884,7 @@ static enum ssl_hs_wait_t do_send_server_key_exchange(SSL_HANDSHAKE *hs) {
hs->server_params.Reset();
- hs->state = state_send_server_hello_done;
+ hs->state = state12_send_server_hello_done;
return ssl_hs_ok;
}
@@ -942,15 +919,18 @@ static enum ssl_hs_wait_t do_send_server_hello_done(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->state = state_read_client_certificate;
+ hs->state = state12_read_client_certificate;
return ssl_hs_flush;
}
static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (ssl->handback && hs->new_cipher->algorithm_mkey == SSL_kECDHE) {
+ return ssl_hs_handback;
+ }
if (!hs->cert_request) {
- hs->state = state_verify_client_certificate;
+ hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}
@@ -973,7 +953,7 @@ static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
// OpenSSL returns X509_V_OK when no certificates are received. This is
// classed by them as a bug, but it's assumed by at least NGINX.
hs->new_session->verify_result = X509_V_OK;
- hs->state = state_verify_client_certificate;
+ hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}
@@ -1035,7 +1015,7 @@ static enum ssl_hs_wait_t do_read_client_certificate(SSL_HANDSHAKE *hs) {
}
ssl->method->next_message(ssl);
- hs->state = state_verify_client_certificate;
+ hs->state = state12_verify_client_certificate;
return ssl_hs_ok;
}
@@ -1051,7 +1031,7 @@ static enum ssl_hs_wait_t do_verify_client_certificate(SSL_HANDSHAKE *hs) {
}
}
- hs->state = state_read_client_key_exchange;
+ hs->state = state12_read_client_key_exchange;
return ssl_hs_ok;
}
@@ -1262,7 +1242,7 @@ static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) {
hs->new_session->extended_master_secret = hs->extended_master_secret;
ssl->method->next_message(ssl);
- hs->state = state_read_client_certificate_verify;
+ hs->state = state12_read_client_certificate_verify;
return ssl_hs_ok;
}
@@ -1273,7 +1253,7 @@ static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
// CertificateVerify is required if and only if there's a client certificate.
if (!hs->peer_pubkey) {
hs->transcript.FreeBuffer();
- hs->state = state_read_change_cipher_spec;
+ hs->state = state12_read_change_cipher_spec;
return ssl_hs_ok;
}
@@ -1358,12 +1338,12 @@ static enum ssl_hs_wait_t do_read_client_certificate_verify(SSL_HANDSHAKE *hs) {
}
ssl->method->next_message(ssl);
- hs->state = state_read_change_cipher_spec;
+ hs->state = state12_read_change_cipher_spec;
return ssl_hs_ok;
}
static enum ssl_hs_wait_t do_read_change_cipher_spec(SSL_HANDSHAKE *hs) {
- hs->state = state_process_change_cipher_spec;
+ hs->state = state12_process_change_cipher_spec;
return ssl_hs_read_change_cipher_spec;
}
@@ -1372,7 +1352,7 @@ static enum ssl_hs_wait_t do_process_change_cipher_spec(SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- hs->state = state_read_next_proto;
+ hs->state = state12_read_next_proto;
return ssl_hs_ok;
}
@@ -1380,7 +1360,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (!hs->next_proto_neg_seen) {
- hs->state = state_read_channel_id;
+ hs->state = state12_read_channel_id;
return ssl_hs_ok;
}
@@ -1408,7 +1388,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) {
}
ssl->method->next_message(ssl);
- hs->state = state_read_channel_id;
+ hs->state = state12_read_channel_id;
return ssl_hs_ok;
}
@@ -1416,7 +1396,7 @@ static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (!ssl->s3->tlsext_channel_id_valid) {
- hs->state = state_read_client_finished;
+ hs->state = state12_read_client_finished;
return ssl_hs_ok;
}
@@ -1432,7 +1412,7 @@ static enum ssl_hs_wait_t do_read_channel_id(SSL_HANDSHAKE *hs) {
}
ssl->method->next_message(ssl);
- hs->state = state_read_client_finished;
+ hs->state = state12_read_client_finished;
return ssl_hs_ok;
}
@@ -1444,9 +1424,9 @@ static enum ssl_hs_wait_t do_read_client_finished(SSL_HANDSHAKE *hs) {
}
if (ssl->session != NULL) {
- hs->state = state_finish_server_handshake;
+ hs->state = state12_finish_server_handshake;
} else {
- hs->state = state_send_server_finished;
+ hs->state = state12_send_server_finished;
}
// If this is a full handshake with ChannelID then record the handshake
@@ -1501,9 +1481,9 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
}
if (ssl->session != NULL) {
- hs->state = state_read_change_cipher_spec;
+ hs->state = state12_read_change_cipher_spec;
} else {
- hs->state = state_finish_server_handshake;
+ hs->state = state12_finish_server_handshake;
}
return ssl_hs_flush;
}
@@ -1511,6 +1491,10 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ if (ssl->handback) {
+ return ssl_hs_handback;
+ }
+
ssl->method->on_handshake_complete(ssl);
// If we aren't retaining peer certificates then we can discard it now.
@@ -1532,77 +1516,77 @@ static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) {
ssl->s3->initial_handshake_complete = true;
ssl_update_cache(hs, SSL_SESS_CACHE_SERVER);
- hs->state = state_done;
+ hs->state = state12_done;
return ssl_hs_ok;
}
enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
- while (hs->state != state_done) {
+ while (hs->state != state12_done) {
enum ssl_hs_wait_t ret = ssl_hs_error;
- enum ssl_server_hs_state_t state =
- static_cast<enum ssl_server_hs_state_t>(hs->state);
+ enum tls12_server_hs_state_t state =
+ static_cast<enum tls12_server_hs_state_t>(hs->state);
switch (state) {
- case state_start_accept:
+ case state12_start_accept:
ret = do_start_accept(hs);
break;
- case state_read_client_hello:
+ case state12_read_client_hello:
ret = do_read_client_hello(hs);
break;
- case state_select_certificate:
+ case state12_select_certificate:
ret = do_select_certificate(hs);
break;
- case state_tls13:
+ case state12_tls13:
ret = do_tls13(hs);
break;
- case state_select_parameters:
+ case state12_select_parameters:
ret = do_select_parameters(hs);
break;
- case state_send_server_hello:
+ case state12_send_server_hello:
ret = do_send_server_hello(hs);
break;
- case state_send_server_certificate:
+ case state12_send_server_certificate:
ret = do_send_server_certificate(hs);
break;
- case state_send_server_key_exchange:
+ case state12_send_server_key_exchange:
ret = do_send_server_key_exchange(hs);
break;
- case state_send_server_hello_done:
+ case state12_send_server_hello_done:
ret = do_send_server_hello_done(hs);
break;
- case state_read_client_certificate:
+ case state12_read_client_certificate:
ret = do_read_client_certificate(hs);
break;
- case state_verify_client_certificate:
+ case state12_verify_client_certificate:
ret = do_verify_client_certificate(hs);
break;
- case state_read_client_key_exchange:
+ case state12_read_client_key_exchange:
ret = do_read_client_key_exchange(hs);
break;
- case state_read_client_certificate_verify:
+ case state12_read_client_certificate_verify:
ret = do_read_client_certificate_verify(hs);
break;
- case state_read_change_cipher_spec:
+ case state12_read_change_cipher_spec:
ret = do_read_change_cipher_spec(hs);
break;
- case state_process_change_cipher_spec:
+ case state12_process_change_cipher_spec:
ret = do_process_change_cipher_spec(hs);
break;
- case state_read_next_proto:
+ case state12_read_next_proto:
ret = do_read_next_proto(hs);
break;
- case state_read_channel_id:
+ case state12_read_channel_id:
ret = do_read_channel_id(hs);
break;
- case state_read_client_finished:
+ case state12_read_client_finished:
ret = do_read_client_finished(hs);
break;
- case state_send_server_finished:
+ case state12_send_server_finished:
ret = do_send_server_finished(hs);
break;
- case state_finish_server_handshake:
+ case state12_finish_server_handshake:
ret = do_finish_server_handshake(hs);
break;
- case state_done:
+ case state12_done:
ret = ssl_hs_ok;
break;
}
@@ -1621,50 +1605,50 @@ enum ssl_hs_wait_t ssl_server_handshake(SSL_HANDSHAKE *hs) {
}
const char *ssl_server_handshake_state(SSL_HANDSHAKE *hs) {
- enum ssl_server_hs_state_t state =
- static_cast<enum ssl_server_hs_state_t>(hs->state);
+ enum tls12_server_hs_state_t state =
+ static_cast<enum tls12_server_hs_state_t>(hs->state);
switch (state) {
- case state_start_accept:
+ case state12_start_accept:
return "TLS server start_accept";
- case state_read_client_hello:
+ case state12_read_client_hello:
return "TLS server read_client_hello";
- case state_select_certificate:
+ case state12_select_certificate:
return "TLS server select_certificate";
- case state_tls13:
+ case state12_tls13:
return tls13_server_handshake_state(hs);
- case state_select_parameters:
+ case state12_select_parameters:
return "TLS server select_parameters";
- case state_send_server_hello:
+ case state12_send_server_hello:
return "TLS server send_server_hello";
- case state_send_server_certificate:
+ case state12_send_server_certificate:
return "TLS server send_server_certificate";
- case state_send_server_key_exchange:
+ case state12_send_server_key_exchange:
return "TLS server send_server_key_exchange";
- case state_send_server_hello_done:
+ case state12_send_server_hello_done:
return "TLS server send_server_hello_done";
- case state_read_client_certificate:
+ case state12_read_client_certificate:
return "TLS server read_client_certificate";
- case state_verify_client_certificate:
+ case state12_verify_client_certificate:
return "TLS server verify_client_certificate";
- case state_read_client_key_exchange:
+ case state12_read_client_key_exchange:
return "TLS server read_client_key_exchange";
- case state_read_client_certificate_verify:
+ case state12_read_client_certificate_verify:
return "TLS server read_client_certificate_verify";
- case state_read_change_cipher_spec:
+ case state12_read_change_cipher_spec:
return "TLS server read_change_cipher_spec";
- case state_process_change_cipher_spec:
+ case state12_process_change_cipher_spec:
return "TLS server process_change_cipher_spec";
- case state_read_next_proto:
+ case state12_read_next_proto:
return "TLS server read_next_proto";
- case state_read_channel_id:
+ case state12_read_channel_id:
return "TLS server read_channel_id";
- case state_read_client_finished:
+ case state12_read_client_finished:
return "TLS server read_client_finished";
- case state_send_server_finished:
+ case state12_send_server_finished:
return "TLS server send_server_finished";
- case state_finish_server_handshake:
+ case state12_finish_server_handshake:
return "TLS server finish_server_handshake";
- case state_done:
+ case state12_done:
return "TLS server done";
}
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index d13d5f2c..e884b636 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -392,6 +392,10 @@ bool ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
// call this function before the version is determined.
uint16_t ssl_protocol_version(const SSL *ssl);
+// ssl_is_draft28 returns whether the version corresponds to a draft28 TLS 1.3
+// variant.
+bool ssl_is_draft28(uint16_t version);
+
// Cipher suites.
} // namespace bssl
@@ -694,7 +698,7 @@ class SSLAEADContext {
// number of bytes written.
size_t GetAdditionalData(uint8_t out[13], uint8_t type,
uint16_t record_version, const uint8_t seqnum[8],
- size_t plaintext_len);
+ size_t plaintext_len, size_t ciphertext_len);
const SSL_CIPHER *cipher_;
ScopedEVP_AEAD_CTX ctx_;
@@ -721,6 +725,9 @@ class SSLAEADContext {
bool omit_version_in_ad_ : 1;
// omit_ad_ is true if the AEAD's ad parameter should be omitted.
bool omit_ad_ : 1;
+ // tls13_ad_ is true if the AEAD's ad parameter should be based on the
+ // TLS 1.3 format.
+ bool tls13_ad_ : 1;
// xor_fixed_nonce_ is true if the fixed nonce should be XOR'd into the
// variable nonce rather than prepended.
bool xor_fixed_nonce_ : 1;
@@ -929,6 +936,10 @@ class SSLKeyShare {
// nullptr on error.
static UniquePtr<SSLKeyShare> Create(uint16_t group_id);
+ // Create deserializes an SSLKeyShare instance previously serialized by
+ // |Serialize|.
+ static UniquePtr<SSLKeyShare> Create(CBS *in);
+
// GroupID returns the group ID.
virtual uint16_t GroupID() const PURE_VIRTUAL;
@@ -952,6 +963,14 @@ class SSLKeyShare {
// send to the peer.
virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert,
Span<const uint8_t> peer_key) PURE_VIRTUAL;
+
+ // Serialize writes the state of the key exchange to |out|, returning true if
+ // successful and false otherwise.
+ virtual bool Serialize(CBB *out) { return false; }
+
+ // Deserialize initializes the state of the key exchange from |in|, returning
+ // true if successful and false otherwise. It is called by |Create|.
+ virtual bool Deserialize(CBS *in) { return false; }
};
// ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
@@ -1258,6 +1277,7 @@ enum ssl_hs_wait_t {
ssl_hs_flush,
ssl_hs_certificate_selection_pending,
ssl_hs_handoff,
+ ssl_hs_handback,
ssl_hs_x509_lookup,
ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
@@ -1280,6 +1300,30 @@ enum ssl_grease_index_t {
ssl_grease_last_index = ssl_grease_ticket_extension,
};
+enum tls12_server_hs_state_t {
+ state12_start_accept = 0,
+ state12_read_client_hello,
+ state12_select_certificate,
+ state12_tls13,
+ state12_select_parameters,
+ state12_send_server_hello,
+ state12_send_server_certificate,
+ state12_send_server_key_exchange,
+ state12_send_server_hello_done,
+ state12_read_client_certificate,
+ state12_verify_client_certificate,
+ state12_read_client_key_exchange,
+ state12_read_client_certificate_verify,
+ state12_read_change_cipher_spec,
+ state12_process_change_cipher_spec,
+ state12_read_next_proto,
+ state12_read_channel_id,
+ state12_read_client_finished,
+ state12_send_server_finished,
+ state12_finish_server_handshake,
+ state12_done,
+};
+
struct SSL_HANDSHAKE {
explicit SSL_HANDSHAKE(SSL *ssl);
~SSL_HANDSHAKE();
@@ -2676,6 +2720,11 @@ struct SSLConnection {
// element of the same name and may be cleared if the handoff is declined.
bool handoff:1;
+ // handback indicates that a server should pause the handshake after
+ // finishing operations that require private key material, in such a way that
+ // |SSL_get_error| returns |SSL_HANDBACK|. It is set by |SSL_apply_handoff|.
+ bool handback : 1;
+
// did_dummy_pq_padding is only valid for a client. In that context, it is
// true iff the client observed the server echoing a dummy PQ padding
// extension.
diff --git a/src/ssl/ssl_aead_ctx.cc b/src/ssl/ssl_aead_ctx.cc
index 247e889e..e6b3ee93 100644
--- a/src/ssl/ssl_aead_ctx.cc
+++ b/src/ssl/ssl_aead_ctx.cc
@@ -43,6 +43,7 @@ SSLAEADContext::SSLAEADContext(uint16_t version_arg, bool is_dtls_arg,
omit_length_in_ad_(false),
omit_version_in_ad_(false),
omit_ad_(false),
+ tls13_ad_(false),
xor_fixed_nonce_(false) {
OPENSSL_memset(fixed_nonce_, 0, sizeof(fixed_nonce_));
}
@@ -134,7 +135,11 @@ UniquePtr<SSLAEADContext> SSLAEADContext::Create(
aead_ctx->xor_fixed_nonce_ = true;
aead_ctx->variable_nonce_len_ = 8;
aead_ctx->variable_nonce_included_in_record_ = false;
- aead_ctx->omit_ad_ = true;
+ if (ssl_is_draft28(version)) {
+ aead_ctx->tls13_ad_ = true;
+ } else {
+ aead_ctx->omit_ad_ = true;
+ }
assert(fixed_iv.size() >= aead_ctx->variable_nonce_len_);
}
} else {
@@ -203,19 +208,26 @@ size_t SSLAEADContext::MaxOverhead() const {
size_t SSLAEADContext::GetAdditionalData(uint8_t out[13], uint8_t type,
uint16_t record_version,
const uint8_t seqnum[8],
- size_t plaintext_len) {
+ size_t plaintext_len,
+ size_t ciphertext_len) {
if (omit_ad_) {
return 0;
}
- OPENSSL_memcpy(out, seqnum, 8);
- size_t len = 8;
+ size_t len = 0;
+ if (!tls13_ad_) {
+ OPENSSL_memcpy(out, seqnum, 8);
+ len += 8;
+ }
out[len++] = type;
if (!omit_version_in_ad_) {
out[len++] = static_cast<uint8_t>((record_version >> 8));
out[len++] = static_cast<uint8_t>(record_version);
}
- if (!omit_length_in_ad_) {
+ if (tls13_ad_) {
+ out[len++] = static_cast<uint8_t>((ciphertext_len >> 8));
+ out[len++] = static_cast<uint8_t>(ciphertext_len);
+ } else if (!omit_length_in_ad_) {
out[len++] = static_cast<uint8_t>((plaintext_len >> 8));
out[len++] = static_cast<uint8_t>(plaintext_len);
}
@@ -244,8 +256,8 @@ bool SSLAEADContext::Open(Span<uint8_t> *out, uint8_t type,
plaintext_len = in.size() - overhead;
}
uint8_t ad[13];
- size_t ad_len =
- GetAdditionalData(ad, type, record_version, seqnum, plaintext_len);
+ size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum,
+ plaintext_len, in.size());
// Assemble the nonce.
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
@@ -320,7 +332,8 @@ bool SSLAEADContext::SealScatter(uint8_t *out_prefix, uint8_t *out,
}
uint8_t ad[13];
- size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len);
+ size_t ad_len = GetAdditionalData(ad, type, record_version, seqnum, in_len,
+ in_len + suffix_len);
// Assemble the nonce.
uint8_t nonce[EVP_AEAD_MAX_NONCE_LENGTH];
diff --git a/src/ssl/ssl_key_share.cc b/src/ssl/ssl_key_share.cc
index 4d76bb23..2a076c33 100644
--- a/src/ssl/ssl_key_share.cc
+++ b/src/ssl/ssl_key_share.cc
@@ -124,6 +124,32 @@ class ECKeyShare : public SSLKeyShare {
return true;
}
+ bool Serialize(CBB *out) override {
+ assert(private_key_);
+ CBB cbb;
+ UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid_));
+ // Padding is added to avoid leaking the length.
+ size_t len = BN_num_bytes(EC_GROUP_get0_order(group.get()));
+ if (!CBB_add_asn1_uint64(out, group_id_) ||
+ !CBB_add_asn1(out, &cbb, CBS_ASN1_OCTETSTRING) ||
+ !BN_bn2cbb_padded(&cbb, len, private_key_.get()) ||
+ !CBB_flush(out)) {
+ return false;
+ }
+ return true;
+ }
+
+ bool Deserialize(CBS *in) override {
+ assert(!private_key_);
+ CBS private_key;
+ if (!CBS_get_asn1(in, &private_key, CBS_ASN1_OCTETSTRING)) {
+ return false;
+ }
+ private_key_.reset(BN_bin2bn(CBS_data(&private_key),
+ CBS_len(&private_key), nullptr));
+ return private_key_ != nullptr;
+ }
+
private:
UniquePtr<BIGNUM> private_key_;
int nid_;
@@ -166,6 +192,21 @@ class X25519KeyShare : public SSLKeyShare {
return true;
}
+ bool Serialize(CBB *out) override {
+ return (CBB_add_asn1_uint64(out, GroupID()) &&
+ CBB_add_asn1_octet_string(out, private_key_, sizeof(private_key_)));
+ }
+
+ bool Deserialize(CBS *in) override {
+ CBS key;
+ if (!CBS_get_asn1(in, &key, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&key) != sizeof(private_key_) ||
+ !CBS_copy_bytes(&key, private_key_, sizeof(private_key_))) {
+ return false;
+ }
+ return true;
+ }
+
private:
uint8_t private_key_[32];
};
@@ -205,6 +246,19 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
}
}
+UniquePtr<SSLKeyShare> SSLKeyShare::Create(CBS *in) {
+ uint64_t group;
+ if (!CBS_get_asn1_uint64(in, &group)) {
+ return nullptr;
+ }
+ UniquePtr<SSLKeyShare> key_share = Create(static_cast<uint64_t>(group));
+ if (!key_share->Deserialize(in)) {
+ return nullptr;
+ }
+ return key_share;
+}
+
+
bool SSLKeyShare::Accept(CBB *out_public_key, Array<uint8_t> *out_secret,
uint8_t *out_alert, Span<const uint8_t> peer_key) {
*out_alert = SSL_AD_INTERNAL_ERROR;
diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc
index ef798311..63125042 100644
--- a/src/ssl/ssl_lib.cc
+++ b/src/ssl/ssl_lib.cc
@@ -1274,6 +1274,9 @@ int SSL_get_error(const SSL *ssl, int ret_code) {
case SSL_HANDOFF:
return SSL_ERROR_HANDOFF;
+ case SSL_HANDBACK:
+ return SSL_ERROR_HANDBACK;
+
case SSL_READING: {
BIO *bio = SSL_get_rbio(ssl);
if (BIO_should_read(bio)) {
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index 9f77f144..12f044c8 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -3949,9 +3949,13 @@ TEST(SSLTest, Handoff) {
int handshake_ret = SSL_do_handshake(handshaker.get());
int handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
- ASSERT_EQ(handshake_err, SSL_ERROR_WANT_READ);
+ ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);
- ASSERT_TRUE(CompleteHandshakes(client.get(), handshaker.get()));
+ // Double-check that additional calls to |SSL_do_handshake| continue
+ // to get |SSL_ERRROR_HANDBACK|.
+ handshake_ret = SSL_do_handshake(handshaker.get());
+ handshake_err = SSL_get_error(handshaker.get(), handshake_ret);
+ ASSERT_EQ(handshake_err, SSL_ERROR_HANDBACK);
ScopedCBB cbb_handback;
Array<uint8_t> handback;
@@ -3963,6 +3967,7 @@ TEST(SSLTest, Handoff) {
ASSERT_TRUE(SSL_apply_handback(server2.get(), handback));
MoveBIOs(server2.get(), handshaker.get());
+ ASSERT_TRUE(CompleteHandshakes(client.get(), server2.get()));
uint8_t byte = 42;
EXPECT_EQ(SSL_write(client.get(), &byte, 1), 1);
diff --git a/src/ssl/ssl_transcript.cc b/src/ssl/ssl_transcript.cc
index 2033dfd4..345f9d31 100644
--- a/src/ssl/ssl_transcript.cc
+++ b/src/ssl/ssl_transcript.cc
@@ -368,10 +368,6 @@ bool SSLTranscript::GetFinishedMAC(uint8_t *out, size_t *out_len,
return true;
}
- // At this point, the handshake should have released the handshake buffer on
- // its own.
- assert(!buffer_);
-
static const char kClientLabel[] = "client finished";
static const char kServerLabel[] = "server finished";
auto label = from_server
diff --git a/src/ssl/ssl_versions.cc b/src/ssl/ssl_versions.cc
index aeb41d3d..73ea26f0 100644
--- a/src/ssl/ssl_versions.cc
+++ b/src/ssl/ssl_versions.cc
@@ -35,6 +35,7 @@ bool ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
return true;
case TLS1_3_DRAFT23_VERSION:
+ case TLS1_3_DRAFT28_VERSION:
*out = TLS1_3_VERSION;
return true;
@@ -57,6 +58,7 @@ bool ssl_protocol_version_from_wire(uint16_t *out, uint16_t version) {
static const uint16_t kTLSVersions[] = {
TLS1_3_DRAFT23_VERSION,
+ TLS1_3_DRAFT28_VERSION,
TLS1_2_VERSION,
TLS1_1_VERSION,
TLS1_VERSION,
@@ -100,6 +102,7 @@ static bool method_supports_version(const SSL_PROTOCOL_METHOD *method,
static const char *ssl_version_to_string(uint16_t version) {
switch (version) {
case TLS1_3_DRAFT23_VERSION:
+ case TLS1_3_DRAFT28_VERSION:
return "TLSv1.3";
case TLS1_2_VERSION:
@@ -129,6 +132,7 @@ 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_DRAFT23_VERSION:
+ case TLS1_3_DRAFT28_VERSION:
return TLS1_3_VERSION;
default:
return version;
@@ -139,7 +143,8 @@ static uint16_t wire_version_to_api(uint16_t version) {
// 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_DRAFT23_VERSION) {
+ if (version == TLS1_3_DRAFT23_VERSION ||
+ version == TLS1_3_DRAFT28_VERSION) {
return false;
}
if (version == TLS1_3_VERSION) {
@@ -295,20 +300,15 @@ bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version) {
}
// This logic is part of the TLS 1.3 variants mechanism used in TLS 1.3
- // experimentation. Although we currently only have one variant, TLS 1.3 does
- // not a final stable deployment yet, so leave the logic in place for now.
+ // experimentation. TLS 1.3 variants must match the enabled |tls13_variant|.
if (protocol_version != TLS1_3_VERSION ||
+ (ssl->tls13_variant == tls13_draft28 &&
+ version == TLS1_3_DRAFT28_VERSION) ||
(ssl->tls13_variant == tls13_default &&
version == TLS1_3_DRAFT23_VERSION)) {
return true;
}
- // The server, when not configured at |tls13_default|, should additionally
- // enable all variants.
- if (ssl->server && ssl->tls13_variant != tls13_default) {
- return true;
- }
-
return false;
}
@@ -356,6 +356,10 @@ bool ssl_negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert,
return false;
}
+bool ssl_is_draft28(uint16_t version) {
+ return version == TLS1_3_DRAFT28_VERSION;
+}
+
} // namespace bssl
using namespace bssl;
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index ae26deda..107de52c 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -1937,40 +1937,34 @@ static bool WriteSettings(int i, const TestConfig *config,
return fwrite(settings, settings_len, 1, file.get()) == 1;
}
-static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
- bssl::UniquePtr<SSL> *ssl_uniqueptr,
- const TestConfig *config, bool is_resume, bool is_retry);
-
-// DoConnection tests an SSL connection against the peer. On success, it returns
-// true and sets |*out_session| to the negotiated SSL session. If the test is a
-// resumption attempt, |is_resume| is true and |session| is the session from the
-// previous exchange.
-static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
- SSL_CTX *ssl_ctx, const TestConfig *config,
- const TestConfig *retry_config, bool is_resume,
- SSL_SESSION *session) {
+static bssl::UniquePtr<SSL> NewSSL(SSL_CTX *ssl_ctx, const TestConfig *config,
+ SSL_SESSION *session, bool is_resume,
+ std::unique_ptr<TestState> test_state) {
bssl::UniquePtr<SSL> ssl(SSL_new(ssl_ctx));
if (!ssl) {
- return false;
+ return nullptr;
}
- if (!SetTestConfig(ssl.get(), config) ||
- !SetTestState(ssl.get(), std::unique_ptr<TestState>(new TestState))) {
- return false;
+ if (!SetTestConfig(ssl.get(), config)) {
+ return nullptr;
+ }
+ if (test_state != nullptr) {
+ if (!SetTestState(ssl.get(), std::move(test_state))) {
+ return nullptr;
+ }
+ GetTestState(ssl.get())->is_resume = is_resume;
}
-
- GetTestState(ssl.get())->is_resume = is_resume;
if (config->fallback_scsv &&
!SSL_set_mode(ssl.get(), SSL_MODE_SEND_FALLBACK_SCSV)) {
- return false;
+ return nullptr;
}
// Install the certificate synchronously if nothing else will handle it.
if (!config->use_early_callback &&
!config->use_old_client_cert_callback &&
!config->async &&
!InstallCertificate(ssl.get())) {
- return false;
+ return nullptr;
}
if (!config->use_old_client_cert_callback) {
SSL_set_cert_cb(ssl.get(), CertCallback, nullptr);
@@ -2027,7 +2021,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
// The async case will be supplied by |ChannelIdCallback|.
bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id);
if (!pkey || !SSL_set1_tls_channel_id(ssl.get(), pkey.get())) {
- return false;
+ return nullptr;
}
}
}
@@ -2039,13 +2033,13 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (!config->host_name.empty() &&
!SSL_set_tlsext_host_name(ssl.get(), config->host_name.c_str())) {
- return false;
+ return nullptr;
}
if (!config->advertise_alpn.empty() &&
SSL_set_alpn_protos(ssl.get(),
(const uint8_t *)config->advertise_alpn.data(),
config->advertise_alpn.size()) != 0) {
- return false;
+ return nullptr;
}
if (!config->psk.empty()) {
SSL_set_psk_client_callback(ssl.get(), PskClientCallback);
@@ -2053,11 +2047,11 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (!config->psk_identity.empty() &&
!SSL_use_psk_identity_hint(ssl.get(), config->psk_identity.c_str())) {
- return false;
+ return nullptr;
}
if (!config->srtp_profiles.empty() &&
!SSL_set_srtp_profiles(ssl.get(), config->srtp_profiles.c_str())) {
- return false;
+ return nullptr;
}
if (config->enable_ocsp_stapling) {
SSL_enable_ocsp_stapling(ssl.get());
@@ -2067,11 +2061,11 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (config->min_version != 0 &&
!SSL_set_min_proto_version(ssl.get(), (uint16_t)config->min_version)) {
- return false;
+ return nullptr;
}
if (config->max_version != 0 &&
!SSL_set_max_proto_version(ssl.get(), (uint16_t)config->max_version)) {
- return false;
+ return nullptr;
}
if (config->mtu != 0) {
SSL_set_options(ssl.get(), SSL_OP_NO_QUERY_MTU);
@@ -2095,7 +2089,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
if (config->p384_only) {
int nid = NID_secp384r1;
if (!SSL_set1_curves(ssl.get(), &nid, 1)) {
- return false;
+ return nullptr;
}
}
if (config->enable_all_curves) {
@@ -2105,7 +2099,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
OPENSSL_ARRAY_SIZE(kAllCurves))) {
- return false;
+ return nullptr;
}
}
if (config->initial_timeout_duration_ms > 0) {
@@ -2123,7 +2117,7 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
}
if (config->dummy_pq_padding_len > 0 &&
!SSL_set_dummy_pq_padding_size(ssl.get(), config->dummy_pq_padding_len)) {
- return false;
+ return nullptr;
}
if (!config->quic_transport_params.empty()) {
if (!SSL_set_quic_transport_params(
@@ -2131,10 +2125,55 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
reinterpret_cast<const uint8_t *>(
config->quic_transport_params.data()),
config->quic_transport_params.size())) {
- return false;
+ return nullptr;
+ }
+ }
+
+ if (session != NULL) {
+ if (!config->is_server) {
+ if (SSL_set_session(ssl.get(), session) != 1) {
+ return nullptr;
+ }
+ } else if (config->async) {
+ // The internal session cache is disabled, so install the session
+ // manually.
+ SSL_SESSION_up_ref(session);
+ GetTestState(ssl.get())->pending_session.reset(session);
}
}
+ if (SSL_get_current_cipher(ssl.get()) != nullptr) {
+ fprintf(stderr, "non-null cipher before handshake\n");
+ return nullptr;
+ }
+
+ return ssl;
+}
+
+static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
+ bssl::UniquePtr<SSL> *ssl_uniqueptr,
+ const TestConfig *config, bool is_resume, bool is_retry);
+
+// DoConnection tests an SSL connection against the peer. On success, it returns
+// true and sets |*out_session| to the negotiated SSL session. If the test is a
+// resumption attempt, |is_resume| is true and |session| is the session from the
+// previous exchange.
+static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
+ SSL_CTX *ssl_ctx, const TestConfig *config,
+ const TestConfig *retry_config, bool is_resume,
+ SSL_SESSION *session) {
+ bssl::UniquePtr<SSL> ssl = NewSSL(ssl_ctx, config, session, is_resume,
+ std::unique_ptr<TestState>(new TestState));
+ if (!ssl) {
+ return false;
+ }
+ if (config->is_server) {
+ SSL_set_accept_state(ssl.get());
+ } else {
+ SSL_set_connect_state(ssl.get());
+ }
+
+
int sock = Connect(config->port);
if (sock == -1) {
return false;
@@ -2167,30 +2206,6 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session,
SSL_set_bio(ssl.get(), bio.get(), bio.get());
bio.release(); // SSL_set_bio takes ownership.
- if (session != NULL) {
- if (!config->is_server) {
- if (SSL_set_session(ssl.get(), session) != 1) {
- return false;
- }
- } else if (config->async) {
- // The internal session cache is disabled, so install the session
- // manually.
- SSL_SESSION_up_ref(session);
- GetTestState(ssl.get())->pending_session.reset(session);
- }
- }
-
- if (SSL_get_current_cipher(ssl.get()) != nullptr) {
- fprintf(stderr, "non-null cipher before handshake\n");
- return false;
- }
-
- if (config->is_server) {
- SSL_set_accept_state(ssl.get());
- } else {
- SSL_set_connect_state(ssl.get());
- }
-
bool ret = DoExchange(out_session, &ssl, config, is_resume, false);
if (!config->is_server && is_resume && config->expect_reject_early_data) {
// We must have failed due to an early data rejection.
@@ -2253,22 +2268,28 @@ static bool HandoffReady(SSL *ssl, int ret) {
return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDOFF;
}
+static bool HandbackReady(SSL *ssl, int ret) {
+ return ret < 0 && SSL_get_error(ssl, ret) == SSL_ERROR_HANDBACK;
+}
+
static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
bssl::UniquePtr<SSL> *ssl_uniqueptr,
const TestConfig *config, bool is_resume,
bool is_retry) {
int ret;
SSL *ssl = ssl_uniqueptr->get();
+ SSL_CTX *session_ctx = ssl->ctx;
if (!config->implicit_handshake) {
if (config->handoff) {
- bssl::UniquePtr<SSL_CTX> ctx_handoff(SSL_CTX_new(TLSv1_method()));
+ bssl::UniquePtr<SSL_CTX> ctx_handoff = SetupCtx(ssl->ctx, config);
if (!ctx_handoff) {
return false;
}
SSL_CTX_set_handoff_mode(ctx_handoff.get(), 1);
- bssl::UniquePtr<SSL> ssl_handoff(SSL_new(ctx_handoff.get()));
+ bssl::UniquePtr<SSL> ssl_handoff =
+ NewSSL(ctx_handoff.get(), config, nullptr, false, nullptr);
if (!ssl_handoff) {
return false;
}
@@ -2318,12 +2339,12 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
});
} while (config->async && RetryAsync(ssl, ret));
- if (ret != 1 ||
- !CheckHandshakeProperties(ssl, is_resume, config)) {
- return false;
- }
-
if (config->handoff) {
+ if (!HandbackReady(ssl, ret)) {
+ fprintf(stderr, "Connection failed to handback.\n");
+ return false;
+ }
+
bssl::ScopedCBB cbb;
bssl::Array<uint8_t> handback;
if (!CBB_init(cbb.get(), 512) ||
@@ -2333,26 +2354,42 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
- bssl::UniquePtr<SSL_CTX> ctx_handback(SSL_CTX_new(TLSv1_method()));
- SSL_CTX_set_msg_callback(ctx_handback.get(), MessageCallback);
- bssl::UniquePtr<SSL> ssl_handback(SSL_new(ctx_handback.get()));
- if (!ssl_handback) {
+ bssl::UniquePtr<SSL_CTX> ctx_handback = SetupCtx(ssl->ctx, config);
+ if (!ctx_handback) {
return false;
}
- if (!SSL_apply_handback(ssl_handback.get(), handback)) {
- fprintf(stderr, "Applying handback failed.\n");
+ bssl::UniquePtr<SSL> ssl_handback =
+ NewSSL(ctx_handback.get(), config, nullptr, false, nullptr);
+ if (!ssl_handback) {
return false;
}
-
MoveBIOs(ssl_handback.get(), ssl);
if (!MoveExData(ssl_handback.get(), ssl)) {
return false;
}
+ if (!SSL_apply_handback(ssl_handback.get(), handback)) {
+ fprintf(stderr, "Applying handback failed.\n");
+ return false;
+ }
+
*ssl_uniqueptr = std::move(ssl_handback);
ssl = ssl_uniqueptr->get();
+
+ do {
+ ret = CheckIdempotentError("SSL_do_handshake", ssl, [&]() -> int {
+ return SSL_do_handshake(ssl);
+ });
+ } while (config->async && RetryAsync(ssl, ret));
}
+ if (ret != 1 || !CheckHandshakeProperties(ssl, is_resume, config)) {
+ return false;
+ }
+
+ lh_SSL_SESSION_doall_arg(ssl->ctx->sessions, ssl_ctx_add_session,
+ session_ctx);
+
if (is_resume && !is_retry && !config->is_server &&
config->expect_no_offer_early_data && SSL_in_early_data(ssl)) {
fprintf(stderr, "Client unexpectedly offered early data.\n");
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 16f4dd76..8f354e9f 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -34,13 +34,16 @@ const (
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
const (
tls13Draft23Version = 0x7f17
+ tls13Draft28Version = 0x7f1c
)
const (
TLS13Draft23 = 0
+ TLS13Draft28 = 1
)
var allTLSWireVersions = []uint16{
+ tls13Draft28Version,
tls13Draft23Version,
VersionTLS12,
VersionTLS11,
@@ -1671,7 +1674,7 @@ func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
switch vers {
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
return vers, true
- case tls13Draft23Version:
+ case tls13Draft23Version, tls13Draft28Version:
return VersionTLS13, true
}
}
@@ -1679,11 +1682,16 @@ func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) {
return 0, false
}
+func isDraft28(vers uint16) bool {
+ return vers == tls13Draft28Version
+}
+
// 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 != TLS13Draft23 && wireVers == tls13Draft23Version {
+ if (c.TLS13Variant != TLS13Draft23 && wireVers == tls13Draft23Version) ||
+ (c.TLS13Variant != TLS13Draft28 && wireVers == tls13Draft28Version) {
return 0, false
}
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index 79cd06a7..9cd61eb4 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -448,6 +448,8 @@ func (hc *halfConn) decrypt(b *block) (ok bool, prefixLen int, contentType recor
n := len(payload) - c.Overhead()
additionalData[11] = byte(n >> 8)
additionalData[12] = byte(n)
+ } else if isDraft28(hc.wireVersion) {
+ additionalData = b.data[:recordHeaderLen]
}
var err error
payload, err = c.Open(payload[:0], nonce, payload, additionalData)
@@ -612,6 +614,12 @@ func (hc *halfConn) encrypt(b *block, explicitIVLen int, typ recordType) (bool,
copy(additionalData[8:], b.data[:3])
additionalData[11] = byte(payloadLen >> 8)
additionalData[12] = byte(payloadLen)
+ } else if isDraft28(hc.wireVersion) {
+ additionalData = make([]byte, 5)
+ copy(additionalData, b.data[:3])
+ n := len(b.data) - recordHeaderLen
+ additionalData[3] = byte(n >> 8)
+ additionalData[4] = byte(n)
}
c.Seal(payload[:0], nonce, payload, additionalData)
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 308f3c66..683fd3ac 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -1378,6 +1378,13 @@ var tlsVersions = []tlsVersion{
versionWire: tls13Draft23Version,
tls13Variant: TLS13Draft23,
},
+ {
+ name: "TLS13Draft28",
+ version: VersionTLS13,
+ excludeFlag: "-no-tls13",
+ versionWire: tls13Draft28Version,
+ tls13Variant: TLS13Draft28,
+ },
}
func allVersions(protocol protocol) []tlsVersion {
@@ -5389,16 +5396,12 @@ func addVersionNegotiationTests() {
expectedVersion = runnerVers.version
}
// When running and shim have different TLS 1.3 variants enabled,
- // shim clients are expected to fall back to TLS 1.2, while shim
- // servers support multiple variants.
- expectedServerVersion := expectedVersion
- expectedClientVersion := expectedVersion
+ // shim peers are expected to fall back to TLS 1.2.
if expectedVersion == VersionTLS13 && runnerVers.tls13Variant != shimVers.tls13Variant {
- expectedClientVersion = VersionTLS12
- if shimVers.tls13Variant == TLS13Draft23 {
- expectedServerVersion = VersionTLS12
- }
+ expectedVersion = VersionTLS12
}
+ expectedClientVersion := expectedVersion
+ expectedServerVersion := expectedVersion
suffix := shimVers.name + "-" + runnerVers.name
if protocol == dtls {
diff --git a/src/ssl/tls_record.cc b/src/ssl/tls_record.cc
index 05a3d569..3152e7a2 100644
--- a/src/ssl/tls_record.cc
+++ b/src/ssl/tls_record.cc
@@ -416,7 +416,7 @@ static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,
out_prefix[4] = ciphertext_len & 0xff;
if (!ssl->s3->aead_write_ctx->SealScatter(
- out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, type,
+ out_prefix + SSL3_RT_HEADER_LENGTH, out, out_suffix, out_prefix[0],
record_version, ssl->s3->write_sequence, in, in_len, extra_in,
extra_in_len) ||
!ssl_record_sequence_update(ssl->s3->write_sequence, 8)) {
diff --git a/src/tool/client.cc b/src/tool/client.cc
index 41626982..bdb5de7f 100644
--- a/src/tool/client.cc
+++ b/src/tool/client.cc
@@ -336,6 +336,10 @@ static bool GetTLS13Variant(tls13_variant_t *out, const std::string &in) {
*out = tls13_default;
return true;
}
+ if (in == "draft28") {
+ *out = tls13_draft28;
+ return true;
+ }
return false;
}
diff --git a/src/tool/server.cc b/src/tool/server.cc
index 896aa867..23a47e96 100644
--- a/src/tool/server.cc
+++ b/src/tool/server.cc
@@ -308,7 +308,7 @@ bool Server(const std::vector<std::string> &args) {
}
if (args_map.count("-tls13-variant") != 0) {
- SSL_CTX_set_tls13_variant(ctx.get(), tls13_default);
+ SSL_CTX_set_tls13_variant(ctx.get(), tls13_draft28);
}
if (args_map.count("-debug") != 0) {
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index 9c499cb0..d95fa9e8 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -169,6 +169,17 @@ static bool SpeedRSA(const std::string &key_name, RSA *key,
if (!TimeFunction(&results,
[key, &fake_sha256_hash, &sig, sig_len]() -> bool {
+ return RSA_verify(NID_sha256, fake_sha256_hash,
+ sizeof(fake_sha256_hash), sig.get(), sig_len, key);
+ })) {
+ fprintf(stderr, "RSA_verify failed.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+ results.Print(key_name + " verify (same key)");
+
+ if (!TimeFunction(&results,
+ [key, &fake_sha256_hash, &sig, sig_len]() -> bool {
// Usually during RSA verification we have to parse an RSA key from a
// certificate or similar, in which case we'd need to construct a new
// RSA key, with a new |BN_MONT_CTX| for the public modulus. If we were
@@ -185,13 +196,14 @@ static bool SpeedRSA(const std::string &key_name, RSA *key,
return false;
}
return RSA_verify(NID_sha256, fake_sha256_hash,
- sizeof(fake_sha256_hash), sig.get(), sig_len, key);
+ sizeof(fake_sha256_hash), sig.get(), sig_len,
+ verify_key.get());
})) {
fprintf(stderr, "RSA_verify failed.\n");
ERR_print_errors_fp(stderr);
return false;
}
- results.Print(key_name + " verify");
+ results.Print(key_name + " verify (fresh key)");
return true;
}