diff options
author | Robert Sloan <varomodt@google.com> | 2018-04-10 10:22:33 -0700 |
---|---|---|
committer | Robert Sloan <varomodt@google.com> | 2018-04-10 10:23:01 -0700 |
commit | dc2f609faa3d5fa920e2c42a39750dca1a247c8f (patch) | |
tree | d5b57ecd5d961f542f8635fbdeefbc5262d779fc /src | |
parent | 49d063bbd8327cb483bdee6ea604c068f1bb044e (diff) | |
download | boringssl-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.c | 2 | ||||
-rw-r--r-- | src/crypto/fipsmodule/bn/prime.c | 62 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec.c | 12 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/internal.h | 7 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/simple.c | 81 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/wnaf.c | 44 | ||||
-rw-r--r-- | src/include/openssl/ssl.h | 14 | ||||
-rw-r--r-- | src/ssl/handoff.cc | 146 | ||||
-rw-r--r-- | src/ssl/handshake.cc | 5 | ||||
-rw-r--r-- | src/ssl/handshake_server.cc | 190 | ||||
-rw-r--r-- | src/ssl/internal.h | 51 | ||||
-rw-r--r-- | src/ssl/ssl_aead_ctx.cc | 29 | ||||
-rw-r--r-- | src/ssl/ssl_key_share.cc | 54 | ||||
-rw-r--r-- | src/ssl/ssl_lib.cc | 3 | ||||
-rw-r--r-- | src/ssl/ssl_test.cc | 9 | ||||
-rw-r--r-- | src/ssl/ssl_transcript.cc | 4 | ||||
-rw-r--r-- | src/ssl/ssl_versions.cc | 22 | ||||
-rw-r--r-- | src/ssl/test/bssl_shim.cc | 175 | ||||
-rw-r--r-- | src/ssl/test/runner/common.go | 12 | ||||
-rw-r--r-- | src/ssl/test/runner/conn.go | 8 | ||||
-rw-r--r-- | src/ssl/test/runner/runner.go | 19 | ||||
-rw-r--r-- | src/ssl/tls_record.cc | 2 | ||||
-rw-r--r-- | src/tool/client.cc | 4 | ||||
-rw-r--r-- | src/tool/server.cc | 2 | ||||
-rw-r--r-- | src/tool/speed.cc | 16 |
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; } |