summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSteven Valdez <svaldez@google.com>2016-11-21 15:35:44 -0500
committerSteven Valdez <svaldez@google.com>2016-11-22 10:25:59 -0500
commit909b19f027eb0af12513f4d5589efdd67e34bd91 (patch)
tree45a240b1d683dbc5599bd3d397f80d794148d6c0 /src
parent95add82835138f09cf7bb4a51c04c6320c241674 (diff)
downloadboringssl-909b19f027eb0af12513f4d5589efdd67e34bd91.tar.gz
external/boringssl: Sync to 68f37b7a3f451aa1ca8c93669c024d01f6270ae8.
This includes the following changes: https://boringssl.googlesource.com/boringssl/+log/3ef7697ed30f28367395a5aafb57a12a19906d96..68f37b7a3f451aa1ca8c93669c024d01f6270ae8 Test: cts-tradefed run cts -m CtsLibcoreOkHttpTestCases -a arm64-v8a Test: cts-tradefed run cts -m CtsLibcoreTestCases -a arm64-v8a Change-Id: I296d05afab7470335cdda2442414a858df591f6c
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt22
-rw-r--r--src/FUZZING.md28
-rw-r--r--src/INCORPORATING.md4
-rw-r--r--src/crypto/CMakeLists.txt2
-rw-r--r--src/crypto/aes/asm/aesp8-ppc.pl4
-rw-r--r--src/crypto/aes/key_wrap.c6
-rw-r--r--src/crypto/asn1/a_gentm.c34
-rw-r--r--src/crypto/asn1/tasn_utl.c26
-rw-r--r--src/crypto/bio/bio.c22
-rw-r--r--src/crypto/bio/bio_test.cc2
-rwxr-xr-xsrc/crypto/bn/asm/x86_64-mont.pl5
-rw-r--r--src/crypto/bn/bn_test.cc50
-rw-r--r--src/crypto/bn/bn_tests.txt12
-rw-r--r--src/crypto/bn/div.c4
-rw-r--r--src/crypto/bn/internal.h4
-rw-r--r--src/crypto/bn/shift.c8
-rw-r--r--src/crypto/cipher/e_tls.c4
-rw-r--r--src/crypto/conf/conf.c2
-rw-r--r--src/crypto/curve25519/curve25519.c45
-rw-r--r--src/crypto/curve25519/ed25519_test.cc21
-rw-r--r--src/crypto/ec/CMakeLists.txt11
-rwxr-xr-xsrc/crypto/ec/asm/p256-x86_64-asm.pl109
-rw-r--r--src/crypto/ec/ec_test.cc58
-rw-r--r--src/crypto/ec/p256-x86_64.c100
-rw-r--r--src/crypto/ec/p256-x86_64.h110
-rw-r--r--src/crypto/ec/p256-x86_64_test.cc508
-rw-r--r--src/crypto/ec/p256-x86_64_tests.txt1405
-rw-r--r--src/crypto/err/ssl.errordata3
-rw-r--r--src/crypto/mem.c8
-rw-r--r--src/crypto/poly1305/poly1305.c25
-rw-r--r--src/crypto/pool/CMakeLists.txt20
-rw-r--r--src/crypto/pool/internal.h45
-rw-r--r--src/crypto/pool/pool.c200
-rw-r--r--src/crypto/pool/pool_test.cc86
-rw-r--r--src/crypto/rand/deterministic.c4
-rw-r--r--src/crypto/rand/rand.c2
-rw-r--r--src/crypto/rand/urandom.c67
-rw-r--r--src/crypto/rand/windows.c4
-rw-r--r--src/crypto/sha/CMakeLists.txt1
-rw-r--r--src/crypto/sha/sha1-altivec.c346
-rw-r--r--src/crypto/sha/sha1.c3
-rw-r--r--src/crypto/x509/t_x509.c2
-rw-r--r--src/crypto/x509/x509_test.cc828
-rw-r--r--src/crypto/x509/x_crl.c2
-rw-r--r--src/crypto/x509/x_name.c8
-rw-r--r--src/crypto/x509/x_x509.c33
-rw-r--r--src/include/openssl/asn1.h10
-rw-r--r--src/include/openssl/base.h10
-rw-r--r--src/include/openssl/bio.h7
-rw-r--r--src/include/openssl/bn.h16
-rw-r--r--src/include/openssl/conf.h3
-rw-r--r--src/include/openssl/curve25519.h12
-rw-r--r--src/include/openssl/lhash.h1
-rw-r--r--src/include/openssl/lhash_macros.h70
-rw-r--r--src/include/openssl/pool.h87
-rw-r--r--src/include/openssl/rand.h2
-rw-r--r--src/include/openssl/ssl.h70
-rw-r--r--src/include/openssl/ssl3.h1
-rw-r--r--src/include/openssl/stack.h1
-rw-r--r--src/include/openssl/stack_macros.h85
-rw-r--r--src/include/openssl/tls1.h3
-rw-r--r--src/include/openssl/x509.h26
-rw-r--r--src/ssl/custom_extensions.c10
-rw-r--r--src/ssl/d1_both.c29
-rw-r--r--src/ssl/d1_pkt.c2
-rw-r--r--src/ssl/dtls_method.c3
-rw-r--r--src/ssl/handshake_client.c244
-rw-r--r--src/ssl/handshake_server.c388
-rw-r--r--src/ssl/internal.h265
-rw-r--r--src/ssl/s3_both.c100
-rw-r--r--src/ssl/s3_enc.c9
-rw-r--r--src/ssl/s3_lib.c4
-rw-r--r--src/ssl/s3_pkt.c6
-rw-r--r--src/ssl/ssl_aead_ctx.c8
-rw-r--r--src/ssl/ssl_asn1.c95
-rw-r--r--src/ssl/ssl_cert.c61
-rw-r--r--src/ssl/ssl_cipher.c225
-rw-r--r--src/ssl/ssl_lib.c128
-rw-r--r--src/ssl/ssl_rsa.c13
-rw-r--r--src/ssl/ssl_session.c106
-rw-r--r--src/ssl/ssl_test.cc966
-rw-r--r--src/ssl/t1_enc.c126
-rw-r--r--src/ssl/t1_lib.c659
-rw-r--r--src/ssl/test/bssl_shim.cc209
-rw-r--r--src/ssl/test/packeted_bio.cc33
-rw-r--r--src/ssl/test/packeted_bio.h13
-rw-r--r--src/ssl/test/runner/cipher_suites.go16
-rw-r--r--src/ssl/test/runner/common.go99
-rw-r--r--src/ssl/test/runner/conn.go69
-rw-r--r--src/ssl/test/runner/fuzzer_mode.json16
-rw-r--r--src/ssl/test/runner/handshake_client.go272
-rw-r--r--src/ssl/test/runner/handshake_messages.go345
-rw-r--r--src/ssl/test/runner/handshake_server.go359
-rw-r--r--src/ssl/test/runner/prf.go59
-rw-r--r--src/ssl/test/runner/rsa_chain_cert.pem35
-rw-r--r--src/ssl/test/runner/rsa_chain_key.pem28
-rw-r--r--src/ssl/test/runner/runner.go1109
-rw-r--r--src/ssl/test/runner/shim_ticket.go249
-rw-r--r--src/ssl/test/test_config.cc15
-rw-r--r--src/ssl/test/test_config.h11
-rw-r--r--src/ssl/tls13_both.c255
-rw-r--r--src/ssl/tls13_client.c312
-rw-r--r--src/ssl/tls13_enc.c288
-rw-r--r--src/ssl/tls13_server.c358
-rw-r--r--src/ssl/tls_method.c3
-rw-r--r--src/ssl/tls_record.c19
-rw-r--r--src/tool/digest.cc18
-rw-r--r--src/tool/pkcs12.cc11
-rw-r--r--src/tool/rand.cc1
-rw-r--r--src/tool/server.cc32
-rw-r--r--src/tool/speed.cc54
-rw-r--r--src/tool/transport_common.cc16
-rw-r--r--src/util/all_tests.json2
-rw-r--r--src/util/bot/DEPS7
-rwxr-xr-xsrc/util/bot/go/bootstrap.py2
-rw-r--r--src/util/bot/update_clang.py2
-rw-r--r--src/util/bot/vs_toolchain.py2
-rw-r--r--src/util/doc.config1
-rw-r--r--src/util/generate_build_files.py2
-rw-r--r--src/util/run_android_tests.go4
120 files changed, 9211 insertions, 3259 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8ab4066c..cb8bb539 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -47,6 +47,9 @@ elseif(MSVC)
"C4127" # conditional expression is constant
"C4200" # nonstandard extension used : zero-sized array in
# struct/union.
+ "C4204" # nonstandard extension used: non-constant aggregate initializer
+ "C4221" # nonstandard extension used : 'identifier' : cannot be
+ # initialized using address of automatic variable
"C4242" # 'function' : conversion from 'int' to 'uint8_t',
# possible loss of data
"C4244" # 'function' : conversion from 'int' to 'uint8_t',
@@ -125,8 +128,13 @@ if(FUZZ)
message(FATAL_ERROR "You need to build with Clang for fuzzing to work")
endif()
- add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
- set(RUNNER_ARGS "-fuzzer" "-deterministic" "-shim-config" "fuzzer_mode.json")
+ add_definitions(-DBORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+ set(RUNNER_ARGS "-deterministic")
+
+ if(NOT NO_FUZZER_MODE)
+ add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE)
+ set(RUNNER_ARGS ${RUNNER_ARGS} "-fuzzer" "-shim-config" "fuzzer_mode.json")
+ endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize-coverage=edge,indirect-calls,8bit-counters")
@@ -160,14 +168,14 @@ elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i386")
set(ARCH "x86")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "i686")
set(ARCH "x86")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm")
- set(ARCH "arm")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv6")
- set(ARCH "arm")
-elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "armv7-a")
+elseif (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm*")
set(ARCH "arm")
elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
set(ARCH "aarch64")
+elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "mips")
+ # Just to avoid the “unknown processor” error.
+elseif (${CMAKE_SYSTEM_PROCESSOR} STREQUAL "ppc64le")
+ set(ARCH "ppc64le")
else()
message(FATAL_ERROR "Unknown processor:" ${CMAKE_SYSTEM_PROCESSOR})
endif()
diff --git a/src/FUZZING.md b/src/FUZZING.md
index 1a214030..f004c27d 100644
--- a/src/FUZZING.md
+++ b/src/FUZZING.md
@@ -53,39 +53,31 @@ In order to minimise all the corpuses, build for fuzzing and run `./fuzz/minimis
## Fuzzer mode
-When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` defined. This modifies the library, particularly the TLS stack, to be more friendly to fuzzers. It will:
+When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FUZZER_MODE` and `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. This modifies the library to be more friendly to fuzzers. If `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` is set, BoringSSL will:
* Replace `RAND_bytes` with a deterministic PRNG. Call `RAND_reset_for_fuzzing()` at the start of fuzzers which use `RAND_bytes` to reset the PRNG state.
+* Use a hard-coded time instead of the actual time.
+
+Additionally, if `BORINGSSL_UNSAFE_FUZZER_MODE` is set, BoringSSL will:
+
* Modify the TLS stack to perform all signature checks (CertificateVerify and ServerKeyExchange) and the Finished check, but always act as if the check succeeded.
* Treat every cipher as the NULL cipher.
-* Use a hard-coded time instead of the actual time.
-
* Tickets are unencrypted and the MAC check is performed but ignored.
This is to prevent the fuzzer from getting stuck at a cryptographic invariant in the protocol.
## TLS transcripts
-The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. To run the tests against a fuzzer-mode `bssl_shim`, run:
+The `client` and `server` corpora are seeded from the test suite. The test suite has a `-fuzzer` flag which mirrors the fuzzer mode changes above and a `-deterministic` flag which removes all non-determinism on the Go side. Not all tests pass, so `ssl/test/runner/fuzzer_mode.json` contains the necessary suppressions. The `run_tests` target will pass appropriate command-line flags.
-```
-cd ssl/test/runner
-go test -fuzzer -deterministic -shim-config fuzzer_mode.json
-```
-
-For a different build directory from `build/`, pass the appropriate `-shim-path` flag. If those tests pass, record a set of transcripts with:
-
-```
-go test -fuzzer -deterministic -transcript-dir /tmp/transcripts/
-```
+There are separate corpora, `client_corpus_no_fuzzer_mode` and `server_corpus_no_fuzzer_mode`. These are transcripts for fuzzers with only `BORINGSSL_UNSAFE_DETERMINISTIC_MODE` defined. To build in this mode, pass `-DNO_FUZZER_MODE=1` into CMake. This configuration is run in the same way but without `-fuzzer` and `-shim-path` flags.
-Note the suppressions file is ignored so disabled tests record transcripts too. Then merge into the existing corpora:
+If both sets of tests pass, refresh the fuzzer corpora with `refresh_ssl_corpora.sh`:
```
-cd build/
-./fuzz/client -max_len=50000 -merge=1 ../fuzz/client_corpus /tmp/transcripts/tls/client
-./fuzz/server -max_len=50000 -merge=1 ../fuzz/server_corpus /tmp/transcripts/tls/server
+cd fuzz
+./refresh_fuzzer_corpora.sh /path/to/fuzzer/mode/build /path/to/non/fuzzer/mode/build
```
diff --git a/src/INCORPORATING.md b/src/INCORPORATING.md
index 38e9d793..6dc7fa9e 100644
--- a/src/INCORPORATING.md
+++ b/src/INCORPORATING.md
@@ -5,7 +5,7 @@
## Bazel
-If you are using [Bazel](http://www.bazel.io) then you can incorporate
+If you are using [Bazel](https://bazel.build) then you can incorporate
BoringSSL as an external repository by using a commit from the
`master-with-bazel` branch. That branch is maintained by a bot from `master`
and includes the needed generated files and a top-level BUILD file.
@@ -38,7 +38,7 @@ updating things more complex.
BoringSSL is designed to work with many different build systems. Currently,
different projects use [GYP](https://gyp.gsrc.io/),
[GN](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/quick_start.md),
-[Bazel](http://bazel.io/) and [Make](https://www.gnu.org/software/make/) to
+[Bazel](https://bazel.build/) and [Make](https://www.gnu.org/software/make/) to
build BoringSSL, without too much pain.
The development build system is CMake and the CMake build knows how to
diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt
index 4cc5ae26..20a38dc6 100644
--- a/src/crypto/CMakeLists.txt
+++ b/src/crypto/CMakeLists.txt
@@ -64,6 +64,7 @@ add_subdirectory(err)
add_subdirectory(buf)
add_subdirectory(base64)
add_subdirectory(bytestring)
+add_subdirectory(pool)
# Level 0.2 - depends on nothing but itself
add_subdirectory(sha)
@@ -136,6 +137,7 @@ add_library(
$<TARGET_OBJECTS:err>
$<TARGET_OBJECTS:base64>
$<TARGET_OBJECTS:bytestring>
+ $<TARGET_OBJECTS:pool>
$<TARGET_OBJECTS:sha>
$<TARGET_OBJECTS:md4>
$<TARGET_OBJECTS:md5>
diff --git a/src/crypto/aes/asm/aesp8-ppc.pl b/src/crypto/aes/asm/aesp8-ppc.pl
index 4bdcff74..ca3a1500 100644
--- a/src/crypto/aes/asm/aesp8-ppc.pl
+++ b/src/crypto/aes/asm/aesp8-ppc.pl
@@ -3011,7 +3011,7 @@ _aesp8_xts_enc5x:
vxor $twk0,$twk0,v31
vcipher $out0,$out0,v26
- lvsr $inpperm,r0,$taillen # $in5 is no more
+ lvsr $inpperm,0,$taillen # $in5 is no more
vcipher $out1,$out1,v26
vcipher $out2,$out2,v26
vcipher $out3,$out3,v26
@@ -3773,7 +3773,7 @@ foreach(split("\n",$code)) {
if ($flavour =~ /le$/o) {
SWITCH: for($conv) {
/\?inv/ && do { @bytes=map($_^0xf,@bytes); last; };
- /\?rev/ && do { @bytes=reverse(@bytes); last; };
+ /\?rev/ && do { @bytes=reverse(@bytes); last; };
}
}
diff --git a/src/crypto/aes/key_wrap.c b/src/crypto/aes/key_wrap.c
index e955c475..c8b6a034 100644
--- a/src/crypto/aes/key_wrap.c
+++ b/src/crypto/aes/key_wrap.c
@@ -59,6 +59,8 @@ static const uint8_t kDefaultIV[] = {
0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6,
};
+static const unsigned kBound = 6;
+
int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
const uint8_t *in, size_t in_len) {
/* See RFC 3394, section 2.2.1. */
@@ -77,7 +79,7 @@ int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
size_t n = in_len / 8;
- for (unsigned j = 0; j < 6; j++) {
+ for (unsigned j = 0; j < kBound; j++) {
for (size_t i = 1; i <= n; i++) {
memcpy(A + 8, out + 8 * i, 8);
AES_encrypt(A, A, key);
@@ -113,7 +115,7 @@ int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
size_t n = (in_len / 8) - 1;
- for (unsigned j = 5; j < 6; j--) {
+ for (unsigned j = kBound - 1; j < kBound; j--) {
for (size_t i = n; i > 0; i--) {
uint32_t t = (uint32_t)(n * j + i);
A[7] ^= t & 0xff;
diff --git a/src/crypto/asn1/a_gentm.c b/src/crypto/asn1/a_gentm.c
index ee6b3db5..2f298689 100644
--- a/src/crypto/asn1/a_gentm.c
+++ b/src/crypto/asn1/a_gentm.c
@@ -220,37 +220,43 @@ ASN1_GENERALIZEDTIME *ASN1_GENERALIZEDTIME_adj(ASN1_GENERALIZEDTIME *s,
struct tm *ts;
struct tm data;
size_t len = 20;
+ ASN1_GENERALIZEDTIME *tmps = NULL;
if (s == NULL)
- s = M_ASN1_GENERALIZEDTIME_new();
- if (s == NULL)
- return (NULL);
+ tmps = ASN1_GENERALIZEDTIME_new();
+ else
+ tmps = s;
+ if (tmps == NULL)
+ return NULL;
ts = OPENSSL_gmtime(&t, &data);
if (ts == NULL)
- return (NULL);
+ goto err;
if (offset_day || offset_sec) {
if (!OPENSSL_gmtime_adj(ts, offset_day, offset_sec))
- return NULL;
+ goto err;
}
- p = (char *)s->data;
- if ((p == NULL) || ((size_t)s->length < len)) {
+ p = (char *)tmps->data;
+ if ((p == NULL) || ((size_t)tmps->length < len)) {
p = OPENSSL_malloc(len);
if (p == NULL) {
OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE);
- return (NULL);
+ goto err;
}
- if (s->data != NULL)
- OPENSSL_free(s->data);
- s->data = (unsigned char *)p;
+ OPENSSL_free(tmps->data);
+ tmps->data = (unsigned char *)p;
}
BIO_snprintf(p, len, "%04d%02d%02d%02d%02d%02dZ", ts->tm_year + 1900,
ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min,
ts->tm_sec);
- s->length = strlen(p);
- s->type = V_ASN1_GENERALIZEDTIME;
- return (s);
+ tmps->length = strlen(p);
+ tmps->type = V_ASN1_GENERALIZEDTIME;
+ return tmps;
+ err:
+ if (s == NULL)
+ ASN1_GENERALIZEDTIME_free(tmps);
+ return NULL;
}
diff --git a/src/crypto/asn1/tasn_utl.c b/src/crypto/asn1/tasn_utl.c
index d409cfac..3f530729 100644
--- a/src/crypto/asn1/tasn_utl.c
+++ b/src/crypto/asn1/tasn_utl.c
@@ -56,6 +56,7 @@
#include <openssl/asn1.h>
+#include <assert.h>
#include <string.h>
#include <openssl/asn1t.h>
@@ -134,6 +135,8 @@ void asn1_enc_init(ASN1_VALUE **pval, const ASN1_ITEM *it) {
if (enc) {
enc->enc = NULL;
enc->len = 0;
+ enc->alias_only = 0;
+ enc->alias_only_on_next_parse = 0;
enc->modified = 1;
}
}
@@ -142,11 +145,13 @@ void asn1_enc_free(ASN1_VALUE **pval, const ASN1_ITEM *it) {
ASN1_ENCODING *enc;
enc = asn1_get_enc_ptr(pval, it);
if (enc) {
- if (enc->enc) {
+ if (enc->enc && !enc->alias_only) {
OPENSSL_free(enc->enc);
}
enc->enc = NULL;
enc->len = 0;
+ enc->alias_only = 0;
+ enc->alias_only_on_next_parse = 0;
enc->modified = 1;
}
}
@@ -159,14 +164,23 @@ int asn1_enc_save(ASN1_VALUE **pval, const unsigned char *in, int inlen,
return 1;
}
- if (enc->enc) {
+ if (!enc->alias_only) {
OPENSSL_free(enc->enc);
}
- enc->enc = OPENSSL_malloc(inlen);
- if (!enc->enc) {
- return 0;
+
+ enc->alias_only = enc->alias_only_on_next_parse;
+ enc->alias_only_on_next_parse = 0;
+
+ if (enc->alias_only) {
+ enc->enc = (uint8_t *) in;
+ } else {
+ enc->enc = OPENSSL_malloc(inlen);
+ if (!enc->enc) {
+ return 0;
+ }
+ memcpy(enc->enc, in, inlen);
}
- memcpy(enc->enc, in, inlen);
+
enc->len = inlen;
enc->modified = 0;
diff --git a/src/crypto/bio/bio.c b/src/crypto/bio/bio.c
index 8f8a1969..675e903a 100644
--- a/src/crypto/bio/bio.c
+++ b/src/crypto/bio/bio.c
@@ -336,7 +336,13 @@ long BIO_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
}
size_t BIO_pending(const BIO *bio) {
- return BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+ const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_PENDING, 0, NULL);
+ assert(r >= 0);
+
+ if (r < 0) {
+ return 0;
+ }
+ return r;
}
size_t BIO_ctrl_pending(const BIO *bio) {
@@ -344,7 +350,13 @@ size_t BIO_ctrl_pending(const BIO *bio) {
}
size_t BIO_wpending(const BIO *bio) {
- return BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+ const long r = BIO_ctrl((BIO *) bio, BIO_CTRL_WPENDING, 0, NULL);
+ assert(r >= 0);
+
+ if (r < 0) {
+ return 0;
+ }
+ return r;
}
int BIO_set_close(BIO *bio, int close_flag) {
@@ -448,12 +460,8 @@ static int print_bio(const char *str, size_t len, void *bio) {
return BIO_write((BIO *)bio, str, len);
}
-void BIO_print_errors(BIO *bio) {
- ERR_print_errors_cb(print_bio, bio);
-}
-
void ERR_print_errors(BIO *bio) {
- BIO_print_errors(bio);
+ ERR_print_errors_cb(print_bio, bio);
}
/* bio_read_all reads everything from |bio| and prepends |prefix| to it. On
diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc
index cbc4fde8..01b93f60 100644
--- a/src/crypto/bio/bio_test.cc
+++ b/src/crypto/bio/bio_test.cc
@@ -59,7 +59,7 @@ static void PrintSocketError(const char *func) {
class ScopedSocket {
public:
- ScopedSocket(int sock) : sock_(sock) {}
+ explicit ScopedSocket(int sock) : sock_(sock) {}
~ScopedSocket() {
closesocket(sock_);
}
diff --git a/src/crypto/bn/asm/x86_64-mont.pl b/src/crypto/bn/asm/x86_64-mont.pl
index 92933d47..60e0111a 100755
--- a/src/crypto/bn/asm/x86_64-mont.pl
+++ b/src/crypto/bn/asm/x86_64-mont.pl
@@ -1059,18 +1059,17 @@ $code.=<<___;
mulx 2*8($aptr),%r15,%r13 # ...
adox -3*8($tptr),%r11
adcx %r15,%r12
- adox $zero,%r12
+ adox -2*8($tptr),%r12
adcx $zero,%r13
+ adox $zero,%r13
mov $bptr,8(%rsp) # off-load &b[i]
- .byte 0x67
mov $mi,%r15
imulq 24(%rsp),$mi # "t[0]"*n0
xor %ebp,%ebp # xor $zero,$zero # cf=0, of=0
mulx 3*8($aptr),%rax,%r14
mov $mi,%rdx
- adox -2*8($tptr),%r12
adcx %rax,%r13
adox -1*8($tptr),%r13
adcx $zero,%r14
diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc
index 04888100..672d83f1 100644
--- a/src/crypto/bn/bn_test.cc
+++ b/src/crypto/bn/bn_test.cc
@@ -1024,14 +1024,12 @@ static bool TestASN1() {
}
// Test the value serializes correctly.
- CBB cbb;
+ bssl::ScopedCBB cbb;
uint8_t *der;
size_t der_len;
- CBB_zero(&cbb);
- if (!CBB_init(&cbb, 0) ||
- !BN_marshal_asn1(&cbb, bn.get()) ||
- !CBB_finish(&cbb, &der, &der_len)) {
- CBB_cleanup(&cbb);
+ if (!CBB_init(cbb.get(), 0) ||
+ !BN_marshal_asn1(cbb.get(), bn.get()) ||
+ !CBB_finish(cbb.get(), &der, &der_len)) {
return false;
}
bssl::UniquePtr<uint8_t> delete_der(der);
@@ -1114,16 +1112,13 @@ static bool TestASN1() {
if (!bn) {
return false;
}
- CBB cbb;
- CBB_zero(&cbb);
- if (!CBB_init(&cbb, 0) ||
- BN_marshal_asn1(&cbb, bn.get())) {
+ bssl::ScopedCBB cbb;
+ if (!CBB_init(cbb.get(), 0) ||
+ BN_marshal_asn1(cbb.get(), bn.get())) {
fprintf(stderr, "Serialized negative number.\n");
- CBB_cleanup(&cbb);
return false;
}
ERR_clear_error();
- CBB_cleanup(&cbb);
return true;
}
@@ -1208,6 +1203,37 @@ static bool TestNegativeZero(BN_CTX *ctx) {
return false;
}
+ // Test that |BN_rshift| and |BN_rshift1| will not produce a negative zero.
+ if (!BN_set_word(a.get(), 1)) {
+ return false;
+ }
+
+ BN_set_negative(a.get(), 1);
+ if (!BN_rshift(b.get(), a.get(), 1) ||
+ !BN_rshift1(c.get(), a.get())) {
+ return false;
+ }
+
+ if (!BN_is_zero(b.get()) || BN_is_negative(b.get())) {
+ fprintf(stderr, "BN_rshift(-1, 1) produced the wrong result.\n");
+ return false;
+ }
+
+ if (!BN_is_zero(c.get()) || BN_is_negative(c.get())) {
+ fprintf(stderr, "BN_rshift1(-1) produced the wrong result.\n");
+ return false;
+ }
+
+ // Test that |BN_div_word| will not produce a negative zero.
+ if (BN_div_word(a.get(), 2) == (BN_ULONG)-1) {
+ return false;
+ }
+
+ if (!BN_is_zero(a.get()) || BN_is_negative(a.get())) {
+ fprintf(stderr, "BN_div_word(-1, 2) produced the wrong result.\n");
+ return false;
+ }
+
return true;
}
diff --git a/src/crypto/bn/bn_tests.txt b/src/crypto/bn/bn_tests.txt
index 8451fcf4..692a6429 100644
--- a/src/crypto/bn/bn_tests.txt
+++ b/src/crypto/bn/bn_tests.txt
@@ -9875,6 +9875,18 @@ A = 1c08cec52d96136fbd9078b7b8db36ab63b86e19dd3dba7b2e3190ff566180e89dfee9423fa4
B = a8b4bc9647d8df9b7c76cc6d0f2248cdbc41f5da9c061f9864aa8415c9557582cada456cf23cc32d47d1fc1caf19d36b398019aac4734e10f55ce3cad419e5e7
M = 7eacffe21f88413af94155a2a8e37f70a431a59653738afda04a1bec72d0d9ed
+# Regression tests for CVE-2016-7055.
+
+ModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9
+A = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878
+B = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81
+M = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf
+
+ModMul = ccd6f75b5f24b7c5ce2ce755fa89c2450c6a7d96ce8c8791e659eab84577a7695e3b2caa7c980fb23f60634233e9798499c28b0338c1f1a326d0ca89fd41f2fd88b759f317889832966b551a950043ec7a4b6152d3e2cbfb40e88458e70ab783b96f12d271f828d5b39e198ccaf8665411d85026282dbead5d24cd01b6c8a8e9
+A = 095d72c08c097ba488c5e439c655a192eafb6380073d8c2664668eddb4060744e16e57fb4edb9ae10a0cefcdc28a894f689a128379db279d48a2e20849d685939b7803bcf46cebf5c533fb0dd35b080593de5472e3fe5db951b8bff9b4cb8f039cc638a5ee8cdd703719f8000e6a9f63beed5f2fcd52ff293ea05a251bb4ab81
+B = 7878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878787878
+M = d78af684e71db0c39cff4e64fb9db567132cb9c50cc98009feb820b26f2ded9b91b9b5e2b83ae0ae4eb4e0523ca726bfbe969b89fd754f674ce99118c3f2d1c5d81fdc7c54e02b60262b241d53c040e99e45826eca37a804668e690e1afc1ca42c9a15d84d4954425f0b7642fc0bd9d7b24e2618d2dcc9b729d944badacfddaf
+
# ModExp tests.
#
diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c
index 03577f24..ab492812 100644
--- a/src/crypto/bn/div.c
+++ b/src/crypto/bn/div.c
@@ -628,6 +628,10 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
a->top--;
}
+ if (a->top == 0) {
+ a->neg = 0;
+ }
+
ret >>= j;
return ret;
}
diff --git a/src/crypto/bn/internal.h b/src/crypto/bn/internal.h
index 99fc3062..aeed88f7 100644
--- a/src/crypto/bn/internal.h
+++ b/src/crypto/bn/internal.h
@@ -160,7 +160,7 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
#define BN_TBIT (0x8000000000000000UL)
#define BN_DEC_CONV (10000000000000000000UL)
#define BN_DEC_NUM 19
-#define TOBN(hi, lo) ((BN_ULONG)hi << 32 | lo)
+#define TOBN(hi, lo) ((BN_ULONG)(hi) << 32 | (lo))
#elif defined(OPENSSL_32_BIT)
@@ -181,7 +181,7 @@ BIGNUM *bn_expand(BIGNUM *bn, size_t bits);
#define BN_TBIT (0x80000000UL)
#define BN_DEC_CONV (1000000000UL)
#define BN_DEC_NUM 9
-#define TOBN(hi, lo) lo, hi
+#define TOBN(hi, lo) (lo), (hi)
#else
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
diff --git a/src/crypto/bn/shift.c b/src/crypto/bn/shift.c
index defec929..22006d1a 100644
--- a/src/crypto/bn/shift.c
+++ b/src/crypto/bn/shift.c
@@ -182,6 +182,10 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) {
}
}
+ if (r->top == 0) {
+ r->neg = 0;
+ }
+
return 1;
}
@@ -215,6 +219,10 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) {
}
r->top = j;
+ if (r->top == 0) {
+ r->neg = 0;
+ }
+
return 1;
}
diff --git a/src/crypto/cipher/e_tls.c b/src/crypto/cipher/e_tls.c
index 95483e71..c0d18fdb 100644
--- a/src/crypto/cipher/e_tls.c
+++ b/src/crypto/cipher/e_tls.c
@@ -262,7 +262,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
/* Remove CBC padding. Code from here on is timing-sensitive with respect to
* |padding_ok| and |data_plus_mac_len| for CBC ciphers. */
- unsigned padding_ok, data_plus_mac_len, data_len;
+ unsigned padding_ok, data_plus_mac_len;
if (EVP_CIPHER_CTX_mode(&tls_ctx->cipher_ctx) == EVP_CIPH_CBC_MODE) {
if (!EVP_tls_cbc_remove_padding(
&padding_ok, &data_plus_mac_len, out, total,
@@ -279,7 +279,7 @@ static int aead_tls_open(const EVP_AEAD_CTX *ctx, uint8_t *out,
* already been checked against the MAC size at the top of the function. */
assert(data_plus_mac_len >= HMAC_size(&tls_ctx->hmac_ctx));
}
- data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx);
+ unsigned data_len = data_plus_mac_len - HMAC_size(&tls_ctx->hmac_ctx);
/* At this point, if the padding is valid, the first |data_plus_mac_len| bytes
* after |out| are the plaintext and MAC. Otherwise, |data_plus_mac_len| is
diff --git a/src/crypto/conf/conf.c b/src/crypto/conf/conf.c
index e4fc428b..96a534ab 100644
--- a/src/crypto/conf/conf.c
+++ b/src/crypto/conf/conf.c
@@ -786,3 +786,5 @@ int CONF_modules_load_file(CONF_MUST_BE_NULL *filename, const char *appname,
void CONF_modules_free(void) {}
void OPENSSL_config(CONF_MUST_BE_NULL *config_name) {}
+
+void OPENSSL_no_config(void) {}
diff --git a/src/crypto/curve25519/curve25519.c b/src/crypto/curve25519/curve25519.c
index 93ef7dc4..d660b6c6 100644
--- a/src/crypto/curve25519/curve25519.c
+++ b/src/crypto/curve25519/curve25519.c
@@ -640,9 +640,6 @@ static void fe_invert(fe out, const fe z) {
int i;
fe_sq(t0, z);
- for (i = 1; i < 1; ++i) {
- fe_sq(t0, t0);
- }
fe_sq(t1, t0);
for (i = 1; i < 2; ++i) {
fe_sq(t1, t1);
@@ -650,9 +647,6 @@ static void fe_invert(fe out, const fe z) {
fe_mul(t1, z, t1);
fe_mul(t0, t0, t1);
fe_sq(t2, t0);
- for (i = 1; i < 1; ++i) {
- fe_sq(t2, t2);
- }
fe_mul(t1, t1, t2);
fe_sq(t2, t1);
for (i = 1; i < 5; ++i) {
@@ -907,9 +901,6 @@ static void fe_pow22523(fe out, const fe z) {
int i;
fe_sq(t0, z);
- for (i = 1; i < 1; ++i) {
- fe_sq(t0, t0);
- }
fe_sq(t1, t0);
for (i = 1; i < 2; ++i) {
fe_sq(t1, t1);
@@ -917,9 +908,6 @@ static void fe_pow22523(fe out, const fe z) {
fe_mul(t1, z, t1);
fe_mul(t0, t0, t1);
fe_sq(t0, t0);
- for (i = 1; i < 1; ++i) {
- fe_sq(t0, t0);
- }
fe_mul(t0, t1, t0);
fe_sq(t1, t0);
for (i = 1; i < 5; ++i) {
@@ -4625,20 +4613,7 @@ static void sc_muladd(uint8_t *s, const uint8_t *a, const uint8_t *b,
void ED25519_keypair(uint8_t out_public_key[32], uint8_t out_private_key[64]) {
uint8_t seed[32];
RAND_bytes(seed, 32);
-
- uint8_t az[SHA512_DIGEST_LENGTH];
- SHA512(seed, 32, az);
-
- az[0] &= 248;
- az[31] &= 63;
- az[31] |= 64;
-
- ge_p3 A;
- x25519_ge_scalarmult_base(&A, az);
- ge_p3_tobytes(out_public_key, &A);
-
- memcpy(out_private_key, seed, 32);
- memmove(out_private_key + 32, out_public_key, 32);
+ ED25519_keypair_from_seed(out_public_key, out_private_key, seed);
}
int ED25519_sign(uint8_t *out_sig, const uint8_t *message, size_t message_len,
@@ -4712,6 +4687,24 @@ int ED25519_verify(const uint8_t *message, size_t message_len,
return CRYPTO_memcmp(rcheck, rcopy, sizeof(rcheck)) == 0;
}
+void ED25519_keypair_from_seed(uint8_t out_public_key[32],
+ uint8_t out_private_key[64],
+ const uint8_t seed[32]) {
+ uint8_t az[SHA512_DIGEST_LENGTH];
+ SHA512(seed, 32, az);
+
+ az[0] &= 248;
+ az[31] &= 63;
+ az[31] |= 64;
+
+ ge_p3 A;
+ x25519_ge_scalarmult_base(&A, az);
+ ge_p3_tobytes(out_public_key, &A);
+
+ memcpy(out_private_key, seed, 32);
+ memcpy(out_private_key + 32, out_public_key, 32);
+}
+
#if defined(BORINGSSL_X25519_X86_64)
diff --git a/src/crypto/curve25519/ed25519_test.cc b/src/crypto/curve25519/ed25519_test.cc
index 1b6a0b61..5af8ba77 100644
--- a/src/crypto/curve25519/ed25519_test.cc
+++ b/src/crypto/curve25519/ed25519_test.cc
@@ -53,11 +53,30 @@ static bool TestSignature(FileTest *t, void *arg) {
return true;
}
+static bool TestKeypairFromSeed() {
+ uint8_t public_key1[32], private_key1[64];
+ ED25519_keypair(public_key1, private_key1);
+
+ uint8_t seed[32];
+ memcpy(seed, private_key1, sizeof(seed));
+
+ uint8_t public_key2[32], private_key2[64];
+ ED25519_keypair_from_seed(public_key2, private_key2, seed);
+
+ if (memcmp(public_key1, public_key2, sizeof(public_key1)) != 0 ||
+ memcmp(private_key1, private_key2, sizeof(private_key1)) != 0) {
+ fprintf(stderr, "TestKeypairFromSeed: resulting keypairs did not match.\n");
+ return false;
+ }
+
+ return true;
+}
+
int main(int argc, char **argv) {
if (argc != 2) {
fprintf(stderr, "%s <test input.txt>\n", argv[0]);
return 1;
}
- return FileTestMain(TestSignature, nullptr, argv[1]);
+ return TestKeypairFromSeed() && FileTestMain(TestSignature, nullptr, argv[1]);
}
diff --git a/src/crypto/ec/CMakeLists.txt b/src/crypto/ec/CMakeLists.txt
index 4749484e..a54075c3 100644
--- a/src/crypto/ec/CMakeLists.txt
+++ b/src/crypto/ec/CMakeLists.txt
@@ -46,6 +46,15 @@ add_executable(
$<TARGET_OBJECTS:test_support>
)
+add_executable(
+ p256-x86_64_test
+
+ p256-x86_64_test.cc
+
+ $<TARGET_OBJECTS:test_support>
+)
+
target_link_libraries(example_mul crypto)
target_link_libraries(ec_test crypto)
-add_dependencies(all_tests example_mul ec_test)
+target_link_libraries(p256-x86_64_test crypto)
+add_dependencies(all_tests example_mul ec_test p256-x86_64_test)
diff --git a/src/crypto/ec/asm/p256-x86_64-asm.pl b/src/crypto/ec/asm/p256-x86_64-asm.pl
index 0a7d6405..a0b4b182 100755
--- a/src/crypto/ec/asm/p256-x86_64-asm.pl
+++ b/src/crypto/ec/asm/p256-x86_64-asm.pl
@@ -94,6 +94,7 @@ ecp_nistz256_mul_by_2:
push %r13
mov 8*0($a_ptr), $a0
+ xor $t4,$t4
mov 8*1($a_ptr), $a1
add $a0, $a0 # a0:a3+a0:a3
mov 8*2($a_ptr), $a2
@@ -104,7 +105,7 @@ ecp_nistz256_mul_by_2:
adc $a2, $a2
adc $a3, $a3
mov $a1, $t1
- sbb $t4, $t4
+ adc \$0, $t4
sub 8*0($a_ptr), $a0
mov $a2, $t2
@@ -112,14 +113,14 @@ ecp_nistz256_mul_by_2:
sbb 8*2($a_ptr), $a2
mov $a3, $t3
sbb 8*3($a_ptr), $a3
- test $t4, $t4
+ sbb \$0, $t4
- cmovz $t0, $a0
- cmovz $t1, $a1
+ cmovc $t0, $a0
+ cmovc $t1, $a1
mov $a0, 8*0($r_ptr)
- cmovz $t2, $a2
+ cmovc $t2, $a2
mov $a1, 8*1($r_ptr)
- cmovz $t3, $a3
+ cmovc $t3, $a3
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
@@ -1570,13 +1571,14 @@ $code.=<<___;
.type __ecp_nistz256_add_toq,\@abi-omnipotent
.align 32
__ecp_nistz256_add_toq:
+ xor $t4,$t4
add 8*0($b_ptr), $a0
adc 8*1($b_ptr), $a1
mov $a0, $t0
adc 8*2($b_ptr), $a2
adc 8*3($b_ptr), $a3
mov $a1, $t1
- sbb $t4, $t4
+ adc \$0, $t4
sub \$-1, $a0
mov $a2, $t2
@@ -1584,14 +1586,14 @@ __ecp_nistz256_add_toq:
sbb \$0, $a2
mov $a3, $t3
sbb $poly3, $a3
- test $t4, $t4
+ sbb \$0, $t4
- cmovz $t0, $a0
- cmovz $t1, $a1
+ cmovc $t0, $a0
+ cmovc $t1, $a1
mov $a0, 8*0($r_ptr)
- cmovz $t2, $a2
+ cmovc $t2, $a2
mov $a1, 8*1($r_ptr)
- cmovz $t3, $a3
+ cmovc $t3, $a3
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
@@ -1659,13 +1661,14 @@ __ecp_nistz256_subq:
.type __ecp_nistz256_mul_by_2q,\@abi-omnipotent
.align 32
__ecp_nistz256_mul_by_2q:
+ xor $t4, $t4
add $a0, $a0 # a0:a3+a0:a3
adc $a1, $a1
mov $a0, $t0
adc $a2, $a2
adc $a3, $a3
mov $a1, $t1
- sbb $t4, $t4
+ adc \$0, $t4
sub \$-1, $a0
mov $a2, $t2
@@ -1673,14 +1676,14 @@ __ecp_nistz256_mul_by_2q:
sbb \$0, $a2
mov $a3, $t3
sbb $poly3, $a3
- test $t4, $t4
+ sbb \$0, $t4
- cmovz $t0, $a0
- cmovz $t1, $a1
+ cmovc $t0, $a0
+ cmovc $t1, $a1
mov $a0, 8*0($r_ptr)
- cmovz $t2, $a2
+ cmovc $t2, $a2
mov $a1, 8*1($r_ptr)
- cmovz $t3, $a3
+ cmovc $t3, $a3
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
@@ -1971,16 +1974,14 @@ $code.=<<___;
mov $b_org, $a_ptr # reassign
movdqa %xmm0, $in1_x(%rsp)
movdqa %xmm1, $in1_x+0x10(%rsp)
- por %xmm0, %xmm1
movdqa %xmm2, $in1_y(%rsp)
movdqa %xmm3, $in1_y+0x10(%rsp)
- por %xmm2, %xmm3
movdqa %xmm4, $in1_z(%rsp)
movdqa %xmm5, $in1_z+0x10(%rsp)
- por %xmm1, %xmm3
+ por %xmm4, %xmm5
movdqu 0x00($a_ptr), %xmm0 # copy *(P256_POINT *)$b_ptr
- pshufd \$0xb1, %xmm3, %xmm5
+ pshufd \$0xb1, %xmm5, %xmm3
movdqu 0x10($a_ptr), %xmm1
movdqu 0x20($a_ptr), %xmm2
por %xmm3, %xmm5
@@ -1992,14 +1993,14 @@ $code.=<<___;
movdqa %xmm0, $in2_x(%rsp)
pshufd \$0x1e, %xmm5, %xmm4
movdqa %xmm1, $in2_x+0x10(%rsp)
- por %xmm0, %xmm1
- movq $r_ptr, %xmm0 # save $r_ptr
+ movdqu 0x40($a_ptr),%xmm0 # in2_z again
+ movdqu 0x50($a_ptr),%xmm1
movdqa %xmm2, $in2_y(%rsp)
movdqa %xmm3, $in2_y+0x10(%rsp)
- por %xmm2, %xmm3
por %xmm4, %xmm5
pxor %xmm4, %xmm4
- por %xmm1, %xmm3
+ por %xmm0, %xmm1
+ movq $r_ptr, %xmm0 # save $r_ptr
lea 0x40-$bias($a_ptr), $a_ptr # $a_ptr is still valid
mov $src0, $in2_z+8*0(%rsp) # make in2_z copy
@@ -2010,8 +2011,8 @@ $code.=<<___;
call __ecp_nistz256_sqr_mont$x # p256_sqr_mont(Z2sqr, in2_z);
pcmpeqd %xmm4, %xmm5
- pshufd \$0xb1, %xmm3, %xmm4
- por %xmm3, %xmm4
+ pshufd \$0xb1, %xmm1, %xmm4
+ por %xmm1, %xmm4
pshufd \$0, %xmm5, %xmm5 # in1infty
pshufd \$0x1e, %xmm4, %xmm3
por %xmm3, %xmm4
@@ -2135,6 +2136,7 @@ $code.=<<___;
#lea $Hsqr(%rsp), $r_ptr # 2*U1*H^2
#call __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
+ xor $t4, $t4
add $acc0, $acc0 # a0:a3+a0:a3
lea $Rsqr(%rsp), $a_ptr
adc $acc1, $acc1
@@ -2142,7 +2144,7 @@ $code.=<<___;
adc $acc2, $acc2
adc $acc3, $acc3
mov $acc1, $t1
- sbb $t4, $t4
+ adc \$0, $t4
sub \$-1, $acc0
mov $acc2, $t2
@@ -2150,15 +2152,15 @@ $code.=<<___;
sbb \$0, $acc2
mov $acc3, $t3
sbb $poly3, $acc3
- test $t4, $t4
+ sbb \$0, $t4
- cmovz $t0, $acc0
+ cmovc $t0, $acc0
mov 8*0($a_ptr), $t0
- cmovz $t1, $acc1
+ cmovc $t1, $acc1
mov 8*1($a_ptr), $t1
- cmovz $t2, $acc2
+ cmovc $t2, $acc2
mov 8*2($a_ptr), $t2
- cmovz $t3, $acc3
+ cmovc $t3, $acc3
mov 8*3($a_ptr), $t3
call __ecp_nistz256_sub$x # p256_sub(res_x, Rsqr, Hsqr);
@@ -2342,16 +2344,14 @@ $code.=<<___;
mov 0x40+8*3($a_ptr), $acc0
movdqa %xmm0, $in1_x(%rsp)
movdqa %xmm1, $in1_x+0x10(%rsp)
- por %xmm0, %xmm1
movdqa %xmm2, $in1_y(%rsp)
movdqa %xmm3, $in1_y+0x10(%rsp)
- por %xmm2, %xmm3
movdqa %xmm4, $in1_z(%rsp)
movdqa %xmm5, $in1_z+0x10(%rsp)
- por %xmm1, %xmm3
+ por %xmm4, %xmm5
movdqu 0x00($b_ptr), %xmm0 # copy *(P256_POINT_AFFINE *)$b_ptr
- pshufd \$0xb1, %xmm3, %xmm5
+ pshufd \$0xb1, %xmm5, %xmm3
movdqu 0x10($b_ptr), %xmm1
movdqu 0x20($b_ptr), %xmm2
por %xmm3, %xmm5
@@ -2440,6 +2440,7 @@ $code.=<<___;
#lea $Hsqr(%rsp), $r_ptr # 2*U1*H^2
#call __ecp_nistz256_mul_by_2 # ecp_nistz256_mul_by_2(Hsqr, U2);
+ xor $t4, $t4
add $acc0, $acc0 # a0:a3+a0:a3
lea $Rsqr(%rsp), $a_ptr
adc $acc1, $acc1
@@ -2447,7 +2448,7 @@ $code.=<<___;
adc $acc2, $acc2
adc $acc3, $acc3
mov $acc1, $t1
- sbb $t4, $t4
+ adc \$0, $t4
sub \$-1, $acc0
mov $acc2, $t2
@@ -2455,15 +2456,15 @@ $code.=<<___;
sbb \$0, $acc2
mov $acc3, $t3
sbb $poly3, $acc3
- test $t4, $t4
+ sbb \$0, $t4
- cmovz $t0, $acc0
+ cmovc $t0, $acc0
mov 8*0($a_ptr), $t0
- cmovz $t1, $acc1
+ cmovc $t1, $acc1
mov 8*1($a_ptr), $t1
- cmovz $t2, $acc2
+ cmovc $t2, $acc2
mov 8*2($a_ptr), $t2
- cmovz $t3, $acc3
+ cmovc $t3, $acc3
mov 8*3($a_ptr), $t3
call __ecp_nistz256_sub$x # p256_sub(res_x, Rsqr, Hsqr);
@@ -2615,14 +2616,14 @@ __ecp_nistz256_add_tox:
sbb \$0, $a2
mov $a3, $t3
sbb $poly3, $a3
+ sbb \$0, $t4
- bt \$0, $t4
- cmovnc $t0, $a0
- cmovnc $t1, $a1
+ cmovc $t0, $a0
+ cmovc $t1, $a1
mov $a0, 8*0($r_ptr)
- cmovnc $t2, $a2
+ cmovc $t2, $a2
mov $a1, 8*1($r_ptr)
- cmovnc $t3, $a3
+ cmovc $t3, $a3
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
@@ -2710,14 +2711,14 @@ __ecp_nistz256_mul_by_2x:
sbb \$0, $a2
mov $a3, $t3
sbb $poly3, $a3
+ sbb \$0, $t4
- bt \$0, $t4
- cmovnc $t0, $a0
- cmovnc $t1, $a1
+ cmovc $t0, $a0
+ cmovc $t1, $a1
mov $a0, 8*0($r_ptr)
- cmovnc $t2, $a2
+ cmovc $t2, $a2
mov $a1, 8*1($r_ptr)
- cmovnc $t3, $a3
+ cmovc $t3, $a3
mov $a2, 8*2($r_ptr)
mov $a3, 8*3($r_ptr)
diff --git a/src/crypto/ec/ec_test.cc b/src/crypto/ec/ec_test.cc
index 839acfeb..31619b1e 100644
--- a/src/crypto/ec/ec_test.cc
+++ b/src/crypto/ec/ec_test.cc
@@ -26,8 +26,6 @@
#include <openssl/nid.h>
-namespace bssl {
-
// kECKeyWithoutPublic is an ECPrivateKey with the optional publicKey field
// omitted.
static const uint8_t kECKeyWithoutPublic[] = {
@@ -112,7 +110,7 @@ static bssl::UniquePtr<EC_KEY> DecodeECPrivateKey(const uint8_t *in,
// EncodeECPrivateKey encodes |key| as an ECPrivateKey structure into |*out|. It
// returns true on success or false on error.
static bool EncodeECPrivateKey(std::vector<uint8_t> *out, const EC_KEY *key) {
- ScopedCBB cbb;
+ bssl::ScopedCBB cbb;
uint8_t *der;
size_t der_len;
if (!CBB_init(cbb.get(), 0) ||
@@ -459,6 +457,51 @@ static bool TestAddingEqualPoints(int nid) {
return true;
}
+static bool TestMulZero(int nid) {
+ bssl::UniquePtr<EC_GROUP> group(EC_GROUP_new_by_curve_name(nid));
+ if (!group) {
+ return false;
+ }
+
+ bssl::UniquePtr<EC_POINT> point(EC_POINT_new(group.get()));
+ bssl::UniquePtr<BIGNUM> zero(BN_new());
+ if (!point || !zero) {
+ return false;
+ }
+
+ BN_zero(zero.get());
+ if (!EC_POINT_mul(group.get(), point.get(), zero.get(), nullptr, nullptr,
+ nullptr)) {
+ return false;
+ }
+
+ if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
+ fprintf(stderr, "g * 0 did not return point at infinity.\n");
+ return false;
+ }
+
+ // Test that zero times an arbitrary point is also infinity. The generator is
+ // used as the arbitrary point.
+ bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get()));
+ bssl::UniquePtr<BIGNUM> one(BN_new());
+ if (!generator ||
+ !one ||
+ !BN_one(one.get()) ||
+ !EC_POINT_mul(group.get(), generator.get(), one.get(), nullptr, nullptr,
+ nullptr) ||
+ !EC_POINT_mul(group.get(), point.get(), nullptr, generator.get(),
+ zero.get(), nullptr)) {
+ return false;
+ }
+
+ if (!EC_POINT_is_at_infinity(group.get(), point.get())) {
+ fprintf(stderr, "p * 0 did not return point at infinity.\n");
+ return false;
+ }
+
+ return true;
+}
+
static bool ForEachCurve(bool (*test_func)(int nid)) {
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
std::vector<EC_builtin_curve> curves(num_curves);
@@ -474,7 +517,7 @@ static bool ForEachCurve(bool (*test_func)(int nid)) {
return true;
}
-static int Main() {
+int main() {
CRYPTO_library_init();
if (!Testd2i_ECPrivateKey() ||
@@ -482,6 +525,7 @@ static int Main() {
!TestSpecifiedCurve() ||
!ForEachCurve(TestSetAffine) ||
!ForEachCurve(TestAddingEqualPoints) ||
+ !ForEachCurve(TestMulZero) ||
!TestArbitraryCurve()) {
fprintf(stderr, "failed\n");
return 1;
@@ -490,9 +534,3 @@ static int Main() {
printf("PASS\n");
return 0;
}
-
-} // namespace bssl
-
-int main() {
- return bssl::Main();
-}
diff --git a/src/crypto/ec/p256-x86_64.c b/src/crypto/ec/p256-x86_64.c
index a5906e45..0a3be92a 100644
--- a/src/crypto/ec/p256-x86_64.c
+++ b/src/crypto/ec/p256-x86_64.c
@@ -31,56 +31,16 @@
#include <openssl/err.h>
#include "../bn/internal.h"
-#include "../ec/internal.h"
#include "../internal.h"
+#include "internal.h"
+#include "p256-x86_64.h"
#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
!defined(OPENSSL_SMALL)
-
-#define P256_LIMBS (256 / BN_BITS2)
-
-typedef struct {
- BN_ULONG X[P256_LIMBS];
- BN_ULONG Y[P256_LIMBS];
- BN_ULONG Z[P256_LIMBS];
-} P256_POINT;
-
-typedef struct {
- BN_ULONG X[P256_LIMBS];
- BN_ULONG Y[P256_LIMBS];
-} P256_POINT_AFFINE;
-
typedef P256_POINT_AFFINE PRECOMP256_ROW[64];
-/* Arithmetic on field elements using Almost Montgomery Multiplication. The
- * "almost" means, in particular, that the inputs and outputs of these
- * functions are in the range [0, 2**BN_BITS2), not [0, P). Only
- * |ecp_nistz256_from_mont| outputs a fully reduced value in [0, P). Almost
- * Montgomery Arithmetic is described clearly in "Efficient Software
- * Implementations of Modular Exponentiation" by Shay Gueron. */
-
-/* Modular neg: res = -a mod P, where res is not fully reduced. */
-void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]);
-/* Montgomery mul: res = a*b*2^-256 mod P, where res is not fully reduced. */
-void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS],
- const BN_ULONG a[P256_LIMBS],
- const BN_ULONG b[P256_LIMBS]);
-/* Montgomery sqr: res = a*a*2^-256 mod P, where res is not fully reduced. */
-void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS],
- const BN_ULONG a[P256_LIMBS]);
-/* Convert a number from Montgomery domain, by multiplying with 1, where res
- * will be fully reduced mod P. */
-void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
- const BN_ULONG in[P256_LIMBS]);
-
-
-/* Functions that perform constant time access to the precomputed tables */
-void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT *in_t, int index);
-void ecp_nistz256_select_w7(P256_POINT_AFFINE *val,
- const P256_POINT_AFFINE *in_t, int index);
-
/* One converted into the Montgomery domain */
static const BN_ULONG ONE[P256_LIMBS] = {
TOBN(0x00000000, 0x00000001), TOBN(0xffffffff, 0x00000000),
@@ -90,7 +50,7 @@ static const BN_ULONG ONE[P256_LIMBS] = {
/* Precomputed tables for the default generator */
#include "p256-x86_64-table.h"
-/* Recode window to a signed digit, see ecp_nistputil.c for details */
+/* Recode window to a signed digit, see util-64.c for details */
static unsigned booth_recode_w5(unsigned in) {
unsigned s, d;
@@ -113,6 +73,11 @@ static unsigned booth_recode_w7(unsigned in) {
return (d << 1) + (s & 1);
}
+/* copy_conditional copies |src| to |dst| if |move| is one and leaves it as-is
+ * if |move| is zero.
+ *
+ * WARNING: this breaks the usual convention of constant-time functions
+ * returning masks. */
static void copy_conditional(BN_ULONG dst[P256_LIMBS],
const BN_ULONG src[P256_LIMBS], BN_ULONG move) {
BN_ULONG mask1 = ((BN_ULONG)0) - move;
@@ -130,15 +95,34 @@ static void copy_conditional(BN_ULONG dst[P256_LIMBS],
}
}
-void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a);
-void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a,
- const P256_POINT *b);
-void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a,
- const P256_POINT_AFFINE *b);
+/* is_not_zero returns one iff in != 0 and zero otherwise.
+ *
+ * WARNING: this breaks the usual convention of constant-time functions
+ * returning masks.
+ *
+ * (define-fun is_not_zero ((in (_ BitVec 64))) (_ BitVec 64)
+ * (bvlshr (bvor in (bvsub #x0000000000000000 in)) #x000000000000003f)
+ * )
+ *
+ * (declare-fun x () (_ BitVec 64))
+ *
+ * (assert (and (= x #x0000000000000000) (= (is_not_zero x) #x0000000000000001)))
+ * (check-sat)
+ *
+ * (assert (and (not (= x #x0000000000000000)) (= (is_not_zero x) #x0000000000000000)))
+ * (check-sat)
+ * */
+static BN_ULONG is_not_zero(BN_ULONG in) {
+ in |= (0 - in);
+ in >>= BN_BITS2 - 1;
+ return in;
+}
-/* r = in^-1 mod p */
-static void ecp_nistz256_mod_inverse(BN_ULONG r[P256_LIMBS],
- const BN_ULONG in[P256_LIMBS]) {
+/* ecp_nistz256_mod_inverse_mont sets |r| to (|in| * 2^-256)^-1 * 2^256 mod p.
+ * That is, |r| is the modular inverse of |in| for input and output in the
+ * Montgomery domain. */
+static void ecp_nistz256_mod_inverse_mont(BN_ULONG r[P256_LIMBS],
+ const BN_ULONG in[P256_LIMBS]) {
/* The poly is ffffffff 00000001 00000000 00000000 00000000 ffffffff ffffffff
ffffffff
We use FLT and used poly-2 as exponent */
@@ -454,7 +438,11 @@ static int ecp_nistz256_points_mul(
ecp_nistz256_neg(p.p.Z, p.p.Y);
copy_conditional(p.p.Y, p.p.Z, wvalue & 1);
- memcpy(p.p.Z, ONE, sizeof(ONE));
+ /* Convert |p| from affine to Jacobian coordinates. We set Z to zero if |p|
+ * is infinity and |ONE| otherwise. |p| was computed from the table, so it
+ * is infinity iff |wvalue >> 1| is zero. */
+ memset(p.p.Z, 0, sizeof(p.p.Z));
+ copy_conditional(p.p.Z, ONE, is_not_zero(wvalue >> 1));
for (i = 1; i < 37; i++) {
unsigned off = (index - 1) / 8;
@@ -524,13 +512,11 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point,
return 0;
}
- ecp_nistz256_mod_inverse(z_inv3, point_z);
+ ecp_nistz256_mod_inverse_mont(z_inv3, point_z);
ecp_nistz256_sqr_mont(z_inv2, z_inv3);
- /* Unlike the |BN_mod_mul_montgomery|-based implementation, we cannot factor
- * out the two calls to |ecp_nistz256_from_mont| into one call, because
- * |ecp_nistz256_from_mont| must be the last operation to ensure that the
- * result is fully reduced mod P. */
+ /* TODO(davidben): The two calls to |ecp_nistz256_from_mont| may be factored
+ * into one call now that other operations also reduce mod P. */
if (x != NULL) {
BN_ULONG x_aff[P256_LIMBS];
diff --git a/src/crypto/ec/p256-x86_64.h b/src/crypto/ec/p256-x86_64.h
new file mode 100644
index 00000000..9897699f
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2014, Intel Corporation.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_EC_P256_X86_64_H
+#define OPENSSL_HEADER_EC_P256_X86_64_H
+
+#include <openssl/base.h>
+
+#include <openssl/bn.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+ !defined(OPENSSL_SMALL)
+
+/* P-256 field operations.
+ *
+ * An element mod P in P-256 is represented as a little-endian array of
+ * |P256_LIMBS| |BN_ULONG|s, spanning the full range of values.
+ *
+ * The following functions take fully-reduced inputs mod P and give
+ * fully-reduced outputs. They may be used in-place. */
+
+#define P256_LIMBS (256 / BN_BITS2)
+
+/* ecp_nistz256_neg sets |res| to -|a| mod P. */
+void ecp_nistz256_neg(BN_ULONG res[P256_LIMBS], const BN_ULONG a[P256_LIMBS]);
+
+/* ecp_nistz256_mul_mont sets |res| to |a| * |b| * 2^-256 mod P. */
+void ecp_nistz256_mul_mont(BN_ULONG res[P256_LIMBS],
+ const BN_ULONG a[P256_LIMBS],
+ const BN_ULONG b[P256_LIMBS]);
+
+/* ecp_nistz256_sqr_mont sets |res| to |a| * |a| * 2^-256 mod P. */
+void ecp_nistz256_sqr_mont(BN_ULONG res[P256_LIMBS],
+ const BN_ULONG a[P256_LIMBS]);
+
+/* ecp_nistz256_from_mont sets |res| to |in|, converted from Montgomery domain
+ * by multiplying with 1. */
+void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
+ const BN_ULONG in[P256_LIMBS]);
+
+
+/* P-256 point operations.
+ *
+ * The following functions may be used in-place. All coordinates are in the
+ * Montgomery domain. */
+
+/* A P256_POINT represents a P-256 point in Jacobian coordinates. */
+typedef struct {
+ BN_ULONG X[P256_LIMBS];
+ BN_ULONG Y[P256_LIMBS];
+ BN_ULONG Z[P256_LIMBS];
+} P256_POINT;
+
+/* A P256_POINT_AFFINE represents a P-256 point in affine coordinates. Infinity
+ * is encoded as (0, 0). */
+typedef struct {
+ BN_ULONG X[P256_LIMBS];
+ BN_ULONG Y[P256_LIMBS];
+} P256_POINT_AFFINE;
+
+/* ecp_nistz256_select_w5 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 16
+ * and all zeros (the point at infinity) if |index| is 0. This is done in
+ * constant time. */
+void ecp_nistz256_select_w5(P256_POINT *val, const P256_POINT in_t[16],
+ int index);
+
+/* ecp_nistz256_select_w7 sets |*val| to |in_t[index-1]| if 1 <= |index| <= 64
+ * and all zeros (the point at infinity) if |index| is 0. This is done in
+ * constant time. */
+void ecp_nistz256_select_w7(P256_POINT_AFFINE *val,
+ const P256_POINT_AFFINE in_t[64], int index);
+
+/* ecp_nistz256_point_double sets |r| to |a| doubled. */
+void ecp_nistz256_point_double(P256_POINT *r, const P256_POINT *a);
+
+/* ecp_nistz256_point_add adds |a| to |b| and places the result in |r|. */
+void ecp_nistz256_point_add(P256_POINT *r, const P256_POINT *a,
+ const P256_POINT *b);
+
+/* ecp_nistz256_point_add_affine adds |a| to |b| and places the result in
+ * |r|. |a| and |b| must not represent the same point unless they are both
+ * infinity. */
+void ecp_nistz256_point_add_affine(P256_POINT *r, const P256_POINT *a,
+ const P256_POINT_AFFINE *b);
+
+#endif /* !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+ !defined(OPENSSL_SMALL) */
+
+
+#if defined(__cplusplus)
+} /* extern C++ */
+#endif
+
+#endif /* OPENSSL_HEADER_EC_P256_X86_64_H */
diff --git a/src/crypto/ec/p256-x86_64_test.cc b/src/crypto/ec/p256-x86_64_test.cc
new file mode 100644
index 00000000..531edcf3
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64_test.cc
@@ -0,0 +1,508 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#if !defined(__STDC_FORMAT_MACROS)
+#define __STDC_FORMAT_MACROS
+#endif
+
+#include <openssl/base.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/mem.h>
+
+#include "../bn/internal.h"
+#include "../test/file_test.h"
+#include "p256-x86_64.h"
+
+
+// Disable tests if BORINGSSL_SHARED_LIBRARY is defined. These tests need access
+// to internal functions.
+#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
+ !defined(OPENSSL_SMALL) && !defined(BORINGSSL_SHARED_LIBRARY)
+
+static bool TestSelectW5() {
+ // Fill a table with some garbage input.
+ P256_POINT table[16];
+ for (size_t i = 0; i < 16; i++) {
+ memset(table[i].X, 3 * i, sizeof(table[i].X));
+ memset(table[i].Y, 3 * i + 1, sizeof(table[i].Y));
+ memset(table[i].Z, 3 * i + 2, sizeof(table[i].Z));
+ }
+
+ for (int i = 0; i <= 16; i++) {
+ P256_POINT val;
+ ecp_nistz256_select_w5(&val, table, i);
+
+ P256_POINT expected;
+ if (i == 0) {
+ memset(&expected, 0, sizeof(expected));
+ } else {
+ expected = table[i-1];
+ }
+
+ if (memcmp(&val, &expected, sizeof(P256_POINT)) != 0) {
+ fprintf(stderr, "ecp_nistz256_select_w5(%d) gave the wrong value.\n", i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestSelectW7() {
+ // Fill a table with some garbage input.
+ P256_POINT_AFFINE table[64];
+ for (size_t i = 0; i < 64; i++) {
+ memset(table[i].X, 2 * i, sizeof(table[i].X));
+ memset(table[i].Y, 2 * i + 1, sizeof(table[i].Y));
+ }
+
+ for (int i = 0; i <= 64; i++) {
+ P256_POINT_AFFINE val;
+ ecp_nistz256_select_w7(&val, table, i);
+
+ P256_POINT_AFFINE expected;
+ if (i == 0) {
+ memset(&expected, 0, sizeof(expected));
+ } else {
+ expected = table[i-1];
+ }
+
+ if (memcmp(&val, &expected, sizeof(P256_POINT_AFFINE)) != 0) {
+ fprintf(stderr, "ecp_nistz256_select_w7(%d) gave the wrong value.\n", i);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool GetFieldElement(FileTest *t, BN_ULONG out[P256_LIMBS],
+ const char *name) {
+ std::vector<uint8_t> bytes;
+ if (!t->GetBytes(&bytes, name)) {
+ return false;
+ }
+
+ if (bytes.size() != BN_BYTES * P256_LIMBS) {
+ t->PrintLine("Invalid length: %s", name);
+ return false;
+ }
+
+ // |byte| contains bytes in big-endian while |out| should contain |BN_ULONG|s
+ // in little-endian.
+ memset(out, 0, P256_LIMBS * sizeof(BN_ULONG));
+ for (size_t i = 0; i < bytes.size(); i++) {
+ out[P256_LIMBS - 1 - (i / BN_BYTES)] <<= 8;
+ out[P256_LIMBS - 1 - (i / BN_BYTES)] |= bytes[i];
+ }
+
+ return true;
+}
+
+static std::string FieldElementToString(const BN_ULONG a[P256_LIMBS]) {
+ std::string ret;
+ for (size_t i = P256_LIMBS-1; i < P256_LIMBS; i--) {
+ char buf[2 * BN_BYTES + 1];
+ BIO_snprintf(buf, sizeof(buf), BN_HEX_FMT2, a[i]);
+ ret += buf;
+ }
+ return ret;
+}
+
+static bool ExpectFieldElementsEqual(FileTest *t, const char *message,
+ const BN_ULONG expected[P256_LIMBS],
+ const BN_ULONG actual[P256_LIMBS]) {
+ if (memcmp(expected, actual, sizeof(BN_ULONG) * P256_LIMBS) == 0) {
+ return true;
+ }
+
+ t->PrintLine("%s", message);
+ t->PrintLine("Expected: %s", FieldElementToString(expected).c_str());
+ t->PrintLine("Actual: %s", FieldElementToString(actual).c_str());
+ return false;
+}
+
+static bool PointToAffine(P256_POINT_AFFINE *out, const P256_POINT *in) {
+ static const uint8_t kP[] = {
+ 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ };
+
+ bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), z(BN_new());
+ bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr));
+ if (!x || !y || !z || !p ||
+ !bn_set_words(x.get(), in->X, P256_LIMBS) ||
+ !bn_set_words(y.get(), in->Y, P256_LIMBS) ||
+ !bn_set_words(z.get(), in->Z, P256_LIMBS)) {
+ return false;
+ }
+
+ // Coordinates must be fully-reduced.
+ if (BN_cmp(x.get(), p.get()) >= 0 ||
+ BN_cmp(y.get(), p.get()) >= 0 ||
+ BN_cmp(z.get(), p.get()) >= 0) {
+ return false;
+ }
+
+ memset(out, 0, sizeof(P256_POINT_AFFINE));
+
+ if (BN_is_zero(z.get())) {
+ // The point at infinity is represented as (0, 0).
+ return true;
+ }
+
+ bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new());
+ bssl::UniquePtr<BN_MONT_CTX> mont(BN_MONT_CTX_new());
+ if (!ctx || !mont ||
+ !BN_MONT_CTX_set(mont.get(), p.get(), ctx.get()) ||
+ // Invert Z.
+ !BN_from_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
+ !BN_mod_inverse(z.get(), z.get(), p.get(), ctx.get()) ||
+ !BN_to_montgomery(z.get(), z.get(), mont.get(), ctx.get()) ||
+ // Convert (X, Y, Z) to (X/Z^2, Y/Z^3).
+ !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
+ ctx.get()) ||
+ !BN_mod_mul_montgomery(x.get(), x.get(), z.get(), mont.get(),
+ ctx.get()) ||
+ !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+ ctx.get()) ||
+ !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+ ctx.get()) ||
+ !BN_mod_mul_montgomery(y.get(), y.get(), z.get(), mont.get(),
+ ctx.get())) {
+ return false;
+ }
+
+ memcpy(out->X, x->d, sizeof(BN_ULONG) * x->top);
+ memcpy(out->Y, y->d, sizeof(BN_ULONG) * y->top);
+ return true;
+}
+
+static bool ExpectPointsEqual(FileTest *t, const char *message,
+ const P256_POINT_AFFINE *expected,
+ const P256_POINT *point) {
+ // There are multiple representations of the same |P256_POINT|, so convert to
+ // |P256_POINT_AFFINE| and compare.
+ P256_POINT_AFFINE affine;
+ if (!PointToAffine(&affine, point)) {
+ t->PrintLine("%s", message);
+ t->PrintLine("Could not convert to affine: (%s, %s, %s)",
+ FieldElementToString(point->X).c_str(),
+ FieldElementToString(point->Y).c_str(),
+ FieldElementToString(point->Z).c_str());
+ return false;
+ }
+
+ if (memcmp(expected, &affine, sizeof(P256_POINT_AFFINE)) != 0) {
+ t->PrintLine("%s", message);
+ t->PrintLine("Expected: (%s, %s)",
+ FieldElementToString(expected->X).c_str(),
+ FieldElementToString(expected->Y).c_str());
+ t->PrintLine("Actual: (%s, %s)", FieldElementToString(affine.X).c_str(),
+ FieldElementToString(affine.Y).c_str());
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestNegate(FileTest *t) {
+ BN_ULONG a[P256_LIMBS], b[P256_LIMBS];
+ if (!GetFieldElement(t, a, "A") ||
+ !GetFieldElement(t, b, "B")) {
+ return false;
+ }
+
+ // Test that -A = B.
+ BN_ULONG ret[P256_LIMBS];
+ ecp_nistz256_neg(ret, a);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(A) was incorrect.", b,
+ ret)) {
+ return false;
+ }
+
+ memcpy(ret, a, sizeof(ret));
+ ecp_nistz256_neg(ret, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "In-place ecp_nistz256_neg(A) was incorrect.", b, ret)) {
+ return false;
+ }
+
+ // Test that -B = A.
+ ecp_nistz256_neg(ret, b);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_neg(B) was incorrect.", a,
+ ret)) {
+ return false;
+ }
+
+ memcpy(ret, b, sizeof(ret));
+ ecp_nistz256_neg(ret, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "In-place ecp_nistz256_neg(B) was incorrect.", a, ret)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestMulMont(FileTest *t) {
+ BN_ULONG a[P256_LIMBS], b[P256_LIMBS], result[P256_LIMBS];
+ if (!GetFieldElement(t, a, "A") ||
+ !GetFieldElement(t, b, "B") ||
+ !GetFieldElement(t, result, "Result")) {
+ return false;
+ }
+
+ BN_ULONG ret[P256_LIMBS];
+ ecp_nistz256_mul_mont(ret, a, b);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(A, B) was incorrect.",
+ result, ret)) {
+ return false;
+ }
+
+ ecp_nistz256_mul_mont(ret, b, a);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_mul_mont(B, A) was incorrect.",
+ result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, a, sizeof(ret));
+ ecp_nistz256_mul_mont(ret, ret, b);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_mul_mont(ret = A, B) was incorrect.", result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, a, sizeof(ret));
+ ecp_nistz256_mul_mont(ret, b, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_mul_mont(B, ret = A) was incorrect.", result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, b, sizeof(ret));
+ ecp_nistz256_mul_mont(ret, a, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_mul_mont(A, ret = B) was incorrect.", result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, b, sizeof(ret));
+ ecp_nistz256_mul_mont(ret, ret, a);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_mul_mont(ret = B, A) was incorrect.", result, ret)) {
+ return false;
+ }
+
+ if (memcmp(a, b, sizeof(a)) == 0) {
+ ecp_nistz256_sqr_mont(ret, a);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_sqr_mont(A) was incorrect.",
+ result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, a, sizeof(ret));
+ ecp_nistz256_sqr_mont(ret, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_sqr_mont(ret = A) was incorrect.", result, ret)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestFromMont(FileTest *t) {
+ BN_ULONG a[P256_LIMBS], result[P256_LIMBS];
+ if (!GetFieldElement(t, a, "A") ||
+ !GetFieldElement(t, result, "Result")) {
+ return false;
+ }
+
+ BN_ULONG ret[P256_LIMBS];
+ ecp_nistz256_from_mont(ret, a);
+ if (!ExpectFieldElementsEqual(t, "ecp_nistz256_from_mont(A) was incorrect.",
+ result, ret)) {
+ return false;
+ }
+
+ memcpy(ret, a, sizeof(ret));
+ ecp_nistz256_from_mont(ret, ret);
+ if (!ExpectFieldElementsEqual(
+ t, "ecp_nistz256_from_mont(ret = A) was incorrect.", result, ret)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestPointAdd(FileTest *t) {
+ P256_POINT a, b;
+ P256_POINT_AFFINE result;
+ if (!GetFieldElement(t, a.X, "A.X") ||
+ !GetFieldElement(t, a.Y, "A.Y") ||
+ !GetFieldElement(t, a.Z, "A.Z") ||
+ !GetFieldElement(t, b.X, "B.X") ||
+ !GetFieldElement(t, b.Y, "B.Y") ||
+ !GetFieldElement(t, b.Z, "B.Z") ||
+ !GetFieldElement(t, result.X, "Result.X") ||
+ !GetFieldElement(t, result.Y, "Result.Y")) {
+ return false;
+ }
+
+ P256_POINT ret;
+ ecp_nistz256_point_add(&ret, &a, &b);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(A, B) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ ecp_nistz256_point_add(&ret, &b, &a);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &a, sizeof(ret));
+ ecp_nistz256_point_add(&ret, &ret, &b);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &a, sizeof(ret));
+ ecp_nistz256_point_add(&ret, &b, &ret);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(B, ret = A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &b, sizeof(ret));
+ ecp_nistz256_point_add(&ret, &a, &ret);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = A, B) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &b, sizeof(ret));
+ ecp_nistz256_point_add(&ret, &ret, &a);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_add(ret = B, A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ P256_POINT_AFFINE a_affine, b_affine, infinity;
+ memset(&infinity, 0, sizeof(infinity));
+ if (!PointToAffine(&a_affine, &a) ||
+ !PointToAffine(&b_affine, &b)) {
+ return false;
+ }
+
+ // ecp_nistz256_point_add_affine does not work when a == b unless doubling the
+ // point at infinity.
+ if (memcmp(&a_affine, &b_affine, sizeof(a_affine)) != 0 ||
+ memcmp(&a_affine, &infinity, sizeof(a_affine)) == 0) {
+ ecp_nistz256_point_add_affine(&ret, &a, &b_affine);
+ if (!ExpectPointsEqual(t,
+ "ecp_nistz256_point_add_affine(A, B) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &a, sizeof(ret));
+ ecp_nistz256_point_add_affine(&ret, &ret, &b_affine);
+ if (!ExpectPointsEqual(
+ t, "ecp_nistz256_point_add_affine(ret = A, B) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ ecp_nistz256_point_add_affine(&ret, &b, &a_affine);
+ if (!ExpectPointsEqual(t,
+ "ecp_nistz256_point_add_affine(B, A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ memcpy(&ret, &b, sizeof(ret));
+ ecp_nistz256_point_add_affine(&ret, &ret, &a_affine);
+ if (!ExpectPointsEqual(
+ t, "ecp_nistz256_point_add_affine(ret = B, A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+ }
+
+ if (memcmp(&a, &b, sizeof(a)) == 0) {
+ ecp_nistz256_point_double(&ret, &a);
+ if (!ExpectPointsEqual(t, "ecp_nistz256_point_double(A) was incorrect.",
+ &result, &ret)) {
+ return false;
+ }
+
+ ret = a;
+ ecp_nistz256_point_double(&ret, &ret);
+ if (!ExpectPointsEqual(
+ t, "In-place ecp_nistz256_point_double(A) was incorrect.", &result,
+ &ret)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ fprintf(stderr, "%s TEST_FILE\n", argv[0]);
+ return 1;
+ }
+
+ if (!TestSelectW5() ||
+ !TestSelectW7()) {
+ return 1;
+ }
+
+ return FileTestMain([](FileTest *t, void *) -> bool {
+ if (t->GetParameter() == "Negate") {
+ return TestNegate(t);
+ }
+ if (t->GetParameter() == "MulMont") {
+ return TestMulMont(t);
+ }
+ if (t->GetParameter() == "FromMont") {
+ return TestFromMont(t);
+ }
+ if (t->GetParameter() == "PointAdd") {
+ return TestPointAdd(t);
+ }
+
+ t->PrintLine("Unknown test type: %s", t->GetParameter().c_str());
+ return false;
+ }, nullptr, argv[1]);
+}
+
+#else
+
+int main() {
+ printf("PASS\n");
+ return 0;
+}
+
+#endif
diff --git a/src/crypto/ec/p256-x86_64_tests.txt b/src/crypto/ec/p256-x86_64_tests.txt
new file mode 100644
index 00000000..a680850f
--- /dev/null
+++ b/src/crypto/ec/p256-x86_64_tests.txt
@@ -0,0 +1,1405 @@
+# Negation tests.
+#
+# The following tests satisfy A = -B (mod P).
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000000
+B = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000001
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffffe
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000003
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffffc
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000007
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffff8
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000000f
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffff0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000001f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffffe0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000003f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffffc0
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000007f
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffff80
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000000ff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffff00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000001ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffe00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000003ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffffc00
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000007ff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffff800
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000000fff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffff000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000001fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffe000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000003fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffffc000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000007fff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffff8000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000000ffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffff0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000001ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffe0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000003ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffffc0000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000007ffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffff80000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000000fffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffff00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000001fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffe00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000003fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffffc00000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000007fffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffff800000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000000ffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffff000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000001ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffe000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000003ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffffc000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000007ffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffff8000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000000fffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffff0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000001fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffe0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000003fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffffc0000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000007fffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffff80000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000000ffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffff00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000001ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffe00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000003ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffffc00000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000007ffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffff800000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000000fffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffff000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000001fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffe000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000003fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffffc000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000007fffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffff8000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000000ffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffff0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000001ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffe0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000003ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffffc0000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000007ffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffff80000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000000fffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffff00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000001fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffe00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000003fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffffc00000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000007fffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffff800000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000000ffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffff000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000001ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffe000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000003ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffffc000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000007ffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffff8000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000000fffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffff0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000001fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffe0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000003fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffffc0000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000007fffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffff80000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000000ffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffff00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000001ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffe00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000003ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffffc00000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000007ffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffff800000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000000fffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffff000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000001fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffe000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000003fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffffc000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000007fffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffff8000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000000ffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffff0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000001ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffe0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000003ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffffc0000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000007ffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffff80000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000000fffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffff00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000001fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffe00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000003fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffffc00000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000007fffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffff800000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000000ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffff000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000001ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffe000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000003ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffffc000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000007ffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffff8000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000000fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffff0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000001fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffe0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000003fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffffc0000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000007fffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffff80000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000000ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffff00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000001ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffe00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000003ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fffc00000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000007ffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fff800000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000000fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fff000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000001fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffe000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000003fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ffc000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000007fffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ff8000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000000ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000ff0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000001ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fe0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000003ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000fc0000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000007ffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000f80000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000000fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000f00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000001fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000e00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000003fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000c00000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000007fffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000800000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000000ffffffffffffffffffffffff
+B = ffffffff00000001000000000000000000000000000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000001ffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffff000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000003ffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffffd000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000007ffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffff9000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000000fffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffff1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000001fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffe1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000003fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffffc1000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000007fffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffff81000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000000ffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffff01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000001ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffe01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000003ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffffc01000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000007ffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffff801000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000000fffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffff001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000001fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffe001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000003fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffffc001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000007fffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffff8001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000000ffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffff0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000001ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffe0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000003ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffffc0001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000007ffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffff80001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000000fffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffff00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000001fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffe00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000003fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffffc00001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000007fffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffff800001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000000ffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffff000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000001ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffe000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000003ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffffc000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000007ffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffff8000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000000fffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffff0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000001fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffe0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000003fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffffc0000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000007fffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffff80000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000000ffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffff00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000001ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffe00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000003ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffffc00000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000007ffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffff800000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000000fffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffff000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000001fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffe000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000003fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffffc000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000007fffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffff8000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000000ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffff0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000001ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffe0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000003ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffffc0000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000007ffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffff80000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000000fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffff00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000001fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffe00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000003fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffffc00000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000007fffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffff800000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000000ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffff000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000001ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffe000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000003ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffffc000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000007ffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffff8000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000000fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffff0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000001fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffe0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000003fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffffc0000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000007fffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffff80000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000000ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffff00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000001ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffe00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000003ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffffc00000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000007ffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffff800000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000000fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffff000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000001fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffe000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000003fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffffc000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000007fffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffff8000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffff0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000001ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffe0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000003ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffffc0000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000007ffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffff80000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000000fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffff00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000001fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffe00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000003fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffffc00000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000007fffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffff800000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000000ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffff000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000001ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffe000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000003ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffffc000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000007ffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffff8000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000000fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffff0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000001fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffe0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000003fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffffc0000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000007fffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffff80000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000000ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffff00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000001ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffe00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000003ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fffc00000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000007ffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fff800000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000000fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fff000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000001fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffe000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000003fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ffc000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000007fffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ff8000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000ff0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000001ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fe0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000003ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000fc0000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000007ffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000f80000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000000fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000f00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000001fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000e00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000003fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000c00000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000007fffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000800000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffff00000000000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000001ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffff000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000003ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffffd000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000007ffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffff9000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000000fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffff1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000001fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffe1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000003fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffffc1000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000007fffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffff81000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000000ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffff01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000001ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffe01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000003ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffffc01000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000007ffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffff801000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000000fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffff001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000001fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffe001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000003fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffffc001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000007fffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffff8001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffff0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000001ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffe0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000003ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefffc0001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000007ffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefff80001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000000fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefff00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000001fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffe00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000003fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeffc00001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000007fffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeff800001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffeff000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000001ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefe000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000003ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffefc000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000007ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffef8000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffef0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000001fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffee0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffec0000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffe80000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffe00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffd00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffffb00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffff700000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffef00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000001fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffdf00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000003fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffffbf00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffff7f00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffeff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffdff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffffbff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffff7ff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffefff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffdfff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffffbfff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffff7fff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffeffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffdffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0003ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fffbffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fff7ffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffefffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 001fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffdfffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 003fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ffbfffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = ff7fffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = feffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fdffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 03ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = fbffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = f7ffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = efffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = dfffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = bfffffff00000001000000000000000000000001000000000000000000000000
+
+Test = Negate
+A = 7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+B = 7fffffff00000001000000000000000000000001000000000000000000000000
+
+
+# Montgomery multiplication tests.
+#
+# The following tests satisfy A * B * 2^-256 = Result (mod P).
+
+Test = MulMont
+A = e762f095431b732ce33c4f4a6f41068ff7f78e37aad940166667d193bfc58039
+B = a43df383dd5df14d7c16737b781261473f9ffb76ee29562fbb5e5d390b882fb5
+Result = cf637a47dc5fb82aed80ed4c66b682a94bf0b76a2878acf483aad86c0db7cc19
+
+Test = MulMont
+A = 2e519e860cb3f8f32fc351861b022e9fc7bb073ca8767efb3d1027dd32a38bcb
+B = 466d035e4238d6a30613dd227b0daeacd6a8634fa60f5150d42dd20601794be4
+Result = 486e1abe0f79e107f8beca6e4653872f63a24dedb005def6aae75a2a51e73c76
+
+Test = MulMont
+A = 1763859541b5e2edee019c66699d0e12e349e6ee586d618ac20c679d2fa8cadd
+B = 56125872de888c5656dec17fbf9678d915ff9815da897df81f03fd9aa4f93654
+Result = 71ce584135a0aba8222ca0021bcefac5811d19100627f96726cf195ff2ac4aad
+
+Test = MulMont
+A = ea3be6295098e4995b93267dbd58f24fd9c18f7e89e9e5aeafdc34ca54e8ec4e
+B = 2735658978d620a4f76bffe94d9cd7d683b3bfd533aa6bb2b94f52122e83f7fc
+Result = 362f7ab3a12effe9bad069b84a7df5f108503c2457f83ddb05b57f19e6457989
+
+Test = MulMont
+A = f607f087ec5015b533df8802771dc60ef1487d86ce405e5bb18f8f06ca483f13
+B = 73ac532eb3f2356a96e668f167a1626a0f7b1fd2cd84ba6deeebd01af1d3897d
+Result = ce7045e69da157e62fb42508880f5734531c36948c704aedec42afa75cb9c2eb
+
+Test = MulMont
+A = 80ce8eb07601fd8e19ba08a9d21081b0324fd459f9c489ac7c871d406133c813
+B = 7ad28cef45b137ecc5426a44b6bce6d4329f5bd2b5e55d46edd5fbb295678a1b
+Result = 04068f8461d17b34c8d9c3eecf61dbaef9cd5a952bbcd9f84bb2044f2439da60
+
+Test = MulMont
+A = 17429caf63689e143c8ca77df69a11cbc02c272daadd75a66f3fa5f88828367e
+B = 5725bedc56a4b16e0f0ae55fa0beb1fdf3ff132ccb9803bab678d4ac7915d88c
+Result = a1da0fa68947e906287ea164b213bc7e80649b2ac3f97f203549d3b270de05a1
+
+Test = MulMont
+A = e7da43c0e0fa7adeb972901bef3160c848e9651bfc810968afdb0cd598830370
+B = 08f03060cac1d3c15eea69623d5fb01da465b209e3e5e90fbb51053a1c5700eb
+Result = cda4ffaf8b1c3ac0d44bae6ea5154de11e14931747a65396531302c0cb1ed537
+
+Test = MulMont
+A = c7375c2b6666713cb33cfb741268fd3ccf703bcaa0b9b27f84a8cb970655da9c
+B = b0796ee4bb88b9bad895d9c25c34f43a3941e9585bda8e86ff4fa0bbb391ac61
+Result = fd1d557a9fb0031e462121bf7ca31804acfcfce822bb6ee6631b54c575380617
+
+Test = MulMont
+A = 72a87b13eb4a2e248214aa591c586df65790f9f750a1641b47581a4ee09be7e9
+B = 38e602844b9aaf737e8b1261110b86ba22806ccbbbfdc5305075429d7ce4f002
+Result = cb2d63ee829de8801759f0229d4c07139bacd804f0c815d35004747c65bffdf2
+
+# Test cases where A == B to test squaring.
+
+Test = MulMont
+A = 0000000000000000000000000000000000000000000000000000000000000000
+B = 0000000000000000000000000000000000000000000000000000000000000000
+Result = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = MulMont
+A = 579e9ce1ad00639b8b64d49546ff4f9c30ad12eaebe9e2ed91e97d55c3c5d847
+B = 579e9ce1ad00639b8b64d49546ff4f9c30ad12eaebe9e2ed91e97d55c3c5d847
+Result = 10c5e60c2d480d5d53f50c24fb771fd2dec208db04624dfd05d2847ca173a9aa
+
+Test = MulMont
+A = 501947209b121bcdedce8c895ee2ba310f2e561e97998eb8f3b99d1f924f36c1
+B = 501947209b121bcdedce8c895ee2ba310f2e561e97998eb8f3b99d1f924f36c1
+Result = 54d6d64566619b215910f1b9e467b22ef205ca3aaad37a00fcbd906357f9c179
+
+Test = MulMont
+A = e84ab9202722498baa2c9158f40d47b1f03df4d13976b0aec916a937e99f3a89
+B = e84ab9202722498baa2c9158f40d47b1f03df4d13976b0aec916a937e99f3a89
+Result = 9af01fa6947a60679b6f87efe9b6fba97baf5d55a19d5e91dd5da1da10caeebf
+
+Test = MulMont
+A = add67c61d8479570f45a59e9b04974f970b0c4c6c046056fea1bdf3f0e7d3152
+B = add67c61d8479570f45a59e9b04974f970b0c4c6c046056fea1bdf3f0e7d3152
+Result = c0c68b4327e3fe7e0522167a54b25aaa6f76085ce4f6550479c89f3f1c39dd18
+
+Test = MulMont
+A = 434ef0db5640a3ea63125f815bc3cb3c92d06dbc3b5cb484e01b5247b3b4bfe5
+B = 434ef0db5640a3ea63125f815bc3cb3c92d06dbc3b5cb484e01b5247b3b4bfe5
+Result = b5105d16b858279247ed31362a90260978d64e0492e84bffa7a0e13ee1541544
+
+Test = MulMont
+A = b1db42aa4b259d9c6104599aff622114f10c327d02c5640b74cf1742adff332d
+B = b1db42aa4b259d9c6104599aff622114f10c327d02c5640b74cf1742adff332d
+Result = 0c175e7f96fc62059864c561d99a8d90978c72757ba305cd8862ed6a5fadad59
+
+Test = MulMont
+A = 7610271796be25416b652badd3119938974b20d4fc92244aea76d23b80d178f0
+B = 7610271796be25416b652badd3119938974b20d4fc92244aea76d23b80d178f0
+Result = 67d76e4a7c8355bb362481a76a63b365ad79767cc672b174130e833d41ca5709
+
+Test = MulMont
+A = 3480d60b0ccafca89c86f22f78380cead81310241f27a815e6fd21c2060caed8
+B = 3480d60b0ccafca89c86f22f78380cead81310241f27a815e6fd21c2060caed8
+Result = 68bfb2652d3bf03d17b20b2c52c68e847b0006047ba4ea81d4b85af2e0a21f72
+
+Test = MulMont
+A = 8ad6fa8bf3fe56ece1d0970636c1429ed5dfc2441c3194928a6348b69490b537
+B = 8ad6fa8bf3fe56ece1d0970636c1429ed5dfc2441c3194928a6348b69490b537
+Result = f5cdccf29e09928722137fb5a5ec035d7f39580838e19b892a7a972866330318
+
+Test = MulMont
+A = 71c328ce472ae74b5028b21f9d1997e0f7dbcee979a8f9fdecfa5d37d359c835
+B = 71c328ce472ae74b5028b21f9d1997e0f7dbcee979a8f9fdecfa5d37d359c835
+Result = c3472fafd01fc3ed93a91ab65411cb852bd5839603a02ca6cdfbadcb9ac474a0
+
+
+# Montgomery conversion tests.
+#
+# The following tests satisfy A * 2^-256 = Result (mod P).
+
+Test = FromMont
+A = 0585a3dada9bb283fd8db4fc46c106d28f95b8cf159a405891196dbb9ce0b5cf
+Result = d198d054d25a069c40cdeeb968a5562a67c3ef659297169e4be872f234897dc0
+
+Test = FromMont
+A = 9ff49a4a3f810fd34ca6f37fb1b3c40e61bc0492227e91e41cbe06bd58ba65b8
+Result = 326a061b2047d9ba4eddaba9b1fe253d5b2a24e268e3f8810767bef8cda07643
+
+Test = FromMont
+A = 05a69f8f646494be65affbd44d0536ca098d6f3640e80b5e48764ab78928cf58
+Result = 5a6f9c7025d4063480c400fe6f271cf3a3d2c43f9e1ceac21a88208c28329731
+
+Test = FromMont
+A = 256481a9e52d692719330a6f1208d9eca4ddd919aee06e234cbbde77d245501b
+Result = fe9fc86a2ff61a0c981d5e86c5472248e071e9639521c5be43947bfffc7d5858
+
+Test = FromMont
+A = 2062ef333cadefc36ced52a2ea7e4215b1fca29283baa1e3be76e321f1b213f0
+Result = 961ce39c3bf1d699b4b61ded8a5beae6eb6185d21f1df435b079b1f6a79dc738
+
+Test = FromMont
+A = 97241c3651a8f9d2fc02730f15c3e09e48d2e645cfe927385cb81d3f454414fb
+Result = 2114225803efe7b6c7fbb290cb946da4e78697aad5624c2d3fe9fb568460b93c
+
+Test = FromMont
+A = 1aae0ad2c8ac988e11beda32ca7257f4d4de41f4b74452fa46f0a3bafb39262a
+Result = 77c884131c34a2c3acce8a69dc5cf55987b7999c70586a9ef3c0dfb634900296
+
+Test = FromMont
+A = 034de033e2d38cf8bec8a994414b64a2fce7c83c5d81efc3d21448225071e85d
+Result = 984fecbde84f393133fb602777b4395c56449d2cbbd7d8ae428b2ee6f82a2956
+
+Test = FromMont
+A = d2b296c2004b2761b6781311c924cbf5ff56dcc0900ed5cd24f5dd2e07f32633
+Result = ddcff6e031b859a814ce8f37b71c10cd5fb642af54af72deabb95adcb99307b1
+
+Test = FromMont
+A = 8f525e6af50a62fc176dec75bdf48f70ba8ab97323ba78c643ef07f6457ba070
+Result = 8fa95d57aae2fff79045654501478f7a394b27b8b54113a25ac74662606f767c
+
+
+# Point adding tests.
+#
+# The following tests satisfy Result = A + B, where Result is in affine
+# coordinates and A and B are in Jacobian coordinates in the Montgomery domain.
+
+# ∞ + ∞ = ∞.
+Test = PointAdd
+A.X = 0000000000000000000000000000000000000000000000000000000000000000
+A.Y = 0000000000000000000000000000000000000000000000000000000000000000
+A.Z = 0000000000000000000000000000000000000000000000000000000000000000
+B.X = 0000000000000000000000000000000000000000000000000000000000000000
+B.Y = 0000000000000000000000000000000000000000000000000000000000000000
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+# ∞ + ∞ = ∞, with an alternate representation of ∞.
+Test = PointAdd
+A.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+A.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+A.Z = 0000000000000000000000000000000000000000000000000000000000000000
+B.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+B.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+# g + ∞ = g.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 0000000000000000000000000000000000000000000000000000000000000000
+B.Y = 0000000000000000000000000000000000000000000000000000000000000000
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+Result.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+
+# g + ∞ = g, with an alternate representation of ∞.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 2b11cb945c8cf152ffa4c9c2b1c965b019b35d0b7626919ef0ae6cb9d232f8af
+B.Y = 6d333da42e30f7011245b6281015ded14e0f100968e758a1b6c3c083afc14ea0
+B.Z = 0000000000000000000000000000000000000000000000000000000000000000
+Result.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+Result.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+
+# g + -g = ∞.
+Test = PointAdd
+A.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+A.Y = 8571ff1825885d85d2e88688dd21f3258b4ab8e4ba19e45cddf25357ce95560a
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 18905f76a53755c679fb732b7762251075ba95fc5fedb60179e730d418a9143c
+B.Y = 7a8e00e6da77a27b2d17797722de0cda74b5471c45e61ba3220daca8316aa9f5
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 0000000000000000000000000000000000000000000000000000000000000000
+Result.Y = 0000000000000000000000000000000000000000000000000000000000000000
+
+Test = PointAdd
+A.X = bcba3eebf2b0af1174a4b874b155b4dc74bd5fb57c70214561aaabb105635580
+A.Y = 1dc33ce74f651305dd89263c1d314edd2773ef6dd043742a6f47f29542b9eb07
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = f9e0b98b1a87b6c49c4cc5fc47efd157e5f12cf5543d71cfa38187a3793d6791
+B.Y = 3b2de94df438554381037c9f9d2c21991c6975d83c0acd42ef1a8419a040436f
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 6bd7b4e06d7862f749901a398417e941618c11c48dffcce719e4026220b77477
+Result.Y = 1e2ffd71e8c206acc19032d26a53ea275fefea51a2c90e4dd3c8b7c6acc51ab6
+
+Test = PointAdd
+A.X = d71c6da129f6e867bf525563e1d8bdbd2f90a9bac7de867a6ea2317a5d6cb507
+A.Y = 125e0cc1ba0c93caa19edb419a764f88d955289c4c6e77d02d90e4e31d47c9a2
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 334c2200ec08896808ab12a76820ff674fcdccff6d85afa2e586b31fc944de33
+B.Y = b5ee8cfa25896d4075588c60926a2582a099c7a5acbcfec78fba457c4886301c
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 93e9d4e6f7736f80da1b00d221024ccfd17f2927d6b505a5bcefe0801fe6f0a9
+Result.Y = 4824eeb2d5da27d57e1d50c2dae000acdcddcbaf534d8b7e7d97854ed3dc939e
+
+Test = PointAdd
+A.X = 0daba41be2b418e7d160a363e6cbdcbff5d433f96b0d5be3812c0a7adfab8ed4
+A.Y = 3ae4dd97c4d2987a63df16c5fb8c494164e14b93eeebd5585d74bd26e2201499
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 87135fb06383ec8b282fdc028eb38fd447ac1ecc76922e37f0cc454febb11aee
+B.Y = 98ab966087531eb3eea1e5e36189271a02f7ee8e381f9c78d6f346a301f96f81
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 2e096c2fabf06a5b838c7e07fda436d068dd1c4e3ff4f5704f89ab9df6b4be5b
+Result.Y = 59ca6304321ae1e41bfa30f52e7ef27fceeade8507f20837654383d70e8a41df
+
+Test = PointAdd
+A.X = 356db98c21c2169899b9b296edcacb7d531524f2572913b75edb7b73196f5682
+A.Y = 47a26c52b1b2f229109e8aca7f5b4af768baf053a15ff8f58051c7e4e1b7f818
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 56956f6d3bbbd4aece299f29bb4c537355f312f391c207c6ec6efe646362b288
+B.Y = a69fc73c0636c9928764cc9d6e1482577b6ca06f277c098f571108356a858cab
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = ca0ddd995a77173a1438473bf82734cb3a09fafe7050bda9bd592a1cf078fa38
+Result.Y = 379da87952d36c5396b934a2ce8b003ee8fc4155b3b488f2f550734e2a82ce7d
+
+Test = PointAdd
+A.X = 13764cccab4addf5cf4ef5fb4af60a93e08fa3a0a72653abf013e3427abbf82c
+A.Y = c3dc524745368a0dc4948f897402f4b5a280acbf74f5ea9180d038a483d4090a
+A.Z = 2903a04d6615ec23cd63ba46287be2e7a8eeee030bed49e7a94769386a46f209
+B.X = a5c5921f9a8c569f661693bfae1b167937987c2fe951956ef0e34c426965c648
+B.Y = f8a299605e690a78e583371e59cf2b848d475afc35bb1448981c53ad8c0a6581
+B.Z = 9c3fde73f1899a76eb40f055fce02ab9c1b1ce7d43b54c54f93ffe56830e3f83
+Result.X = 4073318e85bc2d7637fd0129fa8eb86b6ca20334542795f3bb1de54b90a16b69
+Result.Y = 9a1b1e7435d98287b244d2337f8bf0e9c87b40677bf1ea2a9dedbd07c5241ee0
+
+Test = PointAdd
+A.X = f72706b81fca2b1530238bdc2c0c454b5116ee54fdf156bc62bffea73f0645af
+A.Y = c6e66d9ae8fc5e164e6a985f866aae41f3c4e4281a0eea9173e4e77cb29e4bc7
+A.Z = 6a84f9c37634b8aefdae477e9efec66f20d2f6159575f40c7b21a1e0732e8c49
+B.X = bcf21b020cb8fb4b2ef7f639240d221dd96fc08d7fa575c2e7037fc84d8f03b2
+B.Y = abc500f82f06f0d69a920c8d80eef9dd2310cd09e0d89d80fc7397aa4e361dd1
+B.Z = 5031c46be15f9d4fa9a347be998c07f9cc7f754999fe0f9c3c8b38e0d85dda9f
+Result.X = 401b010df4dd21ed96f7c8babb401db74b3b6ee7f55c498803203855b5911de9
+Result.Y = 05e585cca569bc22855f7df32b20a4a45315a1ca5d98d2b94792eb748ec8744b
+
+Test = PointAdd
+A.X = 7b44b52e9fb1bc58c81a2adc9bfedcc42bba3cb34ec666e51cba8050d48fdb37
+A.Y = 2b7e629fef7b4e175f5eb30c421e60f26fefdf5f9fed743cad4a8e638c18696a
+A.Z = 68f31acd92bed56a4556e954b0c51f9f8f3b797bc853d1b2b01b228657bd317f
+B.X = 3d293c36fd065d1f054eb218932d60feb00d1bd4bee0236cb9788d9723df9571
+B.Y = c8b893b8e9ff935f2e060227334e32ba144f4046b1bd4961f4479ad3fef1c7d2
+B.Z = 9c072deacfe5c025c763efebb4feab79e954c47d3e86ef4abfbd1901f50d8495
+Result.X = 245582d32415c77a2e3abbf844cf1a40c31466c1418cd279747e5394744509be
+Result.Y = 5c2f80f947d2df7fb1f829d05c6175f6fce7cd2d7f79fd7aa865f930e910e9fd
+
+Test = PointAdd
+A.X = 75ab91b8a46a5a1abf827cb209373b28cbb8f83a06adf6a9b10ac76e22493ecc
+A.Y = abd989a78d1bcee7e63920d7e637f9763901da408a9d8c731e4e65a6fc52e1a1
+A.Z = 188a24145243ca066c35870e5a8835532ad512fbdcf5f5ae4033b262fa9aa6b8
+B.X = 5d6e885ec19069b2aa51a2723c98da1f03e8dbc344fe1de0bdb42910ba8bfe96
+B.Y = a1f86e66eacc38db7e47154a324a16031705b4803addf074037d3320b50dbef8
+B.Z = 5cff900a783687049a7d497b1f8cd837c479a61f3fef4b7ced180ea82770bc75
+Result.X = a4029333b9b9db434eea002bd6d4e0d9f3e5317c685511a30ecae351fc60d164
+Result.Y = 8e9302c77bc6f560c9bec473ef1ffb76b357c0d4794192696bda8e99651798ee
+
+Test = PointAdd
+A.X = 8d1867f890abaa26b634d5d5cdeb0f4abc7ebd16d807479f837fcece592dc0eb
+A.Y = fc68c801999c12070eddeb3169219c491f9e8fe29cdc4e3cb698ee8471934076
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 8d1867f890abaa26b634d5d5cdeb0f4abc7ebd16d807479f837fcece592dc0eb
+B.Y = fc68c801999c12070eddeb3169219c491f9e8fe29cdc4e3cb698ee8471934076
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 8da53dc540c1450c73082ad3b799d0d18a69a747fcd81f847e9e60484dcf579a
+Result.Y = c20c398e99e0513a452b5e9b6331863d1ac3eee6fcf73021f505a0b62daf6f80
+
+Test = PointAdd
+A.X = 328b983f6490312e37e8eeb2121cd622cf85dbcf78af93df74fbca961ce3bfa2
+A.Y = 1c8a0aea2f2e540770644f48c41810bf7f9e1a782b2f6397712b17c88109fbce
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 328b983f6490312e37e8eeb2121cd622cf85dbcf78af93df74fbca961ce3bfa2
+B.Y = 1c8a0aea2f2e540770644f48c41810bf7f9e1a782b2f6397712b17c88109fbce
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = b6f3c548944862dfdea2314ca6d6a88780b08da41becf58384af80544aca4966
+Result.Y = 95afecb4ad3195485a2aad3cd14008c9a7c1e0c02656c3c2b7cd5f2e7f3a4474
+
+Test = PointAdd
+A.X = 3ae6b24cadd6a14612d24a1c094a35c6be56db8f53a6d526e0ede03923918443
+A.Y = de8a23105c5f5c88b77dbde74e30a56f8865d78a5ce9060cff9f2927dbd196b6
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = 3ae6b24cadd6a14612d24a1c094a35c6be56db8f53a6d526e0ede03923918443
+B.Y = de8a23105c5f5c88b77dbde74e30a56f8865d78a5ce9060cff9f2927dbd196b6
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = 6f125b512c3c736f39781fcd89adb653e515b4ce1e1204505f08d0a8480052ef
+Result.Y = e1acfccf1b9950067adf0f06e0d9703a8b1ac1bbdbb35b08df28cd56c24ae5a0
+
+Test = PointAdd
+A.X = f317c6c02d9a6ff0799b3b4a22f83c95324831baad336ecd0c631ea04a5e11c8
+A.Y = b624e8057d411031f41b30cd02f56c24e89262e885007b7a1ed1861feb7ffcda
+A.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+B.X = f317c6c02d9a6ff0799b3b4a22f83c95324831baad336ecd0c631ea04a5e11c8
+B.Y = b624e8057d411031f41b30cd02f56c24e89262e885007b7a1ed1861feb7ffcda
+B.Z = 00000000fffffffeffffffffffffffffffffffff000000000000000000000001
+Result.X = e805208c74602e54482d113f16fcf6e4600436f8af49705cdd05ecfb0e6d45fd
+Result.Y = baded898bfead1b4eb3ab3bbd0129837efc85823dabe82718a975bd603f96d9e
+
+Test = PointAdd
+A.X = 3a6802aeaebc67046a1e75152822fa8bab04c11ae2b816f42c073daee3f13274
+A.Y = d6522c882d18e32bc5ea1fa59efbce8ce2369f2154dcc00e6fb17500f50f8ebf
+A.Z = bea747d5bb1c6ee865249d7a22378f3c760916e163497f4b6ef4da8adcb5dfab
+B.X = 3a6802aeaebc67046a1e75152822fa8bab04c11ae2b816f42c073daee3f13274
+B.Y = d6522c882d18e32bc5ea1fa59efbce8ce2369f2154dcc00e6fb17500f50f8ebf
+B.Z = bea747d5bb1c6ee865249d7a22378f3c760916e163497f4b6ef4da8adcb5dfab
+Result.X = 5a2891dca746889d413d8dc1a69b715954baf692689fc32d9aa10b7431a5c149
+Result.Y = 91db7288536b4f6d78e5a787ecbb5094f6834515038cb070a7fa4870af8045f0
+
+Test = PointAdd
+A.X = c76ddbcb15bc63f82807804536a0d25fd7a639c71adf953ad6cc8f68d915f485
+A.Y = e3a4f830809f5e91b68699c05fa9faa7c3d1f9d1b1c982c282508fa18d695537
+A.Z = eb372f19c7b9466a116363ad9114a89ad287523da318d915f59ed5e558bd824e
+B.X = c76ddbcb15bc63f82807804536a0d25fd7a639c71adf953ad6cc8f68d915f485
+B.Y = e3a4f830809f5e91b68699c05fa9faa7c3d1f9d1b1c982c282508fa18d695537
+B.Z = eb372f19c7b9466a116363ad9114a89ad287523da318d915f59ed5e558bd824e
+Result.X = c5485a3509f55c7cc33d098fb0bfe1b198a9f26ce0ebc29bec5baa29ef6f74a2
+Result.Y = 60e949a551aa94afc9a3efe411a3c63ecb851ef1738ed24c88f86cf85ec01020
+
+Test = PointAdd
+A.X = ca72936509631f09d2a3ac14fb786daabb15520ef01de4298c7fd71653e89194
+A.Y = 02aeb6b6f04cd8125887baa18e6e79ba2b0acfa9a2443e9eea36ca7715eb8eb3
+A.Z = 8b4ef1a52fa42c711445e0463003f2ed38ace6583bf08198e9a0b938b4589479
+B.X = ca72936509631f09d2a3ac14fb786daabb15520ef01de4298c7fd71653e89194
+B.Y = 02aeb6b6f04cd8125887baa18e6e79ba2b0acfa9a2443e9eea36ca7715eb8eb3
+B.Z = 8b4ef1a52fa42c711445e0463003f2ed38ace6583bf08198e9a0b938b4589479
+Result.X = 8d3b35c5661faafa83510ab9b3f1642bb121e7686ed4ae61323ddee2c7247f93
+Result.Y = 1a22ef5df156ca80235fe3cd1ca3152e21a3e17b2a34dd93b2003e3274a8a2fb
+
+Test = PointAdd
+A.X = db7b023fbe056819027fa09c5a2a0d777a53fb78c00bf4f31f46b63a7494bbfe
+A.Y = 59affcbf4628d572ee56b95087d30e765bb518b123e879b25df9960dab706a32
+A.Z = 1f7c7226d78e51478c683bbb6afe01abc2225dbfc773d0806d30ff5f827b76c8
+B.X = db7b023fbe056819027fa09c5a2a0d777a53fb78c00bf4f31f46b63a7494bbfe
+B.Y = 59affcbf4628d572ee56b95087d30e765bb518b123e879b25df9960dab706a32
+B.Z = 1f7c7226d78e51478c683bbb6afe01abc2225dbfc773d0806d30ff5f827b76c8
+Result.X = fba400ae656ec3103c5c5f531d2a0f7368031e01a48a91f1a4f3138d294b13be
+Result.Y = 160e358ad1f059eb62722df01a7440048a1db21ecaea8698efa9677db6e9ff97
diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata
index c25683ee..b50f9ab8 100644
--- a/src/crypto/err/ssl.errordata
+++ b/src/crypto/err/ssl.errordata
@@ -66,6 +66,7 @@ SSL,158,INVALID_COMMAND
SSL,256,INVALID_COMPRESSION_LIST
SSL,159,INVALID_MESSAGE
SSL,251,INVALID_OUTER_RECORD_TYPE
+SSL,269,INVALID_SCT_LIST
SSL,160,INVALID_SSL_SESSION
SSL,161,INVALID_TICKET_KEYS_LENGTH
SSL,162,LENGTH_MISMATCH
@@ -99,12 +100,14 @@ SSL,266,NO_SHARED_GROUP
SSL,185,NULL_SSL_CTX
SSL,186,NULL_SSL_METHOD_PASSED
SSL,187,OLD_SESSION_CIPHER_NOT_RETURNED
+SSL,268,OLD_SESSION_PRF_HASH_MISMATCH
SSL,188,OLD_SESSION_VERSION_NOT_RETURNED
SSL,189,OUTPUT_ALIASES_INPUT
SSL,190,PARSE_TLSEXT
SSL,191,PATH_TOO_LONG
SSL,192,PEER_DID_NOT_RETURN_A_CERTIFICATE
SSL,193,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
+SSL,267,PRE_SHARED_KEY_MUST_BE_LAST
SSL,194,PROTOCOL_IS_SHUTDOWN
SSL,195,PSK_IDENTITY_NOT_FOUND
SSL,196,PSK_NO_CLIENT_CB
diff --git a/src/crypto/mem.c b/src/crypto/mem.c
index 4596472a..ee34767a 100644
--- a/src/crypto/mem.c
+++ b/src/crypto/mem.c
@@ -68,14 +68,6 @@
#if defined(OPENSSL_WINDOWS)
OPENSSL_MSVC_PRAGMA(warning(push, 3))
#include <windows.h>
-
-/* Work around a clang-cl bug: SecureZeroMemory() below uses __stosb() but
- * windows.h only declares that intrinsic and then uses `#pragma intrinsic` for
- * it. clang-cl doesn't implement `#pragma intrinsic` yet; it instead defines
- * the function as an always-inline symbol in its intrin.h.
- * TODO(thakis): Remove this once http://llvm.org/PR19898 is fixed.
- */
-#include <intrin.h>
OPENSSL_MSVC_PRAGMA(warning(pop))
#else
#include <strings.h>
diff --git a/src/crypto/poly1305/poly1305.c b/src/crypto/poly1305/poly1305.c
index 5e368020..4c5d11f1 100644
--- a/src/crypto/poly1305/poly1305.c
+++ b/src/crypto/poly1305/poly1305.c
@@ -27,7 +27,6 @@
#if defined(OPENSSL_WINDOWS) || !defined(OPENSSL_X86_64)
-#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM)
/* We can assume little-endian. */
static uint32_t U8TO32_LE(const uint8_t *m) {
uint32_t r;
@@ -36,19 +35,6 @@ static uint32_t U8TO32_LE(const uint8_t *m) {
}
static void U32TO8_LE(uint8_t *m, uint32_t v) { memcpy(m, &v, sizeof(v)); }
-#else
-static uint32_t U8TO32_LE(const uint8_t *m) {
- return (uint32_t)m[0] | (uint32_t)m[1] << 8 | (uint32_t)m[2] << 16 |
- (uint32_t)m[3] << 24;
-}
-
-static void U32TO8_LE(uint8_t *m, uint32_t v) {
- m[0] = v;
- m[1] = v >> 8;
- m[2] = v >> 16;
- m[3] = v >> 24;
-}
-#endif
static uint64_t mul32x32_64(uint32_t a, uint32_t b) { return (uint64_t)a * b; }
@@ -61,6 +47,11 @@ struct poly1305_state_st {
uint8_t key[16];
};
+static inline struct poly1305_state_st *poly1305_aligned_state(
+ poly1305_state *state) {
+ return (struct poly1305_state_st *)(((uintptr_t)state + 63) & ~63);
+}
+
/* poly1305_blocks updates |state| given some amount of input data. This
* function may only be called with a |len| that is not a multiple of 16 at the
* end of the data. Otherwise the input must be buffered into 16 byte blocks. */
@@ -159,7 +150,7 @@ poly1305_donna_atmost15bytes:
}
void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) {
- struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+ struct poly1305_state_st *state = poly1305_aligned_state(statep);
uint32_t t0, t1, t2, t3;
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
@@ -207,7 +198,7 @@ void CRYPTO_poly1305_init(poly1305_state *statep, const uint8_t key[32]) {
void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in,
size_t in_len) {
unsigned int i;
- struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+ struct poly1305_state_st *state = poly1305_aligned_state(statep);
#if defined(OPENSSL_ARM) && !defined(OPENSSL_NO_ASM)
if (CRYPTO_is_NEON_capable()) {
@@ -250,7 +241,7 @@ void CRYPTO_poly1305_update(poly1305_state *statep, const uint8_t *in,
}
void CRYPTO_poly1305_finish(poly1305_state *statep, uint8_t mac[16]) {
- struct poly1305_state_st *state = (struct poly1305_state_st *)statep;
+ struct poly1305_state_st *state = poly1305_aligned_state(statep);
uint64_t f0, f1, f2, f3;
uint32_t g0, g1, g2, g3, g4;
uint32_t b, nb;
diff --git a/src/crypto/pool/CMakeLists.txt b/src/crypto/pool/CMakeLists.txt
new file mode 100644
index 00000000..fe55af20
--- /dev/null
+++ b/src/crypto/pool/CMakeLists.txt
@@ -0,0 +1,20 @@
+include_directories(../../include)
+
+add_library(
+ pool
+
+ OBJECT
+
+ pool.c
+)
+
+add_executable(
+ pool_test
+
+ pool_test.cc
+
+ $<TARGET_OBJECTS:test_support>
+)
+
+target_link_libraries(pool_test crypto)
+add_dependencies(all_tests pool_test)
diff --git a/src/crypto/pool/internal.h b/src/crypto/pool/internal.h
new file mode 100644
index 00000000..3ec2ec2e
--- /dev/null
+++ b/src/crypto/pool/internal.h
@@ -0,0 +1,45 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_POOL_INTERNAL_H
+#define OPENSSL_HEADER_POOL_INTERNAL_H
+
+#include <openssl/lhash.h>
+#include <openssl/thread.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+DECLARE_LHASH_OF(CRYPTO_BUFFER);
+
+struct crypto_buffer_st {
+ CRYPTO_BUFFER_POOL *pool;
+ uint8_t *data;
+ size_t len;
+ CRYPTO_refcount_t references;
+};
+
+struct crypto_buffer_pool_st {
+ LHASH_OF(CRYPTO_BUFFER) *bufs;
+ CRYPTO_MUTEX lock;
+};
+
+
+#if defined(__cplusplus)
+} /* extern C */
+#endif
+
+#endif /* OPENSSL_HEADER_POOL_INTERNAL_H */
diff --git a/src/crypto/pool/pool.c b/src/crypto/pool/pool.c
new file mode 100644
index 00000000..ca058fc2
--- /dev/null
+++ b/src/crypto/pool/pool.c
@@ -0,0 +1,200 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <openssl/pool.h>
+
+#include <assert.h>
+#include <string.h>
+
+#include <openssl/buf.h>
+#include <openssl/bytestring.h>
+#include <openssl/mem.h>
+#include <openssl/thread.h>
+
+#include "../internal.h"
+#include "internal.h"
+
+
+static uint32_t CRYPTO_BUFFER_hash(const CRYPTO_BUFFER *buf) {
+ return OPENSSL_hash32(buf->data, buf->len);
+}
+
+static int CRYPTO_BUFFER_cmp(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b) {
+ if (a->len != b->len) {
+ return 1;
+ }
+ return memcmp(a->data, b->data, a->len);
+}
+
+CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void) {
+ CRYPTO_BUFFER_POOL *pool = OPENSSL_malloc(sizeof(CRYPTO_BUFFER_POOL));
+ if (pool == NULL) {
+ return NULL;
+ }
+
+ memset(pool, 0, sizeof(CRYPTO_BUFFER_POOL));
+ pool->bufs = lh_CRYPTO_BUFFER_new(CRYPTO_BUFFER_hash, CRYPTO_BUFFER_cmp);
+ if (pool->bufs == NULL) {
+ OPENSSL_free(pool);
+ return NULL;
+ }
+
+ CRYPTO_MUTEX_init(&pool->lock);
+
+ return pool;
+}
+
+void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool) {
+ if (pool == NULL) {
+ return;
+ }
+
+#if !defined(NDEBUG)
+ CRYPTO_MUTEX_lock_write(&pool->lock);
+ assert(lh_CRYPTO_BUFFER_num_items(pool->bufs) == 0);
+ CRYPTO_MUTEX_unlock_write(&pool->lock);
+#endif
+
+ lh_CRYPTO_BUFFER_free(pool->bufs);
+ CRYPTO_MUTEX_cleanup(&pool->lock);
+ OPENSSL_free(pool);
+}
+
+CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
+ CRYPTO_BUFFER_POOL *pool) {
+ if (pool != NULL) {
+ CRYPTO_BUFFER tmp;
+ tmp.data = (uint8_t *) data;
+ tmp.len = len;
+
+ CRYPTO_MUTEX_lock_read(&pool->lock);
+ CRYPTO_BUFFER *const duplicate =
+ lh_CRYPTO_BUFFER_retrieve(pool->bufs, &tmp);
+ if (duplicate != NULL) {
+ CRYPTO_refcount_inc(&duplicate->references);
+ }
+ CRYPTO_MUTEX_unlock_read(&pool->lock);
+
+ if (duplicate != NULL) {
+ return duplicate;
+ }
+ }
+
+ CRYPTO_BUFFER *const buf = OPENSSL_malloc(sizeof(CRYPTO_BUFFER));
+ if (buf == NULL) {
+ return NULL;
+ }
+ memset(buf, 0, sizeof(CRYPTO_BUFFER));
+
+ buf->data = BUF_memdup(data, len);
+ if (len != 0 && buf->data == NULL) {
+ OPENSSL_free(buf);
+ return NULL;
+ }
+
+ buf->len = len;
+ buf->references = 1;
+
+ if (pool == NULL) {
+ return buf;
+ }
+
+ buf->pool = pool;
+
+ CRYPTO_MUTEX_lock_write(&pool->lock);
+ CRYPTO_BUFFER *duplicate = lh_CRYPTO_BUFFER_retrieve(pool->bufs, buf);
+ int inserted = 0;
+ if (duplicate == NULL) {
+ CRYPTO_BUFFER *old = NULL;
+ inserted = lh_CRYPTO_BUFFER_insert(pool->bufs, &old, buf);
+ assert(old == NULL);
+ } else {
+ CRYPTO_refcount_inc(&duplicate->references);
+ }
+ CRYPTO_MUTEX_unlock_write(&pool->lock);
+
+ if (!inserted) {
+ /* We raced to insert |buf| into the pool and lost, or else there was an
+ * error inserting. */
+ OPENSSL_free(buf->data);
+ OPENSSL_free(buf);
+ return duplicate;
+ }
+
+ return buf;
+}
+
+CRYPTO_BUFFER* CRYPTO_BUFFER_new_from_CBS(CBS *cbs, CRYPTO_BUFFER_POOL *pool) {
+ return CRYPTO_BUFFER_new(CBS_data(cbs), CBS_len(cbs), pool);
+}
+
+void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf) {
+ if (buf == NULL) {
+ return;
+ }
+
+ CRYPTO_BUFFER_POOL *const pool = buf->pool;
+ if (pool == NULL) {
+ if (CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
+ /* If a reference count of zero is observed, there cannot be a reference
+ * from any pool to this buffer and thus we are able to free this
+ * buffer. */
+ OPENSSL_free(buf->data);
+ OPENSSL_free(buf);
+ }
+
+ return;
+ }
+
+ CRYPTO_MUTEX_lock_write(&pool->lock);
+ if (!CRYPTO_refcount_dec_and_test_zero(&buf->references)) {
+ CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
+ return;
+ }
+
+ /* We have an exclusive lock on the pool, therefore no concurrent lookups can
+ * find this buffer and increment the reference count. Thus, if the count is
+ * zero there are and can never be any more references and thus we can free
+ * this buffer. */
+ void *found = lh_CRYPTO_BUFFER_delete(pool->bufs, buf);
+ assert(found != NULL);
+ assert(found == buf);
+ (void)found;
+ CRYPTO_MUTEX_unlock_write(&buf->pool->lock);
+ OPENSSL_free(buf->data);
+ OPENSSL_free(buf);
+}
+
+int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf) {
+ /* This is safe in the case that |buf->pool| is NULL because it's just
+ * standard reference counting in that case.
+ *
+ * This is also safe if |buf->pool| is non-NULL because, if it were racing
+ * with |CRYPTO_BUFFER_free| then the two callers must have independent
+ * references already and so the reference count will never hit zero. */
+ CRYPTO_refcount_inc(&buf->references);
+ return 1;
+}
+
+const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf) {
+ return buf->data;
+}
+
+size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf) {
+ return buf->len;
+}
+
+void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out) {
+ CBS_init(out, buf->data, buf->len);
+}
diff --git a/src/crypto/pool/pool_test.cc b/src/crypto/pool/pool_test.cc
new file mode 100644
index 00000000..0b5338f4
--- /dev/null
+++ b/src/crypto/pool/pool_test.cc
@@ -0,0 +1,86 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/pool.h>
+
+
+static bool TestUnpooled() {
+ static const uint8_t kData[4] = {1, 2, 3, 4};
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new(kData, sizeof(kData), nullptr));
+ if (!buf) {
+ return false;
+ }
+
+ if (CRYPTO_BUFFER_len(buf.get()) != sizeof(kData) ||
+ memcmp(kData, CRYPTO_BUFFER_data(buf.get()), sizeof(kData)) != 0) {
+ fprintf(stderr, "CRYPTO_BUFFER corrupted data.\n");
+ return false;
+ }
+
+ CRYPTO_BUFFER_up_ref(buf.get());
+ bssl::UniquePtr<CRYPTO_BUFFER> buf2(buf.get());
+
+ return true;
+}
+
+static bool TestEmpty() {
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(CRYPTO_BUFFER_new(nullptr, 0, nullptr));
+ if (!buf) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestPool() {
+ bssl::UniquePtr<CRYPTO_BUFFER_POOL> pool(CRYPTO_BUFFER_POOL_new());
+ if (!pool) {
+ return false;
+ }
+
+ static const uint8_t kData[4] = {1, 2, 3, 4};
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
+ if (!buf) {
+ return false;
+ }
+
+ bssl::UniquePtr<CRYPTO_BUFFER> buf2(
+ CRYPTO_BUFFER_new(kData, sizeof(kData), pool.get()));
+ if (!buf2) {
+ return false;
+ }
+
+ if (buf.get() != buf2.get()) {
+ fprintf(stderr, "CRYPTO_BUFFER_POOL did not dedup data.\n");
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char **argv) {
+ if (!TestUnpooled() ||
+ !TestEmpty() ||
+ !TestPool()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}
diff --git a/src/crypto/rand/deterministic.c b/src/crypto/rand/deterministic.c
index 628fd226..c0a347c0 100644
--- a/src/crypto/rand/deterministic.c
+++ b/src/crypto/rand/deterministic.c
@@ -14,7 +14,7 @@
#include <openssl/rand.h>
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
#include <string.h>
@@ -44,4 +44,4 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
g_num_calls++;
}
-#endif /* BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif /* BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rand/rand.c b/src/crypto/rand/rand.c
index b73bc3cb..ec78a2e2 100644
--- a/src/crypto/rand/rand.c
+++ b/src/crypto/rand/rand.c
@@ -73,7 +73,7 @@ static void rand_thread_state_free(void *state) {
}
#if defined(OPENSSL_X86_64) && !defined(OPENSSL_NO_ASM) && \
- !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
/* These functions are defined in asm/rdrand-x86_64.pl */
extern int CRYPTO_rdrand(uint8_t out[8]);
diff --git a/src/crypto/rand/urandom.c b/src/crypto/rand/urandom.c
index 4c8a5f71..25726259 100644
--- a/src/crypto/rand/urandom.c
+++ b/src/crypto/rand/urandom.c
@@ -12,9 +12,11 @@
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+#define _GNU_SOURCE /* needed for syscall() on Linux. */
+
#include <openssl/rand.h>
-#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
#include <assert.h>
#include <errno.h>
@@ -22,6 +24,10 @@
#include <string.h>
#include <unistd.h>
+#if defined(OPENSSL_LINUX)
+#include <sys/syscall.h>
+#endif
+
#include <openssl/thread.h>
#include <openssl/mem.h>
@@ -29,6 +35,43 @@
#include "../internal.h"
+#if defined(OPENSSL_LINUX)
+
+#if defined(OPENSSL_X86_64)
+#define EXPECTED_SYS_getrandom 318
+#elif defined(OPENSSL_X86)
+#define EXPECTED_SYS_getrandom 355
+#elif defined(OPENSSL_AARCH64)
+#define EXPECTED_SYS_getrandom 278
+#elif defined(OPENSSL_ARM)
+#define EXPECTED_SYS_getrandom 384
+#elif defined(OPENSSL_PPC64LE)
+#define EXPECTED_SYS_getrandom 359
+#endif
+
+#if defined(EXPECTED_SYS_getrandom)
+#define USE_SYS_getrandom
+
+#if defined(SYS_getrandom)
+
+#if SYS_getrandom != EXPECTED_SYS_getrandom
+#error "system call number for getrandom is not the expected value"
+#endif
+
+#else /* SYS_getrandom */
+
+#define SYS_getrandom EXPECTED_SYS_getrandom
+
+#endif /* SYS_getrandom */
+
+#endif /* EXPECTED_SYS_getrandom */
+
+#if !defined(GRND_NONBLOCK)
+#define GRND_NONBLOCK 1
+#endif
+
+#endif /* OPENSSL_LINUX */
+
/* This file implements a PRNG by reading from /dev/urandom, optionally with a
* buffer, which is unsafe across |fork|. */
@@ -71,6 +114,12 @@ static void init_once(void) {
int fd = urandom_fd_requested;
CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock);
+#if defined(USE_SYS_getrandom)
+ /* Initial test of getrandom to find any unexpected behavior. */
+ uint8_t dummy;
+ syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK);
+#endif
+
if (fd == -2) {
do {
fd = open("/dev/urandom", O_RDONLY);
@@ -144,7 +193,7 @@ static struct rand_buffer *get_thread_local_buffer(void) {
if (buf == NULL) {
return NULL;
}
- buf->used = BUF_SIZE; /* To trigger a |read_full| on first use. */
+ buf->used = BUF_SIZE; /* To trigger a |fill_with_entropy| on first use. */
if (!CRYPTO_set_thread_local(OPENSSL_THREAD_LOCAL_URANDOM_BUF, buf,
OPENSSL_free)) {
OPENSSL_free(buf);
@@ -154,14 +203,14 @@ static struct rand_buffer *get_thread_local_buffer(void) {
return buf;
}
-/* read_full reads exactly |len| bytes from |fd| into |out| and returns 1. In
- * the case of an error it returns 0. */
-static char read_full(int fd, uint8_t *out, size_t len) {
+/* fill_with_entropy writes |len| bytes of entropy into |out|. It returns one
+ * on success and zero on error. */
+static char fill_with_entropy(uint8_t *out, size_t len) {
ssize_t r;
while (len > 0) {
do {
- r = read(fd, out, len);
+ r = read(urandom_fd, out, len);
} while (r == -1 && errno == EINTR);
if (r <= 0) {
@@ -186,7 +235,7 @@ static void read_from_buffer(struct rand_buffer *buf,
out += remaining;
requested -= remaining;
- if (!read_full(urandom_fd, buf->rand, BUF_SIZE)) {
+ if (!fill_with_entropy(buf->rand, BUF_SIZE)) {
abort();
return;
}
@@ -213,9 +262,9 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
}
}
- if (!read_full(urandom_fd, out, requested)) {
+ if (!fill_with_entropy(out, requested)) {
abort();
}
}
-#endif /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rand/windows.c b/src/crypto/rand/windows.c
index 07e7dd83..f47182d9 100644
--- a/src/crypto/rand/windows.c
+++ b/src/crypto/rand/windows.c
@@ -14,7 +14,7 @@
#include <openssl/rand.h>
-#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
#include <limits.h>
#include <stdlib.h>
@@ -50,4 +50,4 @@ void CRYPTO_sysrand(uint8_t *out, size_t requested) {
return;
}
-#endif /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_FUZZER_MODE */
+#endif /* OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/sha/CMakeLists.txt b/src/crypto/sha/CMakeLists.txt
index 49147d38..64c77db6 100644
--- a/src/crypto/sha/CMakeLists.txt
+++ b/src/crypto/sha/CMakeLists.txt
@@ -45,6 +45,7 @@ add_library(
OBJECT
+ sha1-altivec.c
sha1.c
sha256.c
sha512.c
diff --git a/src/crypto/sha/sha1-altivec.c b/src/crypto/sha/sha1-altivec.c
new file mode 100644
index 00000000..500986e1
--- /dev/null
+++ b/src/crypto/sha/sha1-altivec.c
@@ -0,0 +1,346 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+/* Altivec-optimized SHA1 in C. This is tested on ppc64le only.
+ *
+ * References:
+ * https://software.intel.com/en-us/articles/improving-the-performance-of-the-secure-hash-algorithm-1
+ * http://arctic.org/~dean/crypto/sha1.html
+ *
+ * This code used the generic SHA-1 from OpenSSL as a basis and AltiVec
+ * optimisations were added on top. */
+
+#include <openssl/sha.h>
+
+#if defined(OPENSSL_PPC64LE)
+
+#include <altivec.h>
+
+void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num);
+
+static uint32_t rotate(uint32_t a, int n) { return (a << n) | (a >> (32 - n)); }
+
+typedef vector unsigned int vec_uint32_t;
+typedef vector unsigned char vec_uint8_t;
+
+/* Vector constants */
+static const vec_uint8_t k_swap_endianness = {3, 2, 1, 0, 7, 6, 5, 4,
+ 11, 10, 9, 8, 15, 14, 13, 12};
+
+/* Shift amounts for byte and bit shifts and rotations */
+static const vec_uint8_t k_4_bytes = {32, 32, 32, 32, 32, 32, 32, 32,
+ 32, 32, 32, 32, 32, 32, 32, 32};
+static const vec_uint8_t k_12_bytes = {96, 96, 96, 96, 96, 96, 96, 96,
+ 96, 96, 96, 96, 96, 96, 96, 96};
+
+#define K_00_19 0x5a827999UL
+#define K_20_39 0x6ed9eba1UL
+#define K_40_59 0x8f1bbcdcUL
+#define K_60_79 0xca62c1d6UL
+
+/* Vector versions of the above. */
+static const vec_uint32_t K_00_19_x_4 = {K_00_19, K_00_19, K_00_19, K_00_19};
+static const vec_uint32_t K_20_39_x_4 = {K_20_39, K_20_39, K_20_39, K_20_39};
+static const vec_uint32_t K_40_59_x_4 = {K_40_59, K_40_59, K_40_59, K_40_59};
+static const vec_uint32_t K_60_79_x_4 = {K_60_79, K_60_79, K_60_79, K_60_79};
+
+/* vector message scheduling: compute message schedule for round i..i+3 where i
+ * is divisible by 4. We return the schedule w[i..i+3] as a vector. In
+ * addition, we also precompute sum w[i..+3] and an additive constant K. This
+ * is done to offload some computation of f() in the integer execution units.
+ *
+ * Byte shifting code below may not be correct for big-endian systems. */
+static vec_uint32_t sched_00_15(vec_uint32_t *pre_added, const void *data,
+ vec_uint32_t k) {
+ const vec_uint32_t v = *((const vec_uint32_t *)data);
+ const vec_uint32_t w = vec_perm(v, v, k_swap_endianness);
+ vec_st(w + k, 0, pre_added);
+ return w;
+}
+
+/* Compute w[i..i+3] using these steps for i in [16, 20, 24, 28]
+ *
+ * w'[i ] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) <<< 1
+ * w'[i+1] = (w[i-2] ^ w[i-7] ^ w[i-13] ^ w[i-15]) <<< 1
+ * w'[i+2] = (w[i-1] ^ w[i-6] ^ w[i-12] ^ w[i-14]) <<< 1
+ * w'[i+3] = ( 0 ^ w[i-5] ^ w[i-11] ^ w[i-13]) <<< 1
+ *
+ * w[ i] = w'[ i]
+ * w[i+1] = w'[i+1]
+ * w[i+2] = w'[i+2]
+ * w[i+3] = w'[i+3] ^ (w'[i] <<< 1) */
+static vec_uint32_t sched_16_31(vec_uint32_t *pre_added, vec_uint32_t minus_4,
+ vec_uint32_t minus_8, vec_uint32_t minus_12,
+ vec_uint32_t minus_16, vec_uint32_t k) {
+ const vec_uint32_t minus_3 = vec_sro(minus_4, k_4_bytes);
+ const vec_uint32_t minus_14 = vec_sld((minus_12), (minus_16), 8);
+ const vec_uint32_t k_1_bit = vec_splat_u32(1);
+ const vec_uint32_t w_prime =
+ vec_rl(minus_3 ^ minus_8 ^ minus_14 ^ minus_16, k_1_bit);
+ const vec_uint32_t w =
+ w_prime ^ vec_rl(vec_slo(w_prime, k_12_bytes), k_1_bit);
+ vec_st(w + k, 0, pre_added);
+ return w;
+}
+
+/* Compute w[i..i+3] using this relation for i in [32, 36, 40 ... 76]
+ * w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]), 2) <<< 2 */
+static vec_uint32_t sched_32_79(vec_uint32_t *pre_added, vec_uint32_t minus_4,
+ vec_uint32_t minus_8, vec_uint32_t minus_16,
+ vec_uint32_t minus_28, vec_uint32_t minus_32,
+ vec_uint32_t k) {
+ const vec_uint32_t minus_6 = vec_sld(minus_4, minus_8, 8);
+ const vec_uint32_t k_2_bits = vec_splat_u32(2);
+ const vec_uint32_t w =
+ vec_rl(minus_6 ^ minus_16 ^ minus_28 ^ minus_32, k_2_bits);
+ vec_st(w + k, 0, pre_added);
+ return w;
+}
+
+/* As pointed out by Wei Dai <weidai@eskimo.com>, F() below can be simplified
+ * to the code in F_00_19. Wei attributes these optimisations to Peter
+ * Gutmann's SHS code, and he attributes it to Rich Schroeppel. #define
+ * F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) I've just become aware of another
+ * tweak to be made, again from Wei Dai, in F_40_59, (x&a)|(y&a) -> (x|y)&a */
+#define F_00_19(b, c, d) ((((c) ^ (d)) & (b)) ^ (d))
+#define F_20_39(b, c, d) ((b) ^ (c) ^ (d))
+#define F_40_59(b, c, d) (((b) & (c)) | (((b) | (c)) & (d)))
+#define F_60_79(b, c, d) F_20_39(b, c, d)
+
+/* We pre-added the K constants during message scheduling. */
+#define BODY_00_19(i, a, b, c, d, e, f) \
+ do { \
+ (f) = w[i] + (e) + rotate((a), 5) + F_00_19((b), (c), (d)); \
+ (b) = rotate((b), 30); \
+ } while (0)
+
+#define BODY_20_39(i, a, b, c, d, e, f) \
+ do { \
+ (f) = w[i] + (e) + rotate((a), 5) + F_20_39((b), (c), (d)); \
+ (b) = rotate((b), 30); \
+ } while (0)
+
+#define BODY_40_59(i, a, b, c, d, e, f) \
+ do { \
+ (f) = w[i] + (e) + rotate((a), 5) + F_40_59((b), (c), (d)); \
+ (b) = rotate((b), 30); \
+ } while (0)
+
+#define BODY_60_79(i, a, b, c, d, e, f) \
+ do { \
+ (f) = w[i] + (e) + rotate((a), 5) + F_60_79((b), (c), (d)); \
+ (b) = rotate((b), 30); \
+ } while (0)
+
+void sha1_block_data_order(uint32_t *state, const uint8_t *data, size_t num) {
+ uint32_t A, B, C, D, E, T;
+
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+
+ for (;;) {
+ vec_uint32_t vw[20];
+ const uint32_t *w = (const uint32_t *)&vw;
+
+ vec_uint32_t k = K_00_19_x_4;
+ const vec_uint32_t w0 = sched_00_15(vw + 0, data + 0, k);
+ BODY_00_19(0, A, B, C, D, E, T);
+ BODY_00_19(1, T, A, B, C, D, E);
+ BODY_00_19(2, E, T, A, B, C, D);
+ BODY_00_19(3, D, E, T, A, B, C);
+
+ const vec_uint32_t w4 = sched_00_15(vw + 1, data + 16, k);
+ BODY_00_19(4, C, D, E, T, A, B);
+ BODY_00_19(5, B, C, D, E, T, A);
+ BODY_00_19(6, A, B, C, D, E, T);
+ BODY_00_19(7, T, A, B, C, D, E);
+
+ const vec_uint32_t w8 = sched_00_15(vw + 2, data + 32, k);
+ BODY_00_19(8, E, T, A, B, C, D);
+ BODY_00_19(9, D, E, T, A, B, C);
+ BODY_00_19(10, C, D, E, T, A, B);
+ BODY_00_19(11, B, C, D, E, T, A);
+
+ const vec_uint32_t w12 = sched_00_15(vw + 3, data + 48, k);
+ BODY_00_19(12, A, B, C, D, E, T);
+ BODY_00_19(13, T, A, B, C, D, E);
+ BODY_00_19(14, E, T, A, B, C, D);
+ BODY_00_19(15, D, E, T, A, B, C);
+
+ const vec_uint32_t w16 = sched_16_31(vw + 4, w12, w8, w4, w0, k);
+ BODY_00_19(16, C, D, E, T, A, B);
+ BODY_00_19(17, B, C, D, E, T, A);
+ BODY_00_19(18, A, B, C, D, E, T);
+ BODY_00_19(19, T, A, B, C, D, E);
+
+ k = K_20_39_x_4;
+ const vec_uint32_t w20 = sched_16_31(vw + 5, w16, w12, w8, w4, k);
+ BODY_20_39(20, E, T, A, B, C, D);
+ BODY_20_39(21, D, E, T, A, B, C);
+ BODY_20_39(22, C, D, E, T, A, B);
+ BODY_20_39(23, B, C, D, E, T, A);
+
+ const vec_uint32_t w24 = sched_16_31(vw + 6, w20, w16, w12, w8, k);
+ BODY_20_39(24, A, B, C, D, E, T);
+ BODY_20_39(25, T, A, B, C, D, E);
+ BODY_20_39(26, E, T, A, B, C, D);
+ BODY_20_39(27, D, E, T, A, B, C);
+
+ const vec_uint32_t w28 = sched_16_31(vw + 7, w24, w20, w16, w12, k);
+ BODY_20_39(28, C, D, E, T, A, B);
+ BODY_20_39(29, B, C, D, E, T, A);
+ BODY_20_39(30, A, B, C, D, E, T);
+ BODY_20_39(31, T, A, B, C, D, E);
+
+ const vec_uint32_t w32 = sched_32_79(vw + 8, w28, w24, w16, w4, w0, k);
+ BODY_20_39(32, E, T, A, B, C, D);
+ BODY_20_39(33, D, E, T, A, B, C);
+ BODY_20_39(34, C, D, E, T, A, B);
+ BODY_20_39(35, B, C, D, E, T, A);
+
+ const vec_uint32_t w36 = sched_32_79(vw + 9, w32, w28, w20, w8, w4, k);
+ BODY_20_39(36, A, B, C, D, E, T);
+ BODY_20_39(37, T, A, B, C, D, E);
+ BODY_20_39(38, E, T, A, B, C, D);
+ BODY_20_39(39, D, E, T, A, B, C);
+
+ k = K_40_59_x_4;
+ const vec_uint32_t w40 = sched_32_79(vw + 10, w36, w32, w24, w12, w8, k);
+ BODY_40_59(40, C, D, E, T, A, B);
+ BODY_40_59(41, B, C, D, E, T, A);
+ BODY_40_59(42, A, B, C, D, E, T);
+ BODY_40_59(43, T, A, B, C, D, E);
+
+ const vec_uint32_t w44 = sched_32_79(vw + 11, w40, w36, w28, w16, w12, k);
+ BODY_40_59(44, E, T, A, B, C, D);
+ BODY_40_59(45, D, E, T, A, B, C);
+ BODY_40_59(46, C, D, E, T, A, B);
+ BODY_40_59(47, B, C, D, E, T, A);
+
+ const vec_uint32_t w48 = sched_32_79(vw + 12, w44, w40, w32, w20, w16, k);
+ BODY_40_59(48, A, B, C, D, E, T);
+ BODY_40_59(49, T, A, B, C, D, E);
+ BODY_40_59(50, E, T, A, B, C, D);
+ BODY_40_59(51, D, E, T, A, B, C);
+
+ const vec_uint32_t w52 = sched_32_79(vw + 13, w48, w44, w36, w24, w20, k);
+ BODY_40_59(52, C, D, E, T, A, B);
+ BODY_40_59(53, B, C, D, E, T, A);
+ BODY_40_59(54, A, B, C, D, E, T);
+ BODY_40_59(55, T, A, B, C, D, E);
+
+ const vec_uint32_t w56 = sched_32_79(vw + 14, w52, w48, w40, w28, w24, k);
+ BODY_40_59(56, E, T, A, B, C, D);
+ BODY_40_59(57, D, E, T, A, B, C);
+ BODY_40_59(58, C, D, E, T, A, B);
+ BODY_40_59(59, B, C, D, E, T, A);
+
+ k = K_60_79_x_4;
+ const vec_uint32_t w60 = sched_32_79(vw + 15, w56, w52, w44, w32, w28, k);
+ BODY_60_79(60, A, B, C, D, E, T);
+ BODY_60_79(61, T, A, B, C, D, E);
+ BODY_60_79(62, E, T, A, B, C, D);
+ BODY_60_79(63, D, E, T, A, B, C);
+
+ const vec_uint32_t w64 = sched_32_79(vw + 16, w60, w56, w48, w36, w32, k);
+ BODY_60_79(64, C, D, E, T, A, B);
+ BODY_60_79(65, B, C, D, E, T, A);
+ BODY_60_79(66, A, B, C, D, E, T);
+ BODY_60_79(67, T, A, B, C, D, E);
+
+ const vec_uint32_t w68 = sched_32_79(vw + 17, w64, w60, w52, w40, w36, k);
+ BODY_60_79(68, E, T, A, B, C, D);
+ BODY_60_79(69, D, E, T, A, B, C);
+ BODY_60_79(70, C, D, E, T, A, B);
+ BODY_60_79(71, B, C, D, E, T, A);
+
+ const vec_uint32_t w72 = sched_32_79(vw + 18, w68, w64, w56, w44, w40, k);
+ BODY_60_79(72, A, B, C, D, E, T);
+ BODY_60_79(73, T, A, B, C, D, E);
+ BODY_60_79(74, E, T, A, B, C, D);
+ BODY_60_79(75, D, E, T, A, B, C);
+
+ /* We don't use the last value */
+ (void)sched_32_79(vw + 19, w72, w68, w60, w48, w44, k);
+ BODY_60_79(76, C, D, E, T, A, B);
+ BODY_60_79(77, B, C, D, E, T, A);
+ BODY_60_79(78, A, B, C, D, E, T);
+ BODY_60_79(79, T, A, B, C, D, E);
+
+ const uint32_t mask = 0xffffffffUL;
+ state[0] = (state[0] + E) & mask;
+ state[1] = (state[1] + T) & mask;
+ state[2] = (state[2] + A) & mask;
+ state[3] = (state[3] + B) & mask;
+ state[4] = (state[4] + C) & mask;
+
+ data += 64;
+ if (--num == 0) {
+ break;
+ }
+
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+ }
+}
+
+#endif /* OPENSSL_PPC64LE */
diff --git a/src/crypto/sha/sha1.c b/src/crypto/sha/sha1.c
index 0ebed99b..12fb4571 100644
--- a/src/crypto/sha/sha1.c
+++ b/src/crypto/sha/sha1.c
@@ -63,7 +63,8 @@
#if !defined(OPENSSL_NO_ASM) && \
(defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \
- defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64))
+ defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \
+ defined(OPENSSL_PPC64LE))
#define SHA1_ASM
#endif
diff --git a/src/crypto/x509/t_x509.c b/src/crypto/x509/t_x509.c
index 1fba9b43..d5d48ba0 100644
--- a/src/crypto/x509/t_x509.c
+++ b/src/crypto/x509/t_x509.c
@@ -207,7 +207,7 @@ int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
pkey = X509_get_pubkey(x);
if (pkey == NULL) {
BIO_printf(bp, "%12sUnable to load Public Key\n", "");
- BIO_print_errors(bp);
+ ERR_print_errors(bp);
} else {
EVP_PKEY_print_public(bp, pkey, 16, NULL);
EVP_PKEY_free(pkey);
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index dc5af139..c39d98d9 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -17,298 +17,375 @@
#include <assert.h>
#include <string.h>
+#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/pem.h>
+#include <openssl/pool.h>
#include <openssl/x509.h>
namespace bssl {
static const char kCrossSigningRootPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICcTCCAdqgAwIBAgIIagJHiPvE0MowDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwo3qFvSB9Zmlbpzn9wJp\n"
-"ikI75Rxkatez8VkLqyxbOhPYl2Haz8F5p1gDG96dCI6jcLGgu3AKT9uhEQyyUko5\n"
-"EKYasazSeA9CQrdyhPg0mkTYVETnPM1W/ebid1YtqQbq1CMWlq2aTDoSGAReGFKP\n"
-"RTdXAbuAXzpCfi/d8LqV13UCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIEMB0GA1Ud\n"
-"JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MBkGA1Ud\n"
-"DgQSBBBHKHC7V3Z/3oLvEZx0RZRwMBsGA1UdIwQUMBKAEEcocLtXdn/egu8RnHRF\n"
-"lHAwDQYJKoZIhvcNAQELBQADgYEAnglibsy6mGtpIXivtlcz4zIEnHw/lNW+r/eC\n"
-"CY7evZTmOoOuC/x9SS3MF9vawt1HFUummWM6ZgErqVBOXIB4//ykrcCgf5ZbF5Hr\n"
-"+3EFprKhBqYiXdD8hpBkrBoXwn85LPYWNd2TceCrx0YtLIprE2R5MB2RIq8y4Jk3\n"
-"YFXvkME=\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICcTCCAdqgAwIBAgIIagJHiPvE0MowDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+ "dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowPDEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+ "dCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwo3qFvSB9Zmlbpzn9wJp\n"
+ "ikI75Rxkatez8VkLqyxbOhPYl2Haz8F5p1gDG96dCI6jcLGgu3AKT9uhEQyyUko5\n"
+ "EKYasazSeA9CQrdyhPg0mkTYVETnPM1W/ebid1YtqQbq1CMWlq2aTDoSGAReGFKP\n"
+ "RTdXAbuAXzpCfi/d8LqV13UCAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIEMB0GA1Ud\n"
+ "JQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MBkGA1Ud\n"
+ "DgQSBBBHKHC7V3Z/3oLvEZx0RZRwMBsGA1UdIwQUMBKAEEcocLtXdn/egu8RnHRF\n"
+ "lHAwDQYJKoZIhvcNAQELBQADgYEAnglibsy6mGtpIXivtlcz4zIEnHw/lNW+r/eC\n"
+ "CY7evZTmOoOuC/x9SS3MF9vawt1HFUummWM6ZgErqVBOXIB4//ykrcCgf5ZbF5Hr\n"
+ "+3EFprKhBqYiXdD8hpBkrBoXwn85LPYWNd2TceCrx0YtLIprE2R5MB2RIq8y4Jk3\n"
+ "YFXvkME=\n"
+ "-----END CERTIFICATE-----\n";
static const char kRootCAPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICVTCCAb6gAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwLjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwIBcNMTUwMTAx\n"
-"MDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMC4xGjAYBgNVBAoTEUJvcmluZ1NTTCBU\n"
-"RVNUSU5HMRAwDgYDVQQDEwdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
-"iQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM\n"
-"2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw+QzGj+mz36NqhGxDWb6dstB2m8PX+plZ\n"
-"w7jl81MDvUnWs8yiQ/6twgu5AbhWKZQDJKcNKCEpqa6UW0r5nwIDAQABo3oweDAO\n"
-"BgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8G\n"
-"A1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEEA31wH7QC+4HH5UBCeMWQEwGwYDVR0j\n"
-"BBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOBgQDXylEK77Za\n"
-"kKeY6ZerrScWyZhrjIGtHFu09qVpdJEzrk87k2G7iHHR9CAvSofCgEExKtWNS9dN\n"
-"+9WiZp/U48iHLk7qaYXdEuO07No4BYtXn+lkOykE+FUxmA4wvOF1cTd2tdj3MzX2\n"
-"kfGIBAYhzGZWhY3JbhIfTEfY1PNM1pWChQ==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICVTCCAb6gAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwLjEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwIBcNMTUwMTAx\n"
+ "MDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMC4xGjAYBgNVBAoTEUJvcmluZ1NTTCBU\n"
+ "RVNUSU5HMRAwDgYDVQQDEwdSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB\n"
+ "iQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM\n"
+ "2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw+QzGj+mz36NqhGxDWb6dstB2m8PX+plZ\n"
+ "w7jl81MDvUnWs8yiQ/6twgu5AbhWKZQDJKcNKCEpqa6UW0r5nwIDAQABo3oweDAO\n"
+ "BgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8G\n"
+ "A1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEEA31wH7QC+4HH5UBCeMWQEwGwYDVR0j\n"
+ "BBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOBgQDXylEK77Za\n"
+ "kKeY6ZerrScWyZhrjIGtHFu09qVpdJEzrk87k2G7iHHR9CAvSofCgEExKtWNS9dN\n"
+ "+9WiZp/U48iHLk7qaYXdEuO07No4BYtXn+lkOykE+FUxmA4wvOF1cTd2tdj3MzX2\n"
+ "kfGIBAYhzGZWhY3JbhIfTEfY1PNM1pWChQ==\n"
+ "-----END CERTIFICATE-----\n";
static const char kRootCrossSignedPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICYzCCAcygAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
-"dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowLjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwgZ8wDQYJKoZI\n"
-"hvcNAQEBBQADgY0AMIGJAoGBAOkOfxEM5lrmhoNw9lEHLgJ4EfWyJJI47iZiAseU\n"
-"8T6hd2rAj9UiaLZd4kza4IURNcKSckmNgbSIl2u3/LJEW9lNBnD5DMaP6bPfo2qE\n"
-"bENZvp2y0Habw9f6mVnDuOXzUwO9SdazzKJD/q3CC7kBuFYplAMkpw0oISmprpRb\n"
-"SvmfAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcD\n"
-"AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gc\n"
-"flQEJ4xZATAbBgNVHSMEFDASgBBHKHC7V3Z/3oLvEZx0RZRwMA0GCSqGSIb3DQEB\n"
-"CwUAA4GBAErTxYJ0en9HVRHAAr5OO5wuk5Iq3VMc79TMyQLCXVL8YH8Uk7KEwv+q\n"
-"9MEKZv2eR/Vfm4HlXlUuIqfgUXbwrAYC/YVVX86Wnbpy/jc73NYVCq8FEZeO+0XU\n"
-"90SWAPDdp+iL7aZdimnMtG1qlM1edmz8AKbrhN/R3IbA2CL0nCWV\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICYzCCAcygAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwPDEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxHjAcBgNVBAMTFUNyb3NzLXNpZ25pbmcgUm9v\n"
+ "dCBDQTAgFw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowLjEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxEDAOBgNVBAMTB1Jvb3QgQ0EwgZ8wDQYJKoZI\n"
+ "hvcNAQEBBQADgY0AMIGJAoGBAOkOfxEM5lrmhoNw9lEHLgJ4EfWyJJI47iZiAseU\n"
+ "8T6hd2rAj9UiaLZd4kza4IURNcKSckmNgbSIl2u3/LJEW9lNBnD5DMaP6bPfo2qE\n"
+ "bENZvp2y0Habw9f6mVnDuOXzUwO9SdazzKJD/q3CC7kBuFYplAMkpw0oISmprpRb\n"
+ "SvmfAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcD\n"
+ "AQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gc\n"
+ "flQEJ4xZATAbBgNVHSMEFDASgBBHKHC7V3Z/3oLvEZx0RZRwMA0GCSqGSIb3DQEB\n"
+ "CwUAA4GBAErTxYJ0en9HVRHAAr5OO5wuk5Iq3VMc79TMyQLCXVL8YH8Uk7KEwv+q\n"
+ "9MEKZv2eR/Vfm4HlXlUuIqfgUXbwrAYC/YVVX86Wnbpy/jc73NYVCq8FEZeO+0XU\n"
+ "90SWAPDdp+iL7aZdimnMtG1qlM1edmz8AKbrhN/R3IbA2CL0nCWV\n"
+ "-----END CERTIFICATE-----\n";
static const char kIntermediatePEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICXjCCAcegAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMC4xGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRAwDgYDVQQDEwdSb290IENBMCAXDTE1MDEw\n"
-"MTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjA2MRowGAYDVQQKExFCb3JpbmdTU0wg\n"
-"VEVTVElORzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIGfMA0GCSqGSIb3DQEB\n"
-"AQUAA4GNADCBiQKBgQC7YtI0l8ocTYJ0gKyXTtPL4iMJCNY4OcxXl48jkncVG1Hl\n"
-"blicgNUa1r9m9YFtVkxvBinb8dXiUpEGhVg4awRPDcatlsBSEBuJkiZGYbRcAmSu\n"
-"CmZYnf6u3aYQ18SU8WqVERPpE4cwVVs+6kwlzRw0+XDoZAczu8ZezVhCUc6NbQID\n"
-"AQABo3oweDAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\n"
-"AQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEIwaaKi1dttdV3sfjRSy\n"
-"BqMwGwYDVR0jBBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOB\n"
-"gQCvnolNWEHuQS8PFVVyuLR+FKBeUUdrVbSfHSzTqNAqQGp0C9fk5oCzDq6ZgTfY\n"
-"ESXM4cJhb3IAnW0UM0NFsYSKQJ50JZL2L3z5ZLQhHdbs4RmODGoC40BVdnJ4/qgB\n"
-"aGSh09eQRvAVmbVCviDK2ipkWNegdyI19jFfNP5uIkGlYg==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICXjCCAcegAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMC4xGjAYBgNV\n"
+ "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRAwDgYDVQQDEwdSb290IENBMCAXDTE1MDEw\n"
+ "MTAwMDAwMFoYDzIxMDAwMTAxMDAwMDAwWjA2MRowGAYDVQQKExFCb3JpbmdTU0wg\n"
+ "VEVTVElORzEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMIGfMA0GCSqGSIb3DQEB\n"
+ "AQUAA4GNADCBiQKBgQC7YtI0l8ocTYJ0gKyXTtPL4iMJCNY4OcxXl48jkncVG1Hl\n"
+ "blicgNUa1r9m9YFtVkxvBinb8dXiUpEGhVg4awRPDcatlsBSEBuJkiZGYbRcAmSu\n"
+ "CmZYnf6u3aYQ18SU8WqVERPpE4cwVVs+6kwlzRw0+XDoZAczu8ZezVhCUc6NbQID\n"
+ "AQABo3oweDAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsG\n"
+ "AQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEIwaaKi1dttdV3sfjRSy\n"
+ "BqMwGwYDVR0jBBQwEoAQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOB\n"
+ "gQCvnolNWEHuQS8PFVVyuLR+FKBeUUdrVbSfHSzTqNAqQGp0C9fk5oCzDq6ZgTfY\n"
+ "ESXM4cJhb3IAnW0UM0NFsYSKQJ50JZL2L3z5ZLQhHdbs4RmODGoC40BVdnJ4/qgB\n"
+ "aGSh09eQRvAVmbVCviDK2ipkWNegdyI19jFfNP5uIkGlYg==\n"
+ "-----END CERTIFICATE-----\n";
static const char kIntermediateSelfSignedPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICZjCCAc+gAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDYxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0EwgZ8wDQYJ\n"
-"KoZIhvcNAQEBBQADgY0AMIGJAoGBALti0jSXyhxNgnSArJdO08viIwkI1jg5zFeX\n"
-"jyOSdxUbUeVuWJyA1RrWv2b1gW1WTG8GKdvx1eJSkQaFWDhrBE8Nxq2WwFIQG4mS\n"
-"JkZhtFwCZK4KZlid/q7dphDXxJTxapURE+kThzBVWz7qTCXNHDT5cOhkBzO7xl7N\n"
-"WEJRzo1tAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEF\n"
-"BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQjBpoqLV2\n"
-"211Xex+NFLIGozAbBgNVHSMEFDASgBCMGmiotXbbXVd7H40UsgajMA0GCSqGSIb3\n"
-"DQEBCwUAA4GBALcccSrAQ0/EqQBsx0ZDTUydHXXNP2DrUkpUKmAXIe8McqIVSlkT\n"
-"6H4xz7z8VRKBo9j+drjjtCw2i0CQc8aOLxRb5WJ8eVLnaW2XRlUqAzhF0CrulfVI\n"
-"E4Vs6ZLU+fra1WAuIj6qFiigRja+3YkZArG8tMA9vtlhTX/g7YBZIkqH\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICZjCCAc+gAwIBAgIJAKJMH+7rscPcMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
+ "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
+ "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDYxGjAYBgNVBAoTEUJv\n"
+ "cmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0EwgZ8wDQYJ\n"
+ "KoZIhvcNAQEBBQADgY0AMIGJAoGBALti0jSXyhxNgnSArJdO08viIwkI1jg5zFeX\n"
+ "jyOSdxUbUeVuWJyA1RrWv2b1gW1WTG8GKdvx1eJSkQaFWDhrBE8Nxq2WwFIQG4mS\n"
+ "JkZhtFwCZK4KZlid/q7dphDXxJTxapURE+kThzBVWz7qTCXNHDT5cOhkBzO7xl7N\n"
+ "WEJRzo1tAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEF\n"
+ "BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQjBpoqLV2\n"
+ "211Xex+NFLIGozAbBgNVHSMEFDASgBCMGmiotXbbXVd7H40UsgajMA0GCSqGSIb3\n"
+ "DQEBCwUAA4GBALcccSrAQ0/EqQBsx0ZDTUydHXXNP2DrUkpUKmAXIe8McqIVSlkT\n"
+ "6H4xz7z8VRKBo9j+drjjtCw2i0CQc8aOLxRb5WJ8eVLnaW2XRlUqAzhF0CrulfVI\n"
+ "E4Vs6ZLU+fra1WAuIj6qFiigRja+3YkZArG8tMA9vtlhTX/g7YBZIkqH\n"
+ "-----END CERTIFICATE-----\n";
static const char kLeafPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICXjCCAcegAwIBAgIIWjO48ufpunYwDQYJKoZIhvcNAQELBQAwNjEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAg\n"
-"Fw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowMjEaMBgGA1UEChMRQm9y\n"
-"aW5nU1NMIFRFU1RJTkcxFDASBgNVBAMTC2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3\n"
-"DQEBAQUAA4GNADCBiQKBgQDD0U0ZYgqShJ7oOjsyNKyVXEHqeafmk/bAoPqY/h1c\n"
-"oPw2E8KmeqiUSoTPjG5IXSblOxcqpbAXgnjPzo8DI3GNMhAf8SYNYsoH7gc7Uy7j\n"
-"5x8bUrisGnuTHqkqH6d4/e7ETJ7i3CpR8bvK16DggEvQTudLipz8FBHtYhFakfdh\n"
-"TwIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG\n"
-"CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEKN5pvbur7mlXjeMEYA0\n"
-"4nUwGwYDVR0jBBQwEoAQjBpoqLV2211Xex+NFLIGozANBgkqhkiG9w0BAQsFAAOB\n"
-"gQBj/p+JChp//LnXWC1k121LM/ii7hFzQzMrt70bny406SGz9jAjaPOX4S3gt38y\n"
-"rhjpPukBlSzgQXFg66y6q5qp1nQTD1Cw6NkKBe9WuBlY3iYfmsf7WT8nhlT1CttU\n"
-"xNCwyMX9mtdXdQicOfNjIGUCD5OLV5PgHFPRKiHHioBAhg==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICXjCCAcegAwIBAgIIWjO48ufpunYwDQYJKoZIhvcNAQELBQAwNjEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxGDAWBgNVBAMTD0ludGVybWVkaWF0ZSBDQTAg\n"
+ "Fw0xNTAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowMjEaMBgGA1UEChMRQm9y\n"
+ "aW5nU1NMIFRFU1RJTkcxFDASBgNVBAMTC2V4YW1wbGUuY29tMIGfMA0GCSqGSIb3\n"
+ "DQEBAQUAA4GNADCBiQKBgQDD0U0ZYgqShJ7oOjsyNKyVXEHqeafmk/bAoPqY/h1c\n"
+ "oPw2E8KmeqiUSoTPjG5IXSblOxcqpbAXgnjPzo8DI3GNMhAf8SYNYsoH7gc7Uy7j\n"
+ "5x8bUrisGnuTHqkqH6d4/e7ETJ7i3CpR8bvK16DggEvQTudLipz8FBHtYhFakfdh\n"
+ "TwIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG\n"
+ "CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEKN5pvbur7mlXjeMEYA0\n"
+ "4nUwGwYDVR0jBBQwEoAQjBpoqLV2211Xex+NFLIGozANBgkqhkiG9w0BAQsFAAOB\n"
+ "gQBj/p+JChp//LnXWC1k121LM/ii7hFzQzMrt70bny406SGz9jAjaPOX4S3gt38y\n"
+ "rhjpPukBlSzgQXFg66y6q5qp1nQTD1Cw6NkKBe9WuBlY3iYfmsf7WT8nhlT1CttU\n"
+ "xNCwyMX9mtdXdQicOfNjIGUCD5OLV5PgHFPRKiHHioBAhg==\n"
+ "-----END CERTIFICATE-----\n";
static const char kLeafNoKeyUsagePEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICNTCCAZ6gAwIBAgIJAIFQGaLQ0G2mMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
-"BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDcxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRkwFwYDVQQDExBldmlsLmV4YW1wbGUuY29tMIGfMA0G\n"
-"CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOKoZe75NPz77EOaMMl4/0s3PyQw++zJvp\n"
-"ejHAxZiTPCJgMbEHLrSzNoHdopg+CLUH5bE4wTXM8w9Inv5P8OAFJt7gJuPUunmk\n"
-"j+NoU3QfzOR6BroePcz1vXX9jyVHRs087M/sLqWRHu9IR+/A+UTcBaWaFiDVUxtJ\n"
-"YOwFMwjNPQIDAQABo0gwRjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBJfLEUWHq1\n"
-"27rZ1AVx2J5GMBsGA1UdIwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwDQYJKoZIhvcN\n"
-"AQELBQADgYEALVKN2Y3LZJOtu6SxFIYKxbLaXhTGTdIjxipZhmbBRDFjbZjZZOTe\n"
-"6Oo+VDNPYco4rBexK7umYXJyfTqoY0E8dbiImhTcGTEj7OAB3DbBomgU1AYe+t2D\n"
-"uwBqh4Y3Eto+Zn4pMVsxGEfUpjzjZDel7bN1/oU/9KWPpDfywfUmjgk=\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICNTCCAZ6gAwIBAgIJAIFQGaLQ0G2mMA0GCSqGSIb3DQEBCwUAMDYxGjAYBgNV\n"
+ "BAoTEUJvcmluZ1NTTCBURVNUSU5HMRgwFgYDVQQDEw9JbnRlcm1lZGlhdGUgQ0Ew\n"
+ "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDcxGjAYBgNVBAoTEUJv\n"
+ "cmluZ1NTTCBURVNUSU5HMRkwFwYDVQQDExBldmlsLmV4YW1wbGUuY29tMIGfMA0G\n"
+ "CSqGSIb3DQEBAQUAA4GNADCBiQKBgQDOKoZe75NPz77EOaMMl4/0s3PyQw++zJvp\n"
+ "ejHAxZiTPCJgMbEHLrSzNoHdopg+CLUH5bE4wTXM8w9Inv5P8OAFJt7gJuPUunmk\n"
+ "j+NoU3QfzOR6BroePcz1vXX9jyVHRs087M/sLqWRHu9IR+/A+UTcBaWaFiDVUxtJ\n"
+ "YOwFMwjNPQIDAQABo0gwRjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBJfLEUWHq1\n"
+ "27rZ1AVx2J5GMBsGA1UdIwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwDQYJKoZIhvcN\n"
+ "AQELBQADgYEALVKN2Y3LZJOtu6SxFIYKxbLaXhTGTdIjxipZhmbBRDFjbZjZZOTe\n"
+ "6Oo+VDNPYco4rBexK7umYXJyfTqoY0E8dbiImhTcGTEj7OAB3DbBomgU1AYe+t2D\n"
+ "uwBqh4Y3Eto+Zn4pMVsxGEfUpjzjZDel7bN1/oU/9KWPpDfywfUmjgk=\n"
+ "-----END CERTIFICATE-----\n";
static const char kForgeryPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICZzCCAdCgAwIBAgIIdTlMzQoKkeMwDQYJKoZIhvcNAQELBQAwNzEaMBgGA1UE\n"
-"ChMRQm9yaW5nU1NMIFRFU1RJTkcxGTAXBgNVBAMTEGV2aWwuZXhhbXBsZS5jb20w\n"
-"IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDoxGjAYBgNVBAoTEUJv\n"
-"cmluZ1NTTCBURVNUSU5HMRwwGgYDVQQDExNmb3JnZXJ5LmV4YW1wbGUuY29tMIGf\n"
-"MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADTwruBQZGb7Ay6s9HiYv5d1lwtEy\n"
-"xQdA2Sy8Rn8uA20Q4KgqwVY7wzIZ+z5Butrsmwb70gdG1XU+yRaDeE7XVoW6jSpm\n"
-"0sw35/5vJbTcL4THEFbnX0OPZnvpuZDFUkvVtq5kxpDWsVyM24G8EEq7kPih3Sa3\n"
-"OMhXVXF8kso6UQIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI\n"
-"KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEEYJ/WHM\n"
-"8p64erPWIg4/liwwGwYDVR0jBBQwEoAQSXyxFFh6tdu62dQFcdieRjANBgkqhkiG\n"
-"9w0BAQsFAAOBgQA+zH7bHPElWRWJvjxDqRexmYLn+D3Aivs8XgXQJsM94W0EzSUf\n"
-"DSLfRgaQwcb2gg2xpDFoG+W0vc6O651uF23WGt5JaFFJJxqjII05IexfCNhuPmp4\n"
-"4UZAXPttuJXpn74IY1tuouaM06B3vXKZR+/ityKmfJvSwxacmFcK+2ziAg==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICZzCCAdCgAwIBAgIIdTlMzQoKkeMwDQYJKoZIhvcNAQELBQAwNzEaMBgGA1UE\n"
+ "ChMRQm9yaW5nU1NMIFRFU1RJTkcxGTAXBgNVBAMTEGV2aWwuZXhhbXBsZS5jb20w\n"
+ "IBcNMTUwMTAxMDAwMDAwWhgPMjEwMDAxMDEwMDAwMDBaMDoxGjAYBgNVBAoTEUJv\n"
+ "cmluZ1NTTCBURVNUSU5HMRwwGgYDVQQDExNmb3JnZXJ5LmV4YW1wbGUuY29tMIGf\n"
+ "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDADTwruBQZGb7Ay6s9HiYv5d1lwtEy\n"
+ "xQdA2Sy8Rn8uA20Q4KgqwVY7wzIZ+z5Butrsmwb70gdG1XU+yRaDeE7XVoW6jSpm\n"
+ "0sw35/5vJbTcL4THEFbnX0OPZnvpuZDFUkvVtq5kxpDWsVyM24G8EEq7kPih3Sa3\n"
+ "OMhXVXF8kso6UQIDAQABo3cwdTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI\n"
+ "KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwGQYDVR0OBBIEEEYJ/WHM\n"
+ "8p64erPWIg4/liwwGwYDVR0jBBQwEoAQSXyxFFh6tdu62dQFcdieRjANBgkqhkiG\n"
+ "9w0BAQsFAAOBgQA+zH7bHPElWRWJvjxDqRexmYLn+D3Aivs8XgXQJsM94W0EzSUf\n"
+ "DSLfRgaQwcb2gg2xpDFoG+W0vc6O651uF23WGt5JaFFJJxqjII05IexfCNhuPmp4\n"
+ "4UZAXPttuJXpn74IY1tuouaM06B3vXKZR+/ityKmfJvSwxacmFcK+2ziAg==\n"
+ "-----END CERTIFICATE-----\n";
// kExamplePSSCert is an example RSA-PSS self-signed certificate, signed with
// the default hash functions.
static const char kExamplePSSCert[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL\n"
-"MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
-"bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5\n"
-"NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK\n"
-"DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n"
-"MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8\n"
-"0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3\n"
-"13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO\n"
-"MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ\n"
-"QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC\n"
-"AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w\n"
-"xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN\n"
-"Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIICYjCCAcagAwIBAgIJAI3qUyT6SIfzMBIGCSqGSIb3DQEBCjAFogMCAWowRTEL\n"
+ "MAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVy\n"
+ "bmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xNDEwMDkxOTA5NTVaFw0xNTEwMDkxOTA5\n"
+ "NTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQK\n"
+ "DBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwgZ8wDQYJKoZIhvcNAQEBBQADgY0A\n"
+ "MIGJAoGBAPi4bIO0vNmoV8CltFl2jFQdeesiUgR+0zfrQf2D+fCmhRU0dXFahKg8\n"
+ "0u9aTtPel4rd/7vPCqqGkr64UOTNb4AzMHYTj8p73OxaymPHAyXvqIqDWHYg+hZ3\n"
+ "13mSYwFIGth7Z/FSVUlO1m5KXNd6NzYM3t2PROjCpywrta9kS2EHAgMBAAGjUDBO\n"
+ "MB0GA1UdDgQWBBTQQfuJQR6nrVrsNF1JEflVgXgfEzAfBgNVHSMEGDAWgBTQQfuJ\n"
+ "QR6nrVrsNF1JEflVgXgfEzAMBgNVHRMEBTADAQH/MBIGCSqGSIb3DQEBCjAFogMC\n"
+ "AWoDgYEASUy2RZcgNbNQZA0/7F+V1YTLEXwD16bm+iSVnzGwtexmQVEYIZG74K/w\n"
+ "xbdZQdTbpNJkp1QPjPfh0zsatw6dmt5QoZ8K8No0DjR9dgf+Wvv5WJvJUIQBoAVN\n"
+ "Z0IL+OQFz6+LcTHxD27JJCebrATXZA0wThGTQDm7crL+a+SujBY=\n"
+ "-----END CERTIFICATE-----\n";
// kBadPSSCertPEM is a self-signed RSA-PSS certificate with bad parameters.
static const char kBadPSSCertPEM[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDdjCCAjqgAwIBAgIJANcwZLyfEv7DMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZI\n"
-"AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3jAnMSUwIwYD\n"
-"VQQDDBxUZXN0IEludmFsaWQgUFNTIGNlcnRpZmljYXRlMB4XDTE1MTEwNDE2MDIz\n"
-"NVoXDTE1MTIwNDE2MDIzNVowJzElMCMGA1UEAwwcVGVzdCBJbnZhbGlkIFBTUyBj\n"
-"ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTaM7WH\n"
-"qVCAGAIA+zL1KWvvASTrhlq+1ePdO7wsrWX2KiYoTYrJYTnxhLnn0wrHqApt79nL\n"
-"IBG7cfShyZqFHOY/IzlYPMVt+gPo293gw96Fds5JBsjhjkyGnOyr9OUntFqvxDbT\n"
-"IIFU7o9IdxD4edaqjRv+fegVE+B79pDk4s0ujsk6dULtCg9Rst0ucGFo19mr+b7k\n"
-"dbfn8pZ72ZNDJPueVdrUAWw9oll61UcYfk75XdrLk6JlL41GrYHc8KlfXf43gGQq\n"
-"QfrpHkg4Ih2cI6Wt2nhFGAzrlcorzLliQIUJRIhM8h4IgDfpBpaPdVQLqS2pFbXa\n"
-"5eQjqiyJwak2vJ8CAwEAAaNQME4wHQYDVR0OBBYEFCt180N4oGUt5LbzBwQ4Ia+2\n"
-"4V97MB8GA1UdIwQYMBaAFCt180N4oGUt5LbzBwQ4Ia+24V97MAwGA1UdEwQFMAMB\n"
-"Af8wMQYJKoZIhvcNAQEKMCSgDTALBglghkgBZQMEAgGhDTALBgkqhkiG9w0BAQii\n"
-"BAICAN4DggEBAAjBtm90lGxgddjc4Xu/nbXXFHVs2zVcHv/mqOZoQkGB9r/BVgLb\n"
-"xhHrFZ2pHGElbUYPfifdS9ztB73e1d4J+P29o0yBqfd4/wGAc/JA8qgn6AAEO/Xn\n"
-"plhFeTRJQtLZVl75CkHXgUGUd3h+ADvKtcBuW9dSUncaUrgNKR8u/h/2sMG38RWY\n"
-"DzBddC/66YTa3r7KkVUfW7yqRQfELiGKdcm+bjlTEMsvS+EhHup9CzbpoCx2Fx9p\n"
-"NPtFY3yEObQhmL1JyoCRWqBE75GzFPbRaiux5UpEkns+i3trkGssZzsOuVqHNTNZ\n"
-"lC9+9hPHIoc9UMmAQNo1vGIW3NWVoeGbaJ8=\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDdjCCAjqgAwIBAgIJANcwZLyfEv7DMD4GCSqGSIb3DQEBCjAxoA0wCwYJYIZI\n"
+ "AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIEAgIA3jAnMSUwIwYD\n"
+ "VQQDDBxUZXN0IEludmFsaWQgUFNTIGNlcnRpZmljYXRlMB4XDTE1MTEwNDE2MDIz\n"
+ "NVoXDTE1MTIwNDE2MDIzNVowJzElMCMGA1UEAwwcVGVzdCBJbnZhbGlkIFBTUyBj\n"
+ "ZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMTaM7WH\n"
+ "qVCAGAIA+zL1KWvvASTrhlq+1ePdO7wsrWX2KiYoTYrJYTnxhLnn0wrHqApt79nL\n"
+ "IBG7cfShyZqFHOY/IzlYPMVt+gPo293gw96Fds5JBsjhjkyGnOyr9OUntFqvxDbT\n"
+ "IIFU7o9IdxD4edaqjRv+fegVE+B79pDk4s0ujsk6dULtCg9Rst0ucGFo19mr+b7k\n"
+ "dbfn8pZ72ZNDJPueVdrUAWw9oll61UcYfk75XdrLk6JlL41GrYHc8KlfXf43gGQq\n"
+ "QfrpHkg4Ih2cI6Wt2nhFGAzrlcorzLliQIUJRIhM8h4IgDfpBpaPdVQLqS2pFbXa\n"
+ "5eQjqiyJwak2vJ8CAwEAAaNQME4wHQYDVR0OBBYEFCt180N4oGUt5LbzBwQ4Ia+2\n"
+ "4V97MB8GA1UdIwQYMBaAFCt180N4oGUt5LbzBwQ4Ia+24V97MAwGA1UdEwQFMAMB\n"
+ "Af8wMQYJKoZIhvcNAQEKMCSgDTALBglghkgBZQMEAgGhDTALBgkqhkiG9w0BAQii\n"
+ "BAICAN4DggEBAAjBtm90lGxgddjc4Xu/nbXXFHVs2zVcHv/mqOZoQkGB9r/BVgLb\n"
+ "xhHrFZ2pHGElbUYPfifdS9ztB73e1d4J+P29o0yBqfd4/wGAc/JA8qgn6AAEO/Xn\n"
+ "plhFeTRJQtLZVl75CkHXgUGUd3h+ADvKtcBuW9dSUncaUrgNKR8u/h/2sMG38RWY\n"
+ "DzBddC/66YTa3r7KkVUfW7yqRQfELiGKdcm+bjlTEMsvS+EhHup9CzbpoCx2Fx9p\n"
+ "NPtFY3yEObQhmL1JyoCRWqBE75GzFPbRaiux5UpEkns+i3trkGssZzsOuVqHNTNZ\n"
+ "lC9+9hPHIoc9UMmAQNo1vGIW3NWVoeGbaJ8=\n"
+ "-----END CERTIFICATE-----\n";
static const char kRSAKey[] =
-"-----BEGIN RSA PRIVATE KEY-----\n"
-"MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
-"kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
-"KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
-"AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
-"i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
-"WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
-"m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
-"QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
-"aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
-"LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
-"104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
-"tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
-"moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
-"-----END RSA PRIVATE KEY-----\n";
-
-
+ "-----BEGIN RSA PRIVATE KEY-----\n"
+ "MIICXgIBAAKBgQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92\n"
+ "kWdGMdAQhLciHnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiF\n"
+ "KKAnHmUcrgfVW28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQAB\n"
+ "AoGBAIBy09Fd4DOq/Ijp8HeKuCMKTHqTW1xGHshLQ6jwVV2vWZIn9aIgmDsvkjCe\n"
+ "i6ssZvnbjVcwzSoByhjN8ZCf/i15HECWDFFh6gt0P5z0MnChwzZmvatV/FXCT0j+\n"
+ "WmGNB/gkehKjGXLLcjTb6dRYVJSCZhVuOLLcbWIV10gggJQBAkEA8S8sGe4ezyyZ\n"
+ "m4e9r95g6s43kPqtj5rewTsUxt+2n4eVodD+ZUlCULWVNAFLkYRTBCASlSrm9Xhj\n"
+ "QpmWAHJUkQJBAOVzQdFUaewLtdOJoPCtpYoY1zd22eae8TQEmpGOR11L6kbxLQsk\n"
+ "aMly/DOnOaa82tqAGTdqDEZgSNmCeKKknmECQAvpnY8GUOVAubGR6c+W90iBuQLj\n"
+ "LtFp/9ihd2w/PoDwrHZaoUYVcT4VSfJQog/k7kjE4MYXYWL8eEKg3WTWQNECQQDk\n"
+ "104Wi91Umd1PzF0ijd2jXOERJU1wEKe6XLkYYNHWQAe5l4J4MWj9OdxFXAxIuuR/\n"
+ "tfDwbqkta4xcux67//khAkEAvvRXLHTaa6VFzTaiiO8SaFsHV3lQyXOtMrBpB5jd\n"
+ "moZWgjHvB2W9Ckn7sDqsPB+U2tyX0joDdQEyuiMECDY8oQ==\n"
+ "-----END RSA PRIVATE KEY-----\n";
+
+// kCRLTestRoot is a test root certificate. It has private key:
+//
+// -----BEGIN RSA PRIVATE KEY-----
+// MIIEpAIBAAKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3BS/dUBpbrzd1aeFzN
+// lI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+5R/Du0iCb1tCZIPY
+// 07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWpuRqO6rctN9qUoMlT
+// IAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n8H922qmvPNA9idmX
+// 9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbLP2o9orxGx7aCtnnB
+// ZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABAoIBAQCJF9MTHfHGkk+/
+// DwCXlA0Wg0e6hBuHl10iNobYkMWIl/xXjOknhYiqOqb181py76472SVC5ERprC+r
+// Lf0PXzqKuA117mnkwT2bYLCL9Skf8WEhoFLQNbVlloF6wYjqXcYgKYKh8HgQbZl4
+// aLg2YQl2NADTNABsUWj/4H2WEelsODVviqfFs725lFg9KHDI8zxAZXLzDt/M9uVL
+// GxJiX12tr0AwaeAFZ1oPM/y+LznM3N3+Ht3jHHw3jZ/u8Z1RdAmdpu3bZ6tbwGBr
+// 9edsH5rKkm9aBvMrY7eX5VHqaqyRNFyG152ZOJh4XiiFG7EmgTPCpaHo50Y018Re
+// grVtk+FBAoGBANY3lY+V8ZOwMxSHes+kTnoimHO5Ob7nxrOC71i27x+4HHsYUeAr
+// /zOOghiDIn+oNkuiX5CIOWZKx159Bp65CPpCbTb/fh+HYnSgXFgCw7XptycO7LXM
+// 5GwR5jSfpfzBFdYxjxoUzDMFBwTEYRTm0HkUHkH+s+ajjw5wqqbcGLcfAoGBAMM8
+// DKW6Tb66xsf708f0jonAjKYTLZ+WOcwsBEWSFHoY8dUjvW5gqx5acHTEsc5ZTeh4
+// BCFLa+Mn9cuJWVJNs09k7Xb2PNl92HQ4GN2vbdkJhExbkT6oLDHg1hVD0w8KLfz1
+// lTAW6pS+6CdOHMEJpvqx89EgU/1GgIQ1fXYczE75AoGAKeJoXdDFkUjsU+FBhAPu
+// TDcjc80Nm2QaF9NMFR5/lsYa236f06MGnQAKM9zADBHJu/Qdl1brUjLg1HrBppsr
+// RDNkw1IlSOjhuUf5hkPUHGd8Jijm440SRIcjabqla8wdBupdvo2+d2NOQgJbsQiI
+// ToQ+fkzcxAXK3Nnuo/1436UCgYBjLH7UNOZHS8OsVM0I1r8NVKVdu4JCfeJQR8/H
+// s2P5ffBir+wLRMnH+nMDreMQiibcPxMCArkERAlE4jlgaJ38Z62E76KLbLTmnJRt
+// EC9Bv+bXjvAiHvWMRMUbOj/ddPNVez7Uld+FvdBaHwDWQlvzHzBWfBCOKSEhh7Z6
+// qDhUqQKBgQDPMDx2i5rfmQp3imV9xUcCkIRsyYQVf8Eo7NV07IdUy/otmksgn4Zt
+// Lbf3v2dvxOpTNTONWjp2c+iUQo8QxJCZr5Sfb21oQ9Ktcrmc/CY7LeBVDibXwxdM
+// vRG8kBzvslFWh7REzC3u06GSVhyKDfW93kN2cKVwGoahRlhj7oHuZQ==
+// -----END RSA PRIVATE KEY-----
static const char kCRLTestRoot[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDbzCCAlegAwIBAgIJAODri7v0dDUFMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV\n"
-"BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW\n"
-"aWV3MRIwEAYDVQQKDAlCb3JpbmdTU0wwHhcNMTYwOTI2MTUwNjI2WhcNMjYwOTI0\n"
-"MTUwNjI2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG\n"
-"A1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJQm9yaW5nU1NMMIIBIjANBgkq\n"
-"hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3B\n"
-"S/dUBpbrzd1aeFzNlI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+\n"
-"5R/Du0iCb1tCZIPY07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWp\n"
-"uRqO6rctN9qUoMlTIAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n\n"
-"8H922qmvPNA9idmX9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbL\n"
-"P2o9orxGx7aCtnnBZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABo1Aw\n"
-"TjAdBgNVHQ4EFgQUWPt3N5cZ/CRvubbrkqfBnAqhq94wHwYDVR0jBBgwFoAUWPt3\n"
-"N5cZ/CRvubbrkqfBnAqhq94wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
-"AQEAORu6M0MOwXy+3VEBwNilfTxyqDfruQsc1jA4PT8Oe8zora1WxE1JB4q2FJOz\n"
-"EAuM3H/NXvEnBuN+ITvKZAJUfm4NKX97qmjMJwLKWe1gVv+VQTr63aR7mgWJReQN\n"
-"XdMztlVeZs2dppV6uEg3ia1X0G7LARxGpA9ETbMyCpb39XxlYuTClcbA5ftDN99B\n"
-"3Xg9KNdd++Ew22O3HWRDvdDpTO/JkzQfzi3sYwUtzMEonENhczJhGf7bQMmvL/w5\n"
-"24Wxj4Z7KzzWIHsNqE/RIs6RV3fcW61j/mRgW2XyoWnMVeBzvcJr9NXp4VQYmFPw\n"
-"amd8GKMZQvP0ufGnUn7D7uartA==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDbzCCAlegAwIBAgIJAODri7v0dDUFMA0GCSqGSIb3DQEBCwUAME4xCzAJBgNV\n"
+ "BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW\n"
+ "aWV3MRIwEAYDVQQKDAlCb3JpbmdTU0wwHhcNMTYwOTI2MTUwNjI2WhcNMjYwOTI0\n"
+ "MTUwNjI2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG\n"
+ "A1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJQm9yaW5nU1NMMIIBIjANBgkq\n"
+ "hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAo16WiLWZuaymsD8n5SKPmxV1y6jjgr3B\n"
+ "S/dUBpbrzd1aeFzNlI8l2jfAnzUyp+I21RQ+nh/MhqjGElkTtK9xMn1Y+S9GMRh+\n"
+ "5R/Du0iCb1tCZIPY07Tgrb0KMNWe0v2QKVVruuYSgxIWodBfxlKO64Z8AJ5IbnWp\n"
+ "uRqO6rctN9qUoMlTIAB6dL4G0tDJ/PGFWOJYwOMEIX54bly2wgyYJVBKiRRt4f7n\n"
+ "8H922qmvPNA9idmX9G1VAtgV6x97XXi7ULORIQvn9lVQF6nTYDBJhyuPB+mLThbL\n"
+ "P2o9orxGx7aCtnnBZUIxUvHNOI0FaSaZH7Fi0xsZ/GkG2HZe7ImPJwIDAQABo1Aw\n"
+ "TjAdBgNVHQ4EFgQUWPt3N5cZ/CRvubbrkqfBnAqhq94wHwYDVR0jBBgwFoAUWPt3\n"
+ "N5cZ/CRvubbrkqfBnAqhq94wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC\n"
+ "AQEAORu6M0MOwXy+3VEBwNilfTxyqDfruQsc1jA4PT8Oe8zora1WxE1JB4q2FJOz\n"
+ "EAuM3H/NXvEnBuN+ITvKZAJUfm4NKX97qmjMJwLKWe1gVv+VQTr63aR7mgWJReQN\n"
+ "XdMztlVeZs2dppV6uEg3ia1X0G7LARxGpA9ETbMyCpb39XxlYuTClcbA5ftDN99B\n"
+ "3Xg9KNdd++Ew22O3HWRDvdDpTO/JkzQfzi3sYwUtzMEonENhczJhGf7bQMmvL/w5\n"
+ "24Wxj4Z7KzzWIHsNqE/RIs6RV3fcW61j/mRgW2XyoWnMVeBzvcJr9NXp4VQYmFPw\n"
+ "amd8GKMZQvP0ufGnUn7D7uartA==\n"
+ "-----END CERTIFICATE-----\n";
static const char kCRLTestLeaf[] =
-"-----BEGIN CERTIFICATE-----\n"
-"MIIDkDCCAnigAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMx\n"
-"EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEjAQ\n"
-"BgNVBAoMCUJvcmluZ1NTTDAeFw0xNjA5MjYxNTA4MzFaFw0xNzA5MjYxNTA4MzFa\n"
-"MEsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQKDAlC\n"
-"b3JpbmdTU0wxEzARBgNVBAMMCmJvcmluZy5zc2wwggEiMA0GCSqGSIb3DQEBAQUA\n"
-"A4IBDwAwggEKAoIBAQDc5v1S1M0W+QWM+raWfO0LH8uvqEwuJQgODqMaGnSlWUx9\n"
-"8iQcnWfjyPja3lWg9K62hSOFDuSyEkysKHDxijz5R93CfLcfnVXjWQDJe7EJTTDP\n"
-"ozEvxN6RjAeYv7CF000euYr3QT5iyBjg76+bon1p0jHZBJeNPP1KqGYgyxp+hzpx\n"
-"e0gZmTlGAXd8JQK4v8kpdYwD6PPifFL/jpmQpqOtQmH/6zcLjY4ojmqpEdBqIKIX\n"
-"+saA29hMq0+NK3K+wgg31RU+cVWxu3tLOIiesETkeDgArjWRS1Vkzbi4v9SJxtNu\n"
-"OZuAxWiynRJw3JwH/OFHYZIvQqz68ZBoj96cepjPAgMBAAGjezB5MAkGA1UdEwQC\n"
-"MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl\n"
-"MB0GA1UdDgQWBBTGn0OVVh/aoYt0bvEKG+PIERqnDzAfBgNVHSMEGDAWgBRY+3c3\n"
-"lxn8JG+5tuuSp8GcCqGr3jANBgkqhkiG9w0BAQsFAAOCAQEAd2nM8gCQN2Dc8QJw\n"
-"XSZXyuI3DBGGCHcay/3iXu0JvTC3EiQo8J6Djv7WLI0N5KH8mkm40u89fJAB2lLZ\n"
-"ShuHVtcC182bOKnePgwp9CNwQ21p0rDEu/P3X46ZvFgdxx82E9xLa0tBB8PiPDWh\n"
-"lV16jbaKTgX5AZqjnsyjR5o9/mbZVupZJXx5Syq+XA8qiJfstSYJs4KyKK9UOjql\n"
-"ICkJVKpi2ahDBqX4MOH4SLfzVk8pqSpviS6yaA1RXqjpkxiN45WWaXDldVHMSkhC\n"
-"5CNXsXi4b1nAntu89crwSLA3rEwzCWeYj+BX7e1T9rr3oJdwOU/2KQtW1js1yQUG\n"
-"tjJMFw==\n"
-"-----END CERTIFICATE-----\n";
+ "-----BEGIN CERTIFICATE-----\n"
+ "MIIDkDCCAnigAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMx\n"
+ "EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxEjAQ\n"
+ "BgNVBAoMCUJvcmluZ1NTTDAeFw0xNjA5MjYxNTA4MzFaFw0xNzA5MjYxNTA4MzFa\n"
+ "MEsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQKDAlC\n"
+ "b3JpbmdTU0wxEzARBgNVBAMMCmJvcmluZy5zc2wwggEiMA0GCSqGSIb3DQEBAQUA\n"
+ "A4IBDwAwggEKAoIBAQDc5v1S1M0W+QWM+raWfO0LH8uvqEwuJQgODqMaGnSlWUx9\n"
+ "8iQcnWfjyPja3lWg9K62hSOFDuSyEkysKHDxijz5R93CfLcfnVXjWQDJe7EJTTDP\n"
+ "ozEvxN6RjAeYv7CF000euYr3QT5iyBjg76+bon1p0jHZBJeNPP1KqGYgyxp+hzpx\n"
+ "e0gZmTlGAXd8JQK4v8kpdYwD6PPifFL/jpmQpqOtQmH/6zcLjY4ojmqpEdBqIKIX\n"
+ "+saA29hMq0+NK3K+wgg31RU+cVWxu3tLOIiesETkeDgArjWRS1Vkzbi4v9SJxtNu\n"
+ "OZuAxWiynRJw3JwH/OFHYZIvQqz68ZBoj96cepjPAgMBAAGjezB5MAkGA1UdEwQC\n"
+ "MAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRl\n"
+ "MB0GA1UdDgQWBBTGn0OVVh/aoYt0bvEKG+PIERqnDzAfBgNVHSMEGDAWgBRY+3c3\n"
+ "lxn8JG+5tuuSp8GcCqGr3jANBgkqhkiG9w0BAQsFAAOCAQEAd2nM8gCQN2Dc8QJw\n"
+ "XSZXyuI3DBGGCHcay/3iXu0JvTC3EiQo8J6Djv7WLI0N5KH8mkm40u89fJAB2lLZ\n"
+ "ShuHVtcC182bOKnePgwp9CNwQ21p0rDEu/P3X46ZvFgdxx82E9xLa0tBB8PiPDWh\n"
+ "lV16jbaKTgX5AZqjnsyjR5o9/mbZVupZJXx5Syq+XA8qiJfstSYJs4KyKK9UOjql\n"
+ "ICkJVKpi2ahDBqX4MOH4SLfzVk8pqSpviS6yaA1RXqjpkxiN45WWaXDldVHMSkhC\n"
+ "5CNXsXi4b1nAntu89crwSLA3rEwzCWeYj+BX7e1T9rr3oJdwOU/2KQtW1js1yQUG\n"
+ "tjJMFw==\n"
+ "-----END CERTIFICATE-----\n";
static const char kBasicCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-"Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV\n"
-"HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN\n"
-"ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo\n"
-"eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os\n"
-"dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv\n"
-"diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho\n"
-"/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==\n"
-"-----END X509 CRL-----\n";
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBpzCBkAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+ "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoA4wDDAKBgNV\n"
+ "HRQEAwIBATANBgkqhkiG9w0BAQsFAAOCAQEAnrBKKgvd9x9zwK9rtUvVeFeJ7+LN\n"
+ "ZEAc+a5oxpPNEsJx6hXoApYEbzXMxuWBQoCs5iEBycSGudct21L+MVf27M38KrWo\n"
+ "eOkq0a2siqViQZO2Fb/SUFR0k9zb8xl86Zf65lgPplALun0bV/HT7MJcl04Tc4os\n"
+ "dsAReBs5nqTGNEd5AlC1iKHvQZkM//MD51DspKnDpsDiUVi54h9C1SpfZmX8H2Vv\n"
+ "diyu0fZ/bPAM3VAGawatf/SyWfBMyKpoPXEG39oAzmjjOj8en82psn7m474IGaho\n"
+ "/vBbhl1ms5qQiLYPjm4YELtnXQoFyC72tBjbdFd/ZE9k4CNKDbxFUXFbkw==\n"
+ "-----END X509 CRL-----\n";
static const char kRevokedCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
-"Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX\n"
-"DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB\n"
-"AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d\n"
-"sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH\n"
-"NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5\n"
-"OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp\n"
-"Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO\n"
-"xzfKY2TzxLiOmctG0hXFkH5J\n"
-"-----END X509 CRL-----\n";
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBvjCBpwIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+ "Qm9yaW5nU1NMFw0xNjA5MjYxNTEyNDRaFw0xNjEwMjYxNTEyNDRaMBUwEwICEAAX\n"
+ "DTE2MDkyNjE1MTIyNlqgDjAMMAoGA1UdFAQDAgECMA0GCSqGSIb3DQEBCwUAA4IB\n"
+ "AQCUGaM4DcWzlQKrcZvI8TMeR8BpsvQeo5BoI/XZu2a8h//PyRyMwYeaOM+3zl0d\n"
+ "sjgCT8b3C1FPgT+P2Lkowv7rJ+FHJRNQkogr+RuqCSPTq65ha4WKlRGWkMFybzVH\n"
+ "NloxC+aU3lgp/NlX9yUtfqYmJek1CDrOOGPrAEAwj1l/BUeYKNGqfBWYJQtPJu+5\n"
+ "OaSvIYGpETCZJscUWODmLEb/O3DM438vLvxonwGqXqS0KX37+CHpUlyhnSovxXxp\n"
+ "Pz4aF+L7OtczxL0GYtD2fR9B7TDMqsNmHXgQrixvvOY7MUdLGbd4RfJL3yA53hyO\n"
+ "xzfKY2TzxLiOmctG0hXFkH5J\n"
+ "-----END X509 CRL-----\n";
static const char kBadIssuerCRL[] =
-"-----BEGIN X509 CRL-----\n"
-"MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
-"CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEWMBQGA1UECgwN\n"
-"Tm90IEJvcmluZ1NTTBcNMTYwOTI2MTUxMjQ0WhcNMTYxMDI2MTUxMjQ0WjAVMBMC\n"
-"AhAAFw0xNjA5MjYxNTEyMjZaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsF\n"
-"AAOCAQEAlBmjOA3Fs5UCq3GbyPEzHkfAabL0HqOQaCP12btmvIf/z8kcjMGHmjjP\n"
-"t85dHbI4Ak/G9wtRT4E/j9i5KML+6yfhRyUTUJKIK/kbqgkj06uuYWuFipURlpDB\n"
-"cm81RzZaMQvmlN5YKfzZV/clLX6mJiXpNQg6zjhj6wBAMI9ZfwVHmCjRqnwVmCUL\n"
-"TybvuTmkryGBqREwmSbHFFjg5ixG/ztwzON/Ly78aJ8Bql6ktCl9+/gh6VJcoZ0q\n"
-"L8V8aT8+Ghfi+zrXM8S9BmLQ9n0fQe0wzKrDZh14EK4sb7zmOzFHSxm3eEXyS98g\n"
-"Od4cjsc3ymNk88S4jpnLRtIVxZB+SQ==\n"
-"-----END X509 CRL-----\n";
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBwjCBqwIBATANBgkqhkiG9w0BAQsFADBSMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEWMBQGA1UECgwN\n"
+ "Tm90IEJvcmluZ1NTTBcNMTYwOTI2MTUxMjQ0WhcNMTYxMDI2MTUxMjQ0WjAVMBMC\n"
+ "AhAAFw0xNjA5MjYxNTEyMjZaoA4wDDAKBgNVHRQEAwIBAjANBgkqhkiG9w0BAQsF\n"
+ "AAOCAQEAlBmjOA3Fs5UCq3GbyPEzHkfAabL0HqOQaCP12btmvIf/z8kcjMGHmjjP\n"
+ "t85dHbI4Ak/G9wtRT4E/j9i5KML+6yfhRyUTUJKIK/kbqgkj06uuYWuFipURlpDB\n"
+ "cm81RzZaMQvmlN5YKfzZV/clLX6mJiXpNQg6zjhj6wBAMI9ZfwVHmCjRqnwVmCUL\n"
+ "TybvuTmkryGBqREwmSbHFFjg5ixG/ztwzON/Ly78aJ8Bql6ktCl9+/gh6VJcoZ0q\n"
+ "L8V8aT8+Ghfi+zrXM8S9BmLQ9n0fQe0wzKrDZh14EK4sb7zmOzFHSxm3eEXyS98g\n"
+ "Od4cjsc3ymNk88S4jpnLRtIVxZB+SQ==\n"
+ "-----END X509 CRL-----\n";
+
+// kKnownCriticalCRL is kBasicCRL but with a critical issuing distribution point
+// extension.
+static const char kKnownCriticalCRL[] =
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBujCBowIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+ "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCEwHzAKBgNV\n"
+ "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wDQYJKoZIhvcNAQELBQADggEBAA+3\n"
+ "i+5e5Ub8sccfgOBs6WVJFI9c8gvJjrJ8/dYfFIAuCyeocs7DFXn1n13CRZ+URR/Q\n"
+ "mVWgU28+xeusuSPYFpd9cyYTcVyNUGNTI3lwgcE/yVjPaOmzSZKdPakApRxtpKKQ\n"
+ "NN/56aQz3bnT/ZSHQNciRB8U6jiD9V30t0w+FDTpGaG+7bzzUH3UVF9xf9Ctp60A\n"
+ "3mfLe0scas7owSt4AEFuj2SPvcE7yvdOXbu+IEv21cEJUVExJAbhvIweHXh6yRW+\n"
+ "7VVeiNzdIjkZjyTmAzoXGha4+wbxXyBRbfH+XWcO/H+8nwyG8Gktdu2QB9S9nnIp\n"
+ "o/1TpfOMSGhMyMoyPrk=\n"
+ "-----END X509 CRL-----\n";
+
+// kUnknownCriticalCRL is kBasicCRL but with an unknown critical extension.
+static const char kUnknownCriticalCRL[] =
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBvDCBpQIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+ "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoCMwITAKBgNV\n"
+ "HRQEAwIBATATBgwqhkiG9xIEAYS3CQABAf8EADANBgkqhkiG9w0BAQsFAAOCAQEA\n"
+ "GvBP0xqL509InMj/3493YVRV+ldTpBv5uTD6jewzf5XdaxEQ/VjTNe5zKnxbpAib\n"
+ "Kf7cwX0PMSkZjx7k7kKdDlEucwVvDoqC+O9aJcqVmM6GDyNb9xENxd0XCXja6MZC\n"
+ "yVgP4AwLauB2vSiEprYJyI1APph3iAEeDm60lTXX/wBM/tupQDDujKh2GPyvBRfJ\n"
+ "+wEDwGg3ICwvu4gO4zeC5qnFR+bpL9t5tOMAQnVZ0NWv+k7mkd2LbHdD44dxrfXC\n"
+ "nhtfERx99SDmC/jtUAJrGhtCO8acr7exCeYcduN7KKCm91OeCJKK6OzWst0Og1DB\n"
+ "kwzzU2rL3G65CrZ7H0SZsQ==\n"
+ "-----END X509 CRL-----\n";
+
+// kUnknownCriticalCRL2 is kBasicCRL but with a critical issuing distribution
+// point extension followed by an unknown critical extension
+static const char kUnknownCriticalCRL2[] =
+ "-----BEGIN X509 CRL-----\n"
+ "MIIBzzCBuAIBATANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzETMBEGA1UE\n"
+ "CAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzESMBAGA1UECgwJ\n"
+ "Qm9yaW5nU1NMFw0xNjA5MjYxNTEwNTVaFw0xNjEwMjYxNTEwNTVaoDYwNDAKBgNV\n"
+ "HRQEAwIBATARBgNVHRwBAf8EBzAFoQMBAf8wEwYMKoZIhvcSBAGEtwkAAQH/BAAw\n"
+ "DQYJKoZIhvcNAQELBQADggEBACTcpQC8jXL12JN5YzOcQ64ubQIe0XxRAd30p7qB\n"
+ "BTXGpgqBjrjxRfLms7EBYodEXB2oXMsDq3km0vT1MfYdsDD05S+SQ9CDsq/pUfaC\n"
+ "E2WNI5p8WircRnroYvbN2vkjlRbMd1+yNITohXYXCJwjEOAWOx3XIM10bwPYBv4R\n"
+ "rDobuLHoMgL3yHgMHmAkP7YpkBucNqeBV8cCdeAZLuhXFWi6yfr3r/X18yWbC/r2\n"
+ "2xXdkrSqXLFo7ToyP8YKTgiXpya4x6m53biEYwa2ULlas0igL6DK7wjYZX95Uy7H\n"
+ "GKljn9weIYiMPV/BzGymwfv2EW0preLwtyJNJPaxbdin6Jc=\n"
+ "-----END X509 CRL-----\n";
// CertFromPEM parses the given, NUL-terminated pem block and returns an
// |X509*|.
@@ -335,9 +412,10 @@ static bssl::UniquePtr<EVP_PKEY> PrivateKeyFromPEM(const char *pem) {
PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr));
}
-// CertsToStack converts a vector of |X509*| to an OpenSSL STACK_OF(X509*),
+// CertsToStack converts a vector of |X509*| to an OpenSSL STACK_OF(X509),
// bumping the reference counts for each certificate in question.
-static STACK_OF(X509)* CertsToStack(const std::vector<X509*> &certs) {
+static bssl::UniquePtr<STACK_OF(X509)> CertsToStack(
+ const std::vector<X509 *> &certs) {
bssl::UniquePtr<STACK_OF(X509)> stack(sk_X509_new_null());
if (!stack) {
return nullptr;
@@ -349,12 +427,13 @@ static STACK_OF(X509)* CertsToStack(const std::vector<X509*> &certs) {
X509_up_ref(cert);
}
- return stack.release();
+ return stack;
}
-// CRLsToStack converts a vector of |X509_CRL*| to an OpenSSL STACK_OF(X509_CRL*),
-// bumping the reference counts for each CRL in question.
-static STACK_OF(X509_CRL)* CRLsToStack(const std::vector<X509_CRL*> &crls) {
+// CRLsToStack converts a vector of |X509_CRL*| to an OpenSSL
+// STACK_OF(X509_CRL), bumping the reference counts for each CRL in question.
+static bssl::UniquePtr<STACK_OF(X509_CRL)> CRLsToStack(
+ const std::vector<X509_CRL *> &crls) {
bssl::UniquePtr<STACK_OF(X509_CRL)> stack(sk_X509_CRL_new_null());
if (!stack) {
return nullptr;
@@ -366,7 +445,7 @@ static STACK_OF(X509_CRL)* CRLsToStack(const std::vector<X509_CRL*> &crls) {
X509_CRL_up_ref(crl);
}
- return stack.release();
+ return stack;
}
static int Verify(X509 *leaf, const std::vector<X509 *> &roots,
@@ -522,13 +601,21 @@ static bool TestCRL() {
bssl::UniquePtr<X509_CRL> basic_crl(CRLFromPEM(kBasicCRL));
bssl::UniquePtr<X509_CRL> revoked_crl(CRLFromPEM(kRevokedCRL));
bssl::UniquePtr<X509_CRL> bad_issuer_crl(CRLFromPEM(kBadIssuerCRL));
+ bssl::UniquePtr<X509_CRL> known_critical_crl(CRLFromPEM(kKnownCriticalCRL));
+ bssl::UniquePtr<X509_CRL> unknown_critical_crl(
+ CRLFromPEM(kUnknownCriticalCRL));
+ bssl::UniquePtr<X509_CRL> unknown_critical_crl2(
+ CRLFromPEM(kUnknownCriticalCRL2));
if (!root ||
!leaf ||
!basic_crl ||
!revoked_crl ||
- !bad_issuer_crl) {
- fprintf(stderr, "Failed to parse certificates\n");
+ !bad_issuer_crl ||
+ !known_critical_crl ||
+ !unknown_critical_crl ||
+ !unknown_critical_crl2) {
+ fprintf(stderr, "Failed to parse certificates and CRLs.\n");
return false;
}
@@ -558,6 +645,26 @@ static bool TestCRL() {
return false;
}
+ if (Verify(leaf.get(), {root.get()}, {root.get()}, {known_critical_crl.get()},
+ X509_V_FLAG_CRL_CHECK) != X509_V_OK) {
+ fprintf(stderr, "CRL with known critical extension was rejected.\n");
+ return false;
+ }
+
+ if (Verify(leaf.get(), {root.get()}, {root.get()},
+ {unknown_critical_crl.get()}, X509_V_FLAG_CRL_CHECK) !=
+ X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) {
+ fprintf(stderr, "CRL with unknown critical extension was accepted.\n");
+ return false;
+ }
+
+ if (Verify(leaf.get(), {root.get()}, {root.get()},
+ {unknown_critical_crl2.get()}, X509_V_FLAG_CRL_CHECK) !=
+ X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION) {
+ fprintf(stderr, "CRL with unknown critical extension (2) was accepted.\n");
+ return false;
+ }
+
return true;
}
@@ -639,6 +746,201 @@ static bool TestSignCtx() {
return true;
}
+static bool PEMToDER(bssl::UniquePtr<uint8_t> *out, size_t *out_len,
+ const char *pem) {
+ bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem)));
+ if (!bio) {
+ return false;
+ }
+
+ char *name, *header;
+ uint8_t *data;
+ long data_len;
+ if (!PEM_read_bio(bio.get(), &name, &header, &data, &data_len)) {
+ fprintf(stderr, "failed to read PEM data.\n");
+ return false;
+ }
+ OPENSSL_free(name);
+ OPENSSL_free(header);
+
+ out->reset(data);
+ *out_len = data_len;
+
+ return true;
+}
+
+static bool TestFromBuffer() {
+ size_t data_len;
+ bssl::UniquePtr<uint8_t> data;
+ if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+ return false;
+ }
+
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+ if (!buf) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+ if (!root) {
+ return false;
+ }
+
+ const uint8_t *enc_pointer = root->cert_info->enc.enc;
+ const uint8_t *buf_pointer = CRYPTO_BUFFER_data(buf.get());
+ if (enc_pointer < buf_pointer ||
+ enc_pointer >= buf_pointer + CRYPTO_BUFFER_len(buf.get())) {
+ fprintf(stderr, "TestFromBuffer: enc does not alias the buffer.\n");
+ return false;
+ }
+
+ buf.reset();
+
+ /* This ensures the X509 took a reference to |buf|, otherwise this will be a
+ * reference to free memory and ASAN should notice. */
+ if (enc_pointer[0] != CBS_ASN1_SEQUENCE) {
+ fprintf(stderr, "TestFromBuffer: enc data is not a SEQUENCE.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestFromBufferTrailingData() {
+ size_t data_len;
+ bssl::UniquePtr<uint8_t> data;
+ if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+ return false;
+ }
+
+ std::unique_ptr<uint8_t[]> trailing_data(new uint8_t[data_len + 1]);
+ memcpy(trailing_data.get(), data.get(), data_len);
+
+ bssl::UniquePtr<CRYPTO_BUFFER> buf_trailing_data(
+ CRYPTO_BUFFER_new(trailing_data.get(), data_len + 1, nullptr));
+ if (!buf_trailing_data) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509> root_trailing_data(
+ X509_parse_from_buffer(buf_trailing_data.get()));
+ if (root_trailing_data) {
+ fprintf(stderr, "TestFromBuffer: trailing data was not rejected.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestFromBufferModified() {
+ size_t data_len;
+ bssl::UniquePtr<uint8_t> data;
+ if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+ return false;
+ }
+
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+ if (!buf) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+ if (!root) {
+ return false;
+ }
+
+ bssl::UniquePtr<ASN1_INTEGER> fourty_two(ASN1_INTEGER_new());
+ ASN1_INTEGER_set(fourty_two.get(), 42);
+ X509_set_serialNumber(root.get(), fourty_two.get());
+
+ if (i2d_X509(root.get(), nullptr) != static_cast<long>(data_len)) {
+ fprintf(stderr,
+ "TestFromBufferModified: i2d_X509 gives different answer before "
+ "marking as modified.\n");
+ return false;
+ }
+
+ X509_CINF_set_modified(root->cert_info);
+
+ if (i2d_X509(root.get(), nullptr) == static_cast<long>(data_len)) {
+ fprintf(stderr,
+ "TestFromBufferModified: i2d_X509 gives same answer after marking "
+ "as modified.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestFromBufferReused() {
+ size_t data_len;
+ bssl::UniquePtr<uint8_t> data;
+ if (!PEMToDER(&data, &data_len, kRootCAPEM)) {
+ return false;
+ }
+
+ bssl::UniquePtr<CRYPTO_BUFFER> buf(
+ CRYPTO_BUFFER_new(data.get(), data_len, nullptr));
+ if (!buf) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509> root(X509_parse_from_buffer(buf.get()));
+ if (!root) {
+ return false;
+ }
+
+ size_t data2_len;
+ bssl::UniquePtr<uint8_t> data2;
+ if (!PEMToDER(&data2, &data2_len, kLeafPEM)) {
+ return false;
+ }
+
+ X509 *x509p = root.get();
+ const uint8_t *inp = data2.get();
+ X509 *ret = d2i_X509(&x509p, &inp, data2_len);
+ if (ret != root.get()) {
+ fprintf(stderr,
+ "TestFromBufferReused: d2i_X509 parsed into a different object.\n");
+ return false;
+ }
+
+ if (root->buf != nullptr) {
+ fprintf(stderr,
+ "TestFromBufferReused: d2i_X509 didn't clear |buf| pointer.\n");
+ return false;
+ }
+
+ // Free |data2| and ensure that |root| took its own copy. Otherwise the
+ // following will trigger a use-after-free.
+ data2.reset();
+
+ uint8_t *i2d = nullptr;
+ int i2d_len = i2d_X509(root.get(), &i2d);
+ if (i2d_len < 0) {
+ return false;
+ }
+ bssl::UniquePtr<uint8_t> i2d_storage(i2d);
+
+ if (!PEMToDER(&data2, &data2_len, kLeafPEM)) {
+ return false;
+ }
+ if (i2d_len != static_cast<long>(data2_len) ||
+ memcmp(data2.get(), i2d, i2d_len) != 0) {
+ fprintf(stderr, "TestFromBufferReused: i2d gave wrong result.\n");
+ return false;
+ }
+
+ if (root->buf != NULL) {
+ fprintf(stderr, "TestFromBufferReused: X509.buf was not cleared.\n");
+ return false;
+ }
+
+ return true;
+}
+
static int Main() {
CRYPTO_library_init();
@@ -646,7 +948,11 @@ static int Main() {
!TestCRL() ||
!TestPSS() ||
!TestBadPSSParameters() ||
- !TestSignCtx()) {
+ !TestSignCtx() ||
+ !TestFromBuffer() ||
+ !TestFromBufferTrailingData() ||
+ !TestFromBufferModified() ||
+ !TestFromBufferReused()) {
return 1;
}
diff --git a/src/crypto/x509/x_crl.c b/src/crypto/x509/x_crl.c
index 89cd5d14..6450e847 100644
--- a/src/crypto/x509/x_crl.c
+++ b/src/crypto/x509/x_crl.c
@@ -283,7 +283,7 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
if ((nid == NID_issuing_distribution_point)
|| (nid == NID_authority_key_identifier)
|| (nid == NID_delta_crl))
- break;;
+ continue;
crl->flags |= EXFLAG_CRITICAL;
break;
}
diff --git a/src/crypto/x509/x_name.c b/src/crypto/x509/x_name.c
index d7dbf804..19f536c2 100644
--- a/src/crypto/x509/x_name.c
+++ b/src/crypto/x509/x_name.c
@@ -346,7 +346,7 @@ static int x509_name_canon(X509_NAME *a)
STACK_OF(STACK_OF_X509_NAME_ENTRY) *intname = NULL;
STACK_OF(X509_NAME_ENTRY) *entries = NULL;
X509_NAME_ENTRY *entry, *tmpentry = NULL;
- int set = -1, ret = 0;
+ int set = -1, ret = 0, len;
size_t i;
if (a->canon_enc) {
@@ -386,7 +386,11 @@ static int x509_name_canon(X509_NAME *a)
/* Finally generate encoding */
- a->canon_enclen = i2d_name_canon(intname, NULL);
+ len = i2d_name_canon(intname, NULL);
+ if (len < 0) {
+ goto err;
+ }
+ a->canon_enclen = len;
p = OPENSSL_malloc(a->canon_enclen);
diff --git a/src/crypto/x509/x_x509.c b/src/crypto/x509/x_x509.c
index 9fdda825..845d4b28 100644
--- a/src/crypto/x509/x_x509.c
+++ b/src/crypto/x509/x_x509.c
@@ -62,6 +62,7 @@
#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
+#include <openssl/pool.h>
#include <openssl/thread.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
@@ -103,9 +104,15 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
ret->akid = NULL;
ret->aux = NULL;
ret->crldp = NULL;
+ ret->buf = NULL;
CRYPTO_new_ex_data(&ret->ex_data);
break;
+ case ASN1_OP_D2I_PRE:
+ CRYPTO_BUFFER_free(ret->buf);
+ ret->buf = NULL;
+ break;
+
case ASN1_OP_D2I_POST:
if (ret->name != NULL)
OPENSSL_free(ret->name);
@@ -121,6 +128,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
policy_cache_free(ret->policy_cache);
GENERAL_NAMES_free(ret->altname);
NAME_CONSTRAINTS_free(ret->nc);
+ CRYPTO_BUFFER_free(ret->buf);
if (ret->name != NULL)
OPENSSL_free(ret->name);
@@ -142,6 +150,31 @@ IMPLEMENT_ASN1_FUNCTIONS(X509)
IMPLEMENT_ASN1_DUP_FUNCTION(X509)
+X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) {
+ X509 *x509 = X509_new();
+ if (x509 == NULL) {
+ return NULL;
+ }
+
+ x509->cert_info->enc.alias_only_on_next_parse = 1;
+
+ const uint8_t *inp = CRYPTO_BUFFER_data(buf);
+ X509 *x509p = x509;
+ X509 *ret = d2i_X509(&x509p, &inp, CRYPTO_BUFFER_len(buf));
+ if (ret == NULL ||
+ (inp - CRYPTO_BUFFER_data(buf)) != (ptrdiff_t) CRYPTO_BUFFER_len(buf)) {
+ X509_free(x509);
+ return NULL;
+ }
+ assert(x509p == x509);
+ assert(ret == x509);
+
+ CRYPTO_BUFFER_up_ref(buf);
+ ret->buf = buf;
+
+ return ret;
+}
+
int X509_up_ref(X509 *x)
{
CRYPTO_refcount_inc(&x->references);
diff --git a/src/include/openssl/asn1.h b/src/include/openssl/asn1.h
index c8b32e72..42386e0c 100644
--- a/src/include/openssl/asn1.h
+++ b/src/include/openssl/asn1.h
@@ -246,7 +246,15 @@ typedef struct ASN1_ENCODING_st
{
unsigned char *enc; /* DER encoding */
long len; /* Length of encoding */
- int modified; /* set to 1 if 'enc' is invalid */
+ int modified; /* set to 1 if 'enc' is invalid */
+ /* alias_only is zero if |enc| owns the buffer that it points to
+ * (although |enc| may still be NULL). If one, |enc| points into a
+ * buffer that is owned elsewhere. */
+ unsigned alias_only:1;
+ /* alias_only_on_next_parse is one iff the next parsing operation
+ * should avoid taking a copy of the input and rather set
+ * |alias_only|. */
+ unsigned alias_only_on_next_parse:1;
} ASN1_ENCODING;
/* Used with ASN1 LONG type: if a long is set to this it is omitted */
diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h
index 10a22ce7..14c243b8 100644
--- a/src/include/openssl/base.h
+++ b/src/include/openssl/base.h
@@ -114,6 +114,10 @@ extern "C" {
#define OPENSSL_WINDOWS
#endif
+#if defined(__linux__)
+#define OPENSSL_LINUX
+#endif
+
#if defined(TRUSTY)
#define OPENSSL_TRUSTY
#define OPENSSL_NO_THREADS
@@ -185,6 +189,10 @@ extern "C" {
#define OPENSSL_MSVC_PRAGMA(arg)
#endif
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) && \
+ !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+#define BORINGSSL_UNSAFE_DETERMINISTIC_MODE
+#endif
/* CRYPTO_THREADID is a dummy value. */
typedef int CRYPTO_THREADID;
@@ -255,6 +263,8 @@ typedef struct cbs_st CBS;
typedef struct cmac_ctx_st CMAC_CTX;
typedef struct conf_st CONF;
typedef struct conf_value_st CONF_VALUE;
+typedef struct crypto_buffer_pool_st CRYPTO_BUFFER_POOL;
+typedef struct crypto_buffer_st CRYPTO_BUFFER;
typedef struct dh_st DH;
typedef struct dsa_st DSA;
typedef struct ec_group_st EC_GROUP;
diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h
index 18f9f2ae..3c8b97d4 100644
--- a/src/include/openssl/bio.h
+++ b/src/include/openssl/bio.h
@@ -333,9 +333,9 @@ OPENSSL_EXPORT int BIO_indent(BIO *bio, unsigned indent, unsigned max_indent);
OPENSSL_EXPORT int BIO_hexdump(BIO *bio, const uint8_t *data, size_t len,
unsigned indent);
-/* BIO_print_errors prints the current contents of the error stack to |bio|
+/* ERR_print_errors prints the current contents of the error stack to |bio|
* using human readable strings where possible. */
-OPENSSL_EXPORT void BIO_print_errors(BIO *bio);
+OPENSSL_EXPORT void ERR_print_errors(BIO *bio);
/* BIO_read_asn1 reads a single ASN.1 object from |bio|. If successful it sets
* |*out| to be an allocated buffer (that should be freed with |OPENSSL_free|),
@@ -748,9 +748,6 @@ OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio,
* on one line. */
OPENSSL_EXPORT const BIO_METHOD *BIO_f_base64(void);
-/* ERR_print_errors is an alias for |BIO_print_errors|. */
-OPENSSL_EXPORT void ERR_print_errors(BIO *bio);
-
/* Private functions */
diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h
index 66945cb9..764d8c5f 100644
--- a/src/include/openssl/bn.h
+++ b/src/include/openssl/bn.h
@@ -148,15 +148,17 @@ extern "C" {
#if defined(OPENSSL_64_BIT)
#define BN_ULONG uint64_t
#define BN_BITS2 64
-#define BN_DEC_FMT1 "%" PRIu64
-#define BN_DEC_FMT2 "%019" PRIu64
-#define BN_HEX_FMT1 "%" PRIx64
+#define BN_DEC_FMT1 "%" PRIu64
+#define BN_DEC_FMT2 "%019" PRIu64
+#define BN_HEX_FMT1 "%" PRIx64
+#define BN_HEX_FMT2 "%016" PRIx64
#elif defined(OPENSSL_32_BIT)
#define BN_ULONG uint32_t
#define BN_BITS2 32
-#define BN_DEC_FMT1 "%" PRIu32
-#define BN_DEC_FMT2 "%09" PRIu32
-#define BN_HEX_FMT1 "%" PRIx32
+#define BN_DEC_FMT1 "%" PRIu32
+#define BN_DEC_FMT2 "%09" PRIu32
+#define BN_HEX_FMT1 "%" PRIx32
+#define BN_HEX_FMT2 "%08" PRIx64
#else
#error "Must define either OPENSSL_32_BIT or OPENSSL_64_BIT"
#endif
@@ -582,7 +584,7 @@ OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p,
/* Random and prime number generation. */
/* The following are values for the |top| parameter of |BN_rand|. */
-#define BN_RAND_TOP_ANY -1
+#define BN_RAND_TOP_ANY (-1)
#define BN_RAND_TOP_ONE 0
#define BN_RAND_TOP_TWO 1
diff --git a/src/include/openssl/conf.h b/src/include/openssl/conf.h
index 6e6364f9..0a09e241 100644
--- a/src/include/openssl/conf.h
+++ b/src/include/openssl/conf.h
@@ -155,6 +155,9 @@ OPENSSL_EXPORT void CONF_modules_free(void);
/* OPENSSL_config does nothing. */
OPENSSL_EXPORT void OPENSSL_config(CONF_MUST_BE_NULL *config_name);
+/* OPENSSL_no_config does nothing. */
+OPENSSL_EXPORT void OPENSSL_no_config(void);
+
#if defined(__cplusplus)
} /* extern C */
diff --git a/src/include/openssl/curve25519.h b/src/include/openssl/curve25519.h
index e9ba04d9..19f9daa4 100644
--- a/src/include/openssl/curve25519.h
+++ b/src/include/openssl/curve25519.h
@@ -33,6 +33,9 @@ extern "C" {
* sometimes referred to as “curve25519”, but “X25519” is a more precise name.
* See http://cr.yp.to/ecdh.html and https://tools.ietf.org/html/rfc7748. */
+#define X25519_PRIVATE_KEY_LEN 32
+#define X25519_PUBLIC_VALUE_LEN 32
+
/* X25519_keypair sets |out_public_value| and |out_private_key| to a freshly
* generated, public–private key pair. */
OPENSSL_EXPORT void X25519_keypair(uint8_t out_public_value[32],
@@ -82,6 +85,15 @@ OPENSSL_EXPORT int ED25519_verify(const uint8_t *message, size_t message_len,
const uint8_t signature[64],
const uint8_t public_key[32]);
+/* ED25519_keypair_from_seed calculates a public and private key from an
+ * Ed25519 “seed”. Seed values are not exposed by this API (although they
+ * happen to be the first 32 bytes of a private key) so this function is for
+ * interoperating with systems that may store just a seed instead of a full
+ * private key. */
+OPENSSL_EXPORT void ED25519_keypair_from_seed(uint8_t out_public_key[32],
+ uint8_t out_private_key[64],
+ const uint8_t seed[32]);
+
/* SPAKE2.
*
diff --git a/src/include/openssl/lhash.h b/src/include/openssl/lhash.h
index 0d6d3aef..130ffb1f 100644
--- a/src/include/openssl/lhash.h
+++ b/src/include/openssl/lhash.h
@@ -97,6 +97,7 @@ extern "C" {
*
* LHASH_OF:ASN1_OBJECT
* LHASH_OF:CONF_VALUE
+ * LHASH_OF:CRYPTO_BUFFER
* LHASH_OF:SSL_SESSION */
#define IN_LHASH_H
diff --git a/src/include/openssl/lhash_macros.h b/src/include/openssl/lhash_macros.h
index 1d981073..ca349a97 100644
--- a/src/include/openssl/lhash_macros.h
+++ b/src/include/openssl/lhash_macros.h
@@ -17,11 +17,11 @@
#endif
/* ASN1_OBJECT */
-#define lh_ASN1_OBJECT_new(hash, comp) \
- ((LHASH_OF(ASN1_OBJECT) *)lh_new( \
- CHECKED_CAST(lhash_hash_func, uint32_t (*)(const ASN1_OBJECT *), hash), \
- CHECKED_CAST(lhash_cmp_func, \
- int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \
+#define lh_ASN1_OBJECT_new(hash, comp) \
+ ((LHASH_OF(ASN1_OBJECT) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t(*)(const ASN1_OBJECT *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const ASN1_OBJECT *a, const ASN1_OBJECT *b), \
comp)))
#define lh_ASN1_OBJECT_free(lh) \
@@ -55,11 +55,12 @@
void (*)(ASN1_OBJECT *, void *), func), \
arg);
+
/* CONF_VALUE */
-#define lh_CONF_VALUE_new(hash, comp) \
- ((LHASH_OF(CONF_VALUE) *)lh_new( \
- CHECKED_CAST(lhash_hash_func, uint32_t (*)(const CONF_VALUE *), hash), \
- CHECKED_CAST(lhash_cmp_func, \
+#define lh_CONF_VALUE_new(hash, comp) \
+ ((LHASH_OF(CONF_VALUE) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CONF_VALUE *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
int (*)(const CONF_VALUE *a, const CONF_VALUE *b), comp)))
#define lh_CONF_VALUE_free(lh) \
@@ -92,12 +93,53 @@
void (*)(CONF_VALUE *, void *), func), \
arg);
+
+/* CRYPTO_BUFFER */
+#define lh_CRYPTO_BUFFER_new(hash, comp) \
+ ((LHASH_OF(CRYPTO_BUFFER) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t(*)(const CRYPTO_BUFFER *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const CRYPTO_BUFFER *a, const CRYPTO_BUFFER *b), \
+ comp)))
+
+#define lh_CRYPTO_BUFFER_free(lh) \
+ lh_free(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh));
+
+#define lh_CRYPTO_BUFFER_num_items(lh) \
+ lh_num_items(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh))
+
+#define lh_CRYPTO_BUFFER_retrieve(lh, data) \
+ ((CRYPTO_BUFFER *)lh_retrieve( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, data)))
+
+#define lh_CRYPTO_BUFFER_insert(lh, old_data, data) \
+ lh_insert(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+ CHECKED_CAST(void **, CRYPTO_BUFFER **, old_data), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, data))
+
+#define lh_CRYPTO_BUFFER_delete(lh, data) \
+ ((CRYPTO_BUFFER *)lh_delete( \
+ CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, data)))
+
+#define lh_CRYPTO_BUFFER_doall(lh, func) \
+ lh_doall(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+ CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), func));
+
+#define lh_CRYPTO_BUFFER_doall_arg(lh, func, arg) \
+ lh_doall_arg(CHECKED_CAST(_LHASH *, LHASH_OF(CRYPTO_BUFFER) *, lh), \
+ CHECKED_CAST(void (*)(void *, void *), \
+ void (*)(CRYPTO_BUFFER *, void *), func), \
+ arg);
+
+
/* SSL_SESSION */
-#define lh_SSL_SESSION_new(hash, comp) \
- ((LHASH_OF(SSL_SESSION) *)lh_new( \
- CHECKED_CAST(lhash_hash_func, uint32_t (*)(const SSL_SESSION *), hash), \
- CHECKED_CAST(lhash_cmp_func, \
- int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \
+#define lh_SSL_SESSION_new(hash, comp) \
+ ((LHASH_OF(SSL_SESSION) *)lh_new( \
+ CHECKED_CAST(lhash_hash_func, uint32_t(*)(const SSL_SESSION *), hash), \
+ CHECKED_CAST(lhash_cmp_func, \
+ int (*)(const SSL_SESSION *a, const SSL_SESSION *b), \
comp)))
#define lh_SSL_SESSION_free(lh) \
diff --git a/src/include/openssl/pool.h b/src/include/openssl/pool.h
new file mode 100644
index 00000000..a6dee9fd
--- /dev/null
+++ b/src/include/openssl/pool.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2016, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+#ifndef OPENSSL_HEADER_POOL_H
+#define OPENSSL_HEADER_POOL_H
+
+#include <openssl/base.h>
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+
+/* Buffers and buffer pools.
+ *
+ * |CRYPTO_BUFFER|s are simply reference-counted blobs. A |CRYPTO_BUFFER_POOL| is
+ * an intern table for |CRYPTO_BUFFER|s. This allows for a single copy of a given
+ * blob to be kept in memory and referenced from multiple places. */
+
+
+/* CRYPTO_BUFFER_POOL_new returns a freshly allocated |CRYPTO_BUFFER_POOL| or
+ * NULL on error. */
+OPENSSL_EXPORT CRYPTO_BUFFER_POOL* CRYPTO_BUFFER_POOL_new(void);
+
+/* CRYPTO_BUFFER_POOL_free frees |pool|, which must be empty. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_POOL_free(CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_new returns a |CRYPTO_BUFFER| containing a copy of |data|, or
+ * else NULL on error. If |pool| is not NULL then the returned value may be a
+ * reference to a previously existing |CRYPTO_BUFFER| that contained the same
+ * data. Otherwise, the returned, fresh |CRYPTO_BUFFER| will be added to the
+ * pool. */
+OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new(const uint8_t *data, size_t len,
+ CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_new_from_CBS acts the same as |CRYPTO_BUFFER_new|. */
+OPENSSL_EXPORT CRYPTO_BUFFER *CRYPTO_BUFFER_new_from_CBS(
+ CBS *cbs, CRYPTO_BUFFER_POOL *pool);
+
+/* CRYPTO_BUFFER_free decrements the reference count of |buf|. If there are no
+ * other references, or if the only remaining reference is from a pool, then
+ * |buf| will be freed. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_free(CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_up_ref increments the reference count of |buf| and returns
+ * one. */
+OPENSSL_EXPORT int CRYPTO_BUFFER_up_ref(CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_data returns a pointer to the data contained in |buf|. */
+OPENSSL_EXPORT const uint8_t *CRYPTO_BUFFER_data(const CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_len returns the length, in bytes, of the data contained in
+ * |buf|. */
+OPENSSL_EXPORT size_t CRYPTO_BUFFER_len(const CRYPTO_BUFFER *buf);
+
+/* CRYPTO_BUFFER_init_CBS initialises |out| to point at the data from |buf|. */
+OPENSSL_EXPORT void CRYPTO_BUFFER_init_CBS(const CRYPTO_BUFFER *buf, CBS *out);
+
+
+#if defined(__cplusplus)
+} /* extern C */
+
+extern "C++" {
+
+namespace bssl {
+
+BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER_POOL, CRYPTO_BUFFER_POOL_free)
+BORINGSSL_MAKE_DELETER(CRYPTO_BUFFER, CRYPTO_BUFFER_free)
+
+} // namespace bssl
+
+} /* extern C++ */
+
+#endif
+
+#endif // OPENSSL_HEADER_POOL_H
diff --git a/src/include/openssl/rand.h b/src/include/openssl/rand.h
index 322249c9..0e9a8cd7 100644
--- a/src/include/openssl/rand.h
+++ b/src/include/openssl/rand.h
@@ -62,7 +62,7 @@ OPENSSL_EXPORT void RAND_set_urandom_fd(int fd);
OPENSSL_EXPORT void RAND_enable_fork_unsafe_buffering(int fd);
#endif
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
/* RAND_reset_for_fuzzing resets the fuzzer-only deterministic RNG. This
* function is only defined in the fuzzer-only build configuration. */
OPENSSL_EXPORT void RAND_reset_for_fuzzing(void);
diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h
index 0d78754d..f5b9f9d3 100644
--- a/src/include/openssl/ssl.h
+++ b/src/include/openssl/ssl.h
@@ -562,7 +562,7 @@ OPENSSL_EXPORT int DTLSv1_handle_timeout(SSL *ssl);
#define DTLS1_VERSION 0xfeff
#define DTLS1_2_VERSION 0xfefd
-#define TLS1_3_DRAFT_VERSION 0x7f10
+#define TLS1_3_DRAFT_VERSION 0x7f12
/* 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
@@ -670,8 +670,9 @@ OPENSSL_EXPORT uint32_t SSL_get_options(const SSL *ssl);
#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
/* SSL_MODE_NO_AUTO_CHAIN disables automatically building a certificate chain
- * before sending certificates to the peer.
- * TODO(davidben): Remove this behavior. https://crbug.com/486295. */
+ * before sending certificates to the peer. This flag is set (and the feature
+ * disabled) by default.
+ * TODO(davidben): Remove this behavior. https://crbug.com/boringssl/42. */
#define SSL_MODE_NO_AUTO_CHAIN 0x00000008L
/* SSL_MODE_ENABLE_FALSE_START allows clients to send application data before
@@ -1306,7 +1307,12 @@ OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *cipher,
* [ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES128-GCM-SHA256]
*
* Once an equal-preference group is used, future directives must be
- * opcode-less. */
+ * opcode-less.
+ *
+ * TLS 1.3 ciphers do not participate in this mechanism and instead have a
+ * built-in preference order. Functions to set cipher lists do not affect TLS
+ * 1.3, and functions to query the cipher list do not include TLS 1.3
+ * ciphers. */
/* SSL_DEFAULT_CIPHER_LIST is the default cipher suite configuration. It is
* substituted when a cipher string starts with 'DEFAULT'. */
@@ -2331,9 +2337,9 @@ OPENSSL_EXPORT int SSL_get_servername_type(const SSL *ssl);
/* SSL_CTX_set_tlsext_servername_callback configures |callback| to be called on
* the server after ClientHello extensions have been parsed and returns one.
- * The callback may use |SSL_get_servername| to examine the server_name extension
- * and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be set by
- * calling |SSL_CTX_set_tlsext_servername_arg|.
+ * The callback may use |SSL_get_servername| to examine the server_name
+ * extension and returns a |SSL_TLSEXT_ERR_*| value. The value of |arg| may be
+ * set by calling |SSL_CTX_set_tlsext_servername_arg|.
*
* If the callback returns |SSL_TLSEXT_ERR_NOACK|, the server_name extension is
* not acknowledged in the ServerHello. If the return value is
@@ -2389,7 +2395,10 @@ OPENSSL_EXPORT int SSL_set_alpn_protos(SSL *ssl, const uint8_t *protos,
* |*out_len| to the selected protocol and return |SSL_TLSEXT_ERR_OK| on
* success. It does not pass ownership of the buffer. Otherwise, it should
* return |SSL_TLSEXT_ERR_NOACK|. Other |SSL_TLSEXT_ERR_*| values are
- * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|. */
+ * unimplemented and will be treated as |SSL_TLSEXT_ERR_NOACK|.
+ *
+ * The cipher suite is selected before negotiating ALPN. The callback may use
+ * |SSL_get_pending_cipher| to query the cipher suite. */
OPENSSL_EXPORT void SSL_CTX_set_alpn_select_cb(
SSL_CTX *ctx, int (*cb)(SSL *ssl, const uint8_t **out, uint8_t *out_len,
const uint8_t *in, unsigned in_len, void *arg),
@@ -3107,6 +3116,14 @@ OPENSSL_EXPORT size_t SSL_get_server_random(const SSL *ssl, uint8_t *out,
* NULL if one has not been negotiated yet or there is no pending handshake. */
OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl);
+/* SSL_set_retain_only_sha256_of_client_certs, on a server, sets whether only
+ * the SHA-256 hash of peer's certificate should be saved in memory and in the
+ * session. This can save memory, ticket size and session cache space. If
+ * enabled, |SSL_get_peer_certificate| will return NULL after the handshake
+ * completes. See the |peer_sha256| field of |SSL_SESSION| for the hash. */
+OPENSSL_EXPORT void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl,
+ int enable);
+
/* SSL_CTX_set_retain_only_sha256_of_client_certs, on a server, sets whether
* only the SHA-256 hash of peer's certificate should be saved in memory and in
* the session. This can save memory, ticket size and session cache space. If
@@ -3119,6 +3136,10 @@ OPENSSL_EXPORT void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx,
* GREASE. See draft-davidben-tls-grease-01. */
OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled);
+/* SSL_max_seal_overhead returns the maximum overhead, in bytes, of sealing a
+ * record with |ssl|. */
+OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl);
+
/* Deprecated functions. */
@@ -3613,9 +3634,6 @@ OPENSSL_EXPORT int SSL_set_max_version(SSL *ssl, uint16_t version);
* deprecated. */
typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD;
-typedef struct ssl3_enc_method SSL3_ENC_METHOD;
-typedef struct ssl_aead_ctx_st SSL_AEAD_CTX;
-typedef struct ssl_handshake_st SSL_HANDSHAKE;
struct ssl_cipher_st {
/* name is the OpenSSL name for the cipher. */
@@ -3631,12 +3649,6 @@ struct ssl_cipher_st {
uint32_t algorithm_prf;
};
-typedef struct ssl_ecdh_method_st SSL_ECDH_METHOD;
-typedef struct ssl_ecdh_ctx_st {
- const SSL_ECDH_METHOD *method;
- void *data;
-} SSL_ECDH_CTX;
-
#define SSL_MAX_SSL_SESSION_ID_LENGTH 32
#define SSL_MAX_SID_CTX_LENGTH 32
#define SSL_MAX_MASTER_KEY_LENGTH 48
@@ -3671,19 +3683,23 @@ struct ssl_session_st {
uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH];
char *psk_identity;
- /* peer is the peer's certificate. */
- X509 *peer;
+ /* x509_peer is the peer's certificate. */
+ X509 *x509_peer;
- /* cert_chain is the certificate chain sent by the peer. NOTE: for historical
+ /* x509_chain is the certificate chain sent by the peer. NOTE: for historical
* reasons, when a client (so the peer is a server), the chain includes
* |peer|, but when a server it does not. */
- STACK_OF(X509) *cert_chain;
+ STACK_OF(X509) *x509_chain;
/* verify_result is the result of certificate verification in the case of
* non-fatal certificate errors. */
long verify_result;
+ /* timeout is the lifetime of the session in seconds, measured from |time|. */
long timeout;
+
+ /* time is the time the session was issued, measured in seconds from the UNIX
+ * epoch. */
long time;
const SSL_CIPHER *cipher;
@@ -3788,8 +3804,6 @@ struct ssl_ctx_st {
uint16_t min_version;
struct ssl_cipher_preference_list_st *cipher_list;
- /* same as above but sorted for lookup */
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
/* cipher_list_tls10 is the list of ciphers when TLS 1.0 or greater is in
* use. This only applies to server connections as, for clients, the version
@@ -4091,7 +4105,6 @@ struct ssl_st {
/* crypto */
struct ssl_cipher_preference_list_st *cipher_list;
- STACK_OF(SSL_CIPHER) *cipher_list_by_id;
/* session info */
@@ -4195,8 +4208,10 @@ struct ssl_st {
* we'll advertise support. */
unsigned tlsext_channel_id_enabled:1;
- /* RFC4507 session ticket expected to be received or sent */
- unsigned tlsext_ticket_expected:1;
+ /* retain_only_sha256_of_client_certs is true if we should compute the SHA256
+ * hash of the peer's certificate and then discard it to save memory and
+ * session space. Only effective on the server side. */
+ unsigned retain_only_sha256_of_client_certs:1;
/* TODO(agl): remove once node.js not longer references this. */
int tlsext_status_type;
@@ -4534,6 +4549,9 @@ BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free)
#define SSL_R_DUPLICATE_KEY_SHARE 264
#define SSL_R_NO_GROUPS_SPECIFIED 265
#define SSL_R_NO_SHARED_GROUP 266
+#define SSL_R_PRE_SHARED_KEY_MUST_BE_LAST 267
+#define SSL_R_OLD_SESSION_PRF_HASH_MISMATCH 268
+#define SSL_R_INVALID_SCT_LIST 269
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000
#define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010
#define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020
diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h
index 4a991968..4cf51e1b 100644
--- a/src/include/openssl/ssl3.h
+++ b/src/include/openssl/ssl3.h
@@ -352,6 +352,7 @@ OPENSSL_COMPILE_ASSERT(
#define SSL3_ST_SR_CLNT_HELLO_B (0x111 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT)
#define SSL3_ST_SR_CLNT_HELLO_D (0x113 | SSL_ST_ACCEPT)
+#define SSL3_ST_SR_CLNT_HELLO_E (0x114 | SSL_ST_ACCEPT)
/* write to client */
#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT)
#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT)
diff --git a/src/include/openssl/stack.h b/src/include/openssl/stack.h
index c6e0de32..c0cd0f6f 100644
--- a/src/include/openssl/stack.h
+++ b/src/include/openssl/stack.h
@@ -129,6 +129,7 @@ typedef struct stack_st {
* STACK_OF:BY_DIR_ENTRY
* STACK_OF:BY_DIR_HASH
* STACK_OF:CONF_VALUE
+ * STACK_OF:CRYPTO_BUFFER
* STACK_OF:CRYPTO_EX_DATA_FUNCS
* STACK_OF:DIST_POINT
* STACK_OF:GENERAL_NAME
diff --git a/src/include/openssl/stack_macros.h b/src/include/openssl/stack_macros.h
index d5f47f7b..a5f36fb6 100644
--- a/src/include/openssl/stack_macros.h
+++ b/src/include/openssl/stack_macros.h
@@ -1014,6 +1014,91 @@
copy_func), \
CHECKED_CAST(void (*)(void *), void (*)(CONF_VALUE *), free_func)))
+/* CRYPTO_BUFFER */
+#define sk_CRYPTO_BUFFER_new(comp) \
+ ((STACK_OF(CRYPTO_BUFFER) *)sk_new(CHECKED_CAST( \
+ stack_cmp_func, \
+ int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b), comp)))
+
+#define sk_CRYPTO_BUFFER_new_null() ((STACK_OF(CRYPTO_BUFFER) *)sk_new_null())
+
+#define sk_CRYPTO_BUFFER_num(sk) \
+ sk_num(CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_zero(sk) \
+ sk_zero(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk));
+
+#define sk_CRYPTO_BUFFER_value(sk, i) \
+ ((CRYPTO_BUFFER *)sk_value( \
+ CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk), (i)))
+
+#define sk_CRYPTO_BUFFER_set(sk, i, p) \
+ ((CRYPTO_BUFFER *)sk_set( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (i), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, p)))
+
+#define sk_CRYPTO_BUFFER_free(sk) \
+ sk_free(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_pop_free(sk, free_func) \
+ sk_pop_free( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func))
+
+#define sk_CRYPTO_BUFFER_insert(sk, p, where) \
+ sk_insert(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, p), (where))
+
+#define sk_CRYPTO_BUFFER_delete(sk, where) \
+ ((CRYPTO_BUFFER *)sk_delete( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (where)))
+
+#define sk_CRYPTO_BUFFER_delete_ptr(sk, p) \
+ ((CRYPTO_BUFFER *)sk_delete_ptr( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, p)))
+
+#define sk_CRYPTO_BUFFER_find(sk, out_index, p) \
+ sk_find(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), (out_index), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, p))
+
+#define sk_CRYPTO_BUFFER_shift(sk) \
+ ((CRYPTO_BUFFER *)sk_shift( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_push(sk, p) \
+ sk_push(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(void *, CRYPTO_BUFFER *, p))
+
+#define sk_CRYPTO_BUFFER_pop(sk) \
+ ((CRYPTO_BUFFER *)sk_pop( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_dup(sk) \
+ ((STACK_OF(CRYPTO_BUFFER) *)sk_dup( \
+ CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk)))
+
+#define sk_CRYPTO_BUFFER_sort(sk) \
+ sk_sort(CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_is_sorted(sk) \
+ sk_is_sorted( \
+ CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk))
+
+#define sk_CRYPTO_BUFFER_set_cmp_func(sk, comp) \
+ ((int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b))sk_set_cmp_func( \
+ CHECKED_CAST(_STACK *, STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(stack_cmp_func, \
+ int (*)(const CRYPTO_BUFFER **a, const CRYPTO_BUFFER **b), \
+ comp)))
+
+#define sk_CRYPTO_BUFFER_deep_copy(sk, copy_func, free_func) \
+ ((STACK_OF(CRYPTO_BUFFER) *)sk_deep_copy( \
+ CHECKED_CAST(const _STACK *, const STACK_OF(CRYPTO_BUFFER) *, sk), \
+ CHECKED_CAST(void *(*)(void *), CRYPTO_BUFFER *(*)(CRYPTO_BUFFER *), \
+ copy_func), \
+ CHECKED_CAST(void (*)(void *), void (*)(CRYPTO_BUFFER *), free_func)))
+
/* CRYPTO_EX_DATA_FUNCS */
#define sk_CRYPTO_EX_DATA_FUNCS_new(comp) \
((STACK_OF(CRYPTO_EX_DATA_FUNCS) *)sk_new(CHECKED_CAST( \
diff --git a/src/include/openssl/tls1.h b/src/include/openssl/tls1.h
index 35d31453..dfaf78a4 100644
--- a/src/include/openssl/tls1.h
+++ b/src/include/openssl/tls1.h
@@ -205,13 +205,14 @@ extern "C" {
/* ExtensionType value from RFC4507 */
#define TLSEXT_TYPE_session_ticket 35
-/* ExtensionType values from draft-ietf-tls-tls13-16 */
+/* ExtensionType values from draft-ietf-tls-tls13-18 */
#define TLSEXT_TYPE_supported_groups 10
#define TLSEXT_TYPE_key_share 40
#define TLSEXT_TYPE_pre_shared_key 41
#define TLSEXT_TYPE_early_data 42
#define TLSEXT_TYPE_supported_versions 43
#define TLSEXT_TYPE_cookie 44
+#define TLSEXT_TYPE_psk_key_exchange_modes 45
/* ExtensionType value from RFC5746 */
#define TLSEXT_TYPE_renegotiate 0xff01
diff --git a/src/include/openssl/x509.h b/src/include/openssl/x509.h
index 82044868..8f2e1c3a 100644
--- a/src/include/openssl/x509.h
+++ b/src/include/openssl/x509.h
@@ -77,6 +77,7 @@
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/obj.h>
+#include <openssl/pool.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/stack.h>
@@ -261,6 +262,7 @@ struct x509_st
NAME_CONSTRAINTS *nc;
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
X509_CERT_AUX *aux;
+ CRYPTO_BUFFER *buf;
} /* X509 */;
DECLARE_STACK_OF(X509)
@@ -636,6 +638,12 @@ OPENSSL_EXPORT int X509_NAME_digest(const X509_NAME *data,const EVP_MD *type,
unsigned char *md, unsigned int *len);
#endif
+/* X509_parse_from_buffer parses an X.509 structure from |buf| and returns a
+ * fresh X509 or NULL on error. There must not be any trailing data in |buf|.
+ * The returned structure (if any) holds a reference to |buf| rather than
+ * copying parts of it as a normal |d2i_X509| call would do. */
+OPENSSL_EXPORT X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf);
+
#ifndef OPENSSL_NO_FP_API
OPENSSL_EXPORT X509 *d2i_X509_fp(FILE *fp, X509 **x509);
OPENSSL_EXPORT int i2d_X509_fp(FILE *fp,X509 *x509);
@@ -1074,24 +1082,6 @@ OPENSSL_EXPORT int X509_ATTRIBUTE_count(X509_ATTRIBUTE *attr);
OPENSSL_EXPORT ASN1_OBJECT *X509_ATTRIBUTE_get0_object(X509_ATTRIBUTE *attr);
OPENSSL_EXPORT ASN1_TYPE *X509_ATTRIBUTE_get0_type(X509_ATTRIBUTE *attr, int idx);
-OPENSSL_EXPORT int EVP_PKEY_get_attr_count(const EVP_PKEY *key);
-OPENSSL_EXPORT int EVP_PKEY_get_attr_by_NID(const EVP_PKEY *key, int nid,
- int lastpos);
-OPENSSL_EXPORT int EVP_PKEY_get_attr_by_OBJ(const EVP_PKEY *key, ASN1_OBJECT *obj,
- int lastpos);
-OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_get_attr(const EVP_PKEY *key, int loc);
-OPENSSL_EXPORT X509_ATTRIBUTE *EVP_PKEY_delete_attr(EVP_PKEY *key, int loc);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr(EVP_PKEY *key, X509_ATTRIBUTE *attr);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_OBJ(EVP_PKEY *key,
- const ASN1_OBJECT *obj, int type,
- const unsigned char *bytes, int len);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_NID(EVP_PKEY *key,
- int nid, int type,
- const unsigned char *bytes, int len);
-OPENSSL_EXPORT int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key,
- const char *attrname, int type,
- const unsigned char *bytes, int len);
-
OPENSSL_EXPORT int X509_verify_cert(X509_STORE_CTX *ctx);
/* lookup a cert from a X509 STACK */
diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c
index 780cdc68..46b5efb4 100644
--- a/src/ssl/custom_extensions.c
+++ b/src/ssl/custom_extensions.c
@@ -90,7 +90,7 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) {
!CBB_add_bytes(&contents_cbb, contents, contents_len) ||
!CBB_flush(extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+ ERR_add_error_dataf("extension %u", (unsigned) ext->value);
if (ext->free_callback && 0 < contents_len) {
ext->free_callback(ssl, ext->value, contents, ext->add_arg);
}
@@ -113,7 +113,7 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) {
default:
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
- ERR_add_error_dataf("extension: %u", (unsigned) ext->value);
+ ERR_add_error_dataf("extension %u", (unsigned) ext->value);
return 0;
}
}
@@ -136,7 +136,7 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value,
/* Also, if we didn't send the extension, that's also unacceptable. */
!(ssl->s3->hs->custom_extensions.sent & (1u << index))) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)value);
+ ERR_add_error_dataf("extension %u", (unsigned)value);
*out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
return 0;
}
@@ -145,7 +145,7 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value,
!ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
out_alert, ext->parse_arg)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
- ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+ ERR_add_error_dataf("extension %u", (unsigned)ext->value);
return 0;
}
@@ -169,7 +169,7 @@ int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value,
!ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension),
out_alert, ext->parse_arg)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
- ERR_add_error_dataf("extension: %u", (unsigned)ext->value);
+ ERR_add_error_dataf("extension %u", (unsigned)ext->value);
return 0;
}
diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c
index 7bb2de28..f9bb8f49 100644
--- a/src/ssl/d1_both.c
+++ b/src/ssl/d1_both.c
@@ -433,7 +433,7 @@ int dtls1_get_message(SSL *ssl, int msg_type,
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
return -1;
}
- if (hash_message == ssl_hash_message && !dtls1_hash_current_message(ssl)) {
+ if (hash_message == ssl_hash_message && !ssl_hash_current_message(ssl)) {
return -1;
}
@@ -442,13 +442,12 @@ int dtls1_get_message(SSL *ssl, int msg_type,
return 1;
}
-int dtls1_hash_current_message(SSL *ssl) {
+void dtls1_get_current_message(const SSL *ssl, CBS *out) {
assert(dtls1_is_current_message_complete(ssl));
hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq %
SSL_MAX_HANDSHAKE_FLIGHT];
- return ssl3_update_handshake_hash(ssl, frag->data,
- DTLS1_HM_HEADER_LENGTH + frag->msg_len);
+ CBS_init(out, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len);
}
void dtls1_release_current_message(SSL *ssl, int free_buffer) {
@@ -527,10 +526,10 @@ static void dtls1_update_mtu(SSL *ssl) {
/* dtls1_max_record_size returns the maximum record body length that may be
* written without exceeding the MTU. It accounts for any buffering installed on
* the write BIO. If no record may be written, it returns zero. */
-static size_t dtls1_max_record_size(SSL *ssl) {
+static size_t dtls1_max_record_size(const SSL *ssl) {
size_t ret = ssl->d1->mtu;
- size_t overhead = ssl_max_seal_overhead(ssl);
+ size_t overhead = SSL_max_seal_overhead(ssl);
if (ret <= overhead) {
return 0;
}
@@ -736,21 +735,23 @@ int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
return 1;
}
-int dtls1_finish_message(SSL *ssl, CBB *cbb) {
- uint8_t *msg = NULL;
- size_t len;
- if (!CBB_finish(cbb, &msg, &len) ||
- len > 0xffffffffu ||
- len < DTLS1_HM_HEADER_LENGTH) {
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len) {
+ *out_msg = NULL;
+ if (!CBB_finish(cbb, out_msg, out_len) ||
+ *out_len < DTLS1_HM_HEADER_LENGTH) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- OPENSSL_free(msg);
+ OPENSSL_free(*out_msg);
return 0;
}
/* Fix up the header. Copy the fragment length into the total message
* length. */
- memcpy(msg + 1, msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+ memcpy(*out_msg + 1, *out_msg + DTLS1_HM_HEADER_LENGTH - 3, 3);
+ return 1;
+}
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
ssl3_update_handshake_hash(ssl, msg, len);
ssl->d1->handshake_write_seq++;
diff --git a/src/ssl/d1_pkt.c b/src/ssl/d1_pkt.c
index 099de5db..155359cd 100644
--- a/src/ssl/d1_pkt.c
+++ b/src/ssl/d1_pkt.c
@@ -377,7 +377,7 @@ int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len,
return -1;
}
- size_t max_out = len + ssl_max_seal_overhead(ssl);
+ size_t max_out = len + SSL_max_seal_overhead(ssl);
uint8_t *out;
size_t ciphertext_len;
if (!ssl_write_buffer_init(ssl, &out, max_out) ||
diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c
index 9d791b59..8e92cc9f 100644
--- a/src/ssl/dtls_method.c
+++ b/src/ssl/dtls_method.c
@@ -132,7 +132,7 @@ static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
dtls1_new,
dtls1_free,
dtls1_get_message,
- dtls1_hash_current_message,
+ dtls1_get_current_message,
dtls1_release_current_message,
dtls1_read_app_data,
dtls1_read_change_cipher_spec,
@@ -142,6 +142,7 @@ static const SSL_PROTOCOL_METHOD kDTLSProtocolMethod = {
dtls1_supports_cipher,
dtls1_init_message,
dtls1_finish_message,
+ dtls1_queue_message,
dtls1_write_message,
dtls1_send_change_cipher_spec,
dtls1_expect_flight,
diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c
index a917e024..70d8d96d 100644
--- a/src/ssl/handshake_client.c
+++ b/src/ssl/handshake_client.c
@@ -152,6 +152,7 @@
#include <assert.h>
#include <string.h>
+#include <openssl/aead.h>
#include <openssl/bn.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
@@ -447,7 +448,7 @@ int ssl3_connect(SSL *ssl) {
goto end;
case SSL3_ST_CR_SESSION_TICKET_A:
- if (ssl->tlsext_ticket_expected) {
+ if (ssl->s3->hs->ticket_expected) {
ret = ssl3_get_new_session_ticket(ssl);
if (ret <= 0) {
goto end;
@@ -506,8 +507,6 @@ int ssl3_connect(SSL *ssl) {
break;
case SSL_ST_OK:
- /* Clean a few things up. */
- ssl3_cleanup_key_block(ssl);
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
SSL_SESSION_free(ssl->s3->established_session);
@@ -537,9 +536,6 @@ int ssl3_connect(SSL *ssl) {
/* Remove write buffering now. */
ssl_free_wbio_buffer(ssl);
- ssl_handshake_free(ssl->s3->hs);
- ssl->s3->hs = NULL;
-
const int is_initial_handshake = !ssl->s3->initial_handshake_complete;
ssl->s3->initial_handshake_complete = 1;
if (is_initial_handshake) {
@@ -547,6 +543,9 @@ int ssl3_connect(SSL *ssl) {
ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT);
}
+ ssl_handshake_free(ssl->s3->hs);
+ ssl->s3->hs = NULL;
+
ret = 1;
ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
goto end;
@@ -605,30 +604,48 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out,
return 0;
}
- STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
-
- int any_enabled = 0;
- for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
- const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
- /* Skip disabled ciphers */
- if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
- (cipher->algorithm_auth & ssl->cert->mask_a)) {
- continue;
+ /* Add TLS 1.3 ciphers. Order ChaCha20-Poly1305 relative to AES-GCM based on
+ * hardware support. */
+ if (max_version >= TLS1_3_VERSION) {
+ if (!EVP_has_aes_hardware() &&
+ !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
+ return 0;
}
- if (SSL_CIPHER_get_min_version(cipher) > max_version ||
- SSL_CIPHER_get_max_version(cipher) < min_version) {
- continue;
+ if (!CBB_add_u16(&child, TLS1_CK_AES_128_GCM_SHA256 & 0xffff) ||
+ !CBB_add_u16(&child, TLS1_CK_AES_256_GCM_SHA384 & 0xffff)) {
+ return 0;
}
- any_enabled = 1;
- if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
+ if (EVP_has_aes_hardware() &&
+ !CBB_add_u16(&child, TLS1_CK_CHACHA20_POLY1305_SHA256 & 0xffff)) {
return 0;
}
}
- /* If all ciphers were disabled, return the error to the caller. */
- if (!any_enabled) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
- return 0;
+ if (min_version < TLS1_3_VERSION) {
+ STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl);
+ int any_enabled = 0;
+ for (size_t i = 0; i < sk_SSL_CIPHER_num(ciphers); i++) {
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ciphers, i);
+ /* Skip disabled ciphers */
+ if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
+ (cipher->algorithm_auth & ssl->cert->mask_a)) {
+ continue;
+ }
+ if (SSL_CIPHER_get_min_version(cipher) > max_version ||
+ SSL_CIPHER_get_max_version(cipher) < min_version) {
+ continue;
+ }
+ any_enabled = 1;
+ if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) {
+ return 0;
+ }
+ }
+
+ /* If all ciphers were disabled, return the error to the caller. */
+ if (!any_enabled && max_version < TLS1_3_VERSION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CIPHERS_AVAILABLE);
+ return 0;
+ }
}
/* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is
@@ -649,43 +666,66 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out,
return CBB_flush(out);
}
-int ssl_add_client_hello_body(SSL *ssl, CBB *body) {
+int ssl_write_client_hello(SSL *ssl) {
uint16_t min_version, max_version;
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
return 0;
}
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO)) {
+ goto err;
+ }
+
/* Renegotiations do not participate in session resumption. */
int has_session = ssl->session != NULL &&
!ssl->s3->initial_handshake_complete;
CBB child;
- if (!CBB_add_u16(body, ssl->client_version) ||
- !CBB_add_bytes(body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
- !CBB_add_u8_length_prefixed(body, &child) ||
+ if (!CBB_add_u16(&body, ssl->client_version) ||
+ !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !CBB_add_u8_length_prefixed(&body, &child) ||
(has_session &&
!CBB_add_bytes(&child, ssl->session->session_id,
ssl->session->session_id_length))) {
- return 0;
+ goto err;
}
if (SSL_is_dtls(ssl)) {
- if (!CBB_add_u8_length_prefixed(body, &child) ||
+ if (!CBB_add_u8_length_prefixed(&body, &child) ||
!CBB_add_bytes(&child, ssl->d1->cookie, ssl->d1->cookie_len)) {
- return 0;
+ goto err;
}
}
size_t header_len =
SSL_is_dtls(ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH;
- if (!ssl_write_client_cipher_list(ssl, body, min_version, max_version) ||
- !CBB_add_u8(body, 1 /* one compression method */) ||
- !CBB_add_u8(body, 0 /* null compression */) ||
- !ssl_add_clienthello_tlsext(ssl, body, header_len + CBB_len(body))) {
- return 0;
+ if (!ssl_write_client_cipher_list(ssl, &body, min_version, max_version) ||
+ !CBB_add_u8(&body, 1 /* one compression method */) ||
+ !CBB_add_u8(&body, 0 /* null compression */) ||
+ !ssl_add_clienthello_tlsext(ssl, &body, header_len + CBB_len(&body))) {
+ goto err;
}
- return 1;
+ uint8_t *msg = NULL;
+ size_t len;
+ if (!ssl->method->finish_message(ssl, &cbb, &msg, &len)) {
+ goto err;
+ }
+
+ /* Now that the length prefixes have been computed, fill in the placeholder
+ * PSK binder. */
+ if (ssl->s3->hs->needs_psk_binder &&
+ !tls13_write_psk_binder(ssl, msg, len)) {
+ OPENSSL_free(msg);
+ goto err;
+ }
+
+ return ssl->method->queue_message(ssl, msg, len);
+
+ err:
+ CBB_cleanup(&cbb);
+ return 0;
}
static int ssl3_send_client_hello(SSL *ssl) {
@@ -700,12 +740,9 @@ static int ssl3_send_client_hello(SSL *ssl) {
return -1;
}
- CBB cbb;
- CBB_zero(&cbb);
-
uint16_t min_version, max_version;
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
- goto err;
+ return -1;
}
assert(ssl->state == SSL3_ST_CW_CLNT_HELLO_A);
@@ -741,22 +778,15 @@ static int ssl3_send_client_hello(SSL *ssl) {
* renegerate the client_random. The random must be reused. */
if ((!SSL_is_dtls(ssl) || !ssl->d1->send_cookie) &&
!RAND_bytes(ssl->s3->client_random, sizeof(ssl->s3->client_random))) {
- goto err;
+ return -1;
}
- CBB body;
- if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
- !ssl_add_client_hello_body(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
- goto err;
+ if (!ssl_write_client_hello(ssl)) {
+ return -1;
}
ssl->state = SSL3_ST_CW_CLNT_HELLO_B;
return ssl->method->write_message(ssl);
-
-err:
- CBB_cleanup(&cbb);
- return -1;
}
static int dtls1_get_hello_verify(SSL *ssl) {
@@ -802,8 +832,6 @@ f_err:
}
static int ssl3_get_server_hello(SSL *ssl) {
- STACK_OF(SSL_CIPHER) *sk;
- const SSL_CIPHER *c;
CERT *ct = ssl->cert;
int al = SSL_AD_INTERNAL_ERROR;
CBS server_hello, server_random, session_id;
@@ -911,26 +939,19 @@ static int ssl3_get_server_hello(SSL *ssl) {
CBS_len(&session_id));
}
- c = SSL_get_cipher_by_value(cipher_suite);
+ const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite);
if (c == NULL) {
/* unknown cipher */
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED);
goto f_err;
}
- /* If the cipher is disabled then we didn't sent it in the ClientHello, so if
- * the server selected it, it's an error. */
+
+ /* The cipher must be allowed in the selected version and enabled. */
if ((c->algorithm_mkey & ct->mask_k) || (c->algorithm_auth & ct->mask_a) ||
SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) ||
- SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
- goto f_err;
- }
-
- sk = ssl_get_ciphers_by_id(ssl);
- if (!sk_SSL_CIPHER_find(sk, NULL, c)) {
- /* we did not say we would use this cipher */
+ SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl) ||
+ !sk_SSL_CIPHER_find(SSL_get_ciphers(ssl), NULL, c)) {
al = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
goto f_err;
@@ -1041,14 +1062,14 @@ static int ssl3_get_server_certificate(SSL *ssl) {
goto err;
}
- /* NOTE: Unlike the server half, the client's copy of |cert_chain| includes
+ /* NOTE: Unlike the server half, the client's copy of |x509_chain| includes
* the leaf. */
- sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
- ssl->s3->new_session->cert_chain = chain;
+ sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+ ssl->s3->new_session->x509_chain = chain;
- X509_free(ssl->s3->new_session->peer);
+ X509_free(ssl->s3->new_session->x509_peer);
X509_up_ref(leaf);
- ssl->s3->new_session->peer = leaf;
+ ssl->s3->new_session->x509_peer = leaf;
return 1;
@@ -1100,7 +1121,7 @@ f_err:
static int ssl3_verify_server_cert(SSL *ssl) {
if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result,
- ssl->s3->new_session->cert_chain)) {
+ ssl->s3->new_session->x509_chain)) {
return -1;
}
@@ -1274,7 +1295,7 @@ static int ssl3_get_server_key_exchange(SSL *ssl) {
/* ServerKeyExchange should be signed by the server's public key. */
if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- pkey = X509_get_pubkey(ssl->s3->new_session->peer);
+ pkey = X509_get_pubkey(ssl->s3->new_session->x509_peer);
if (pkey == NULL) {
goto err;
}
@@ -1455,6 +1476,7 @@ static int ssl3_send_client_certificate(SSL *ssl) {
return -1;
}
if (ret == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return -1;
}
@@ -1562,7 +1584,7 @@ static int ssl3_send_client_key_exchange(SSL *ssl) {
goto err;
}
- EVP_PKEY *pkey = X509_get_pubkey(ssl->s3->new_session->peer);
+ EVP_PKEY *pkey = X509_get_pubkey(ssl->s3->new_session->x509_peer);
if (pkey == NULL) {
goto err;
}
@@ -1668,7 +1690,7 @@ static int ssl3_send_client_key_exchange(SSL *ssl) {
/* The message must be added to the finished hash before calculating the
* master secret. */
- if (!ssl->method->finish_message(ssl, &cbb)) {
+ if (!ssl_complete_message(ssl, &cbb)) {
goto err;
}
ssl->state = SSL3_ST_CW_KEY_EXCH_B;
@@ -1785,7 +1807,7 @@ static int ssl3_send_cert_verify(SSL *ssl) {
}
if (!CBB_did_write(&child, sig_len) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -1814,7 +1836,7 @@ static int ssl3_send_next_proto(SSL *ssl) {
ssl->s3->next_proto_negotiated_len) ||
!CBB_add_u8_length_prefixed(&body, &child) ||
!CBB_add_bytes(&child, kZero, padding_len) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return -1;
@@ -1831,16 +1853,8 @@ static int ssl3_send_channel_id(SSL *ssl) {
assert(ssl->state == SSL3_ST_CW_CHANNEL_ID_A);
- if (ssl->tlsext_channel_id_private == NULL &&
- ssl->ctx->channel_id_cb != NULL) {
- EVP_PKEY *key = NULL;
- ssl->ctx->channel_id_cb(ssl, &key);
- if (key != NULL &&
- !SSL_set1_tls_channel_id(ssl, key)) {
- EVP_PKEY_free(key);
- return -1;
- }
- EVP_PKEY_free(key);
+ if (!ssl_do_channel_id_callback(ssl)) {
+ return -1;
}
if (ssl->tlsext_channel_id_private == NULL) {
@@ -1848,55 +1862,17 @@ static int ssl3_send_channel_id(SSL *ssl) {
return -1;
}
- EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
- if (ec_key == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
-
- int ret = -1;
- BIGNUM *x = BN_new();
- BIGNUM *y = BN_new();
- ECDSA_SIG *sig = NULL;
- if (x == NULL || y == NULL ||
- !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
- EC_KEY_get0_public_key(ec_key),
- x, y, NULL)) {
- goto err;
- }
-
- uint8_t digest[EVP_MAX_MD_SIZE];
- size_t digest_len;
- if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
- goto err;
- }
-
- sig = ECDSA_do_sign(digest, digest_len, ec_key);
- if (sig == NULL) {
- goto err;
- }
-
- CBB cbb, body, child;
+ CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
- !CBB_add_u16(&body, TLSEXT_TYPE_channel_id) ||
- !CBB_add_u16_length_prefixed(&body, &child) ||
- !BN_bn2cbb_padded(&child, 32, x) || !BN_bn2cbb_padded(&child, 32, y) ||
- !BN_bn2cbb_padded(&child, 32, sig->r) ||
- !BN_bn2cbb_padded(&child, 32, sig->s) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !tls1_write_channel_id(ssl, &body) ||
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
- goto err;
+ return -1;
}
ssl->state = SSL3_ST_CW_CHANNEL_ID_B;
- ret = ssl->method->write_message(ssl);
-
-err:
- BN_free(x);
- BN_free(y);
- ECDSA_SIG_free(sig);
- return ret;
+ return ssl->method->write_message(ssl);
}
static int ssl3_get_new_session_ticket(SSL *ssl) {
@@ -1919,10 +1895,9 @@ static int ssl3_get_new_session_ticket(SSL *ssl) {
if (CBS_len(&ticket) == 0) {
/* RFC 5077 allows a server to change its mind and send no ticket after
- * negotiating the extension. The value of |tlsext_ticket_expected| is
- * checked in |ssl_update_cache| so is cleared here to avoid an unnecessary
- * update. */
- ssl->tlsext_ticket_expected = 0;
+ * negotiating the extension. The value of |ticket_expected| is checked in
+ * |ssl_update_cache| so is cleared here to avoid an unnecessary update. */
+ ssl->s3->hs->ticket_expected = 0;
return 1;
}
@@ -1940,6 +1915,9 @@ static int ssl3_get_new_session_ticket(SSL *ssl) {
}
}
+ /* |tlsext_tick_lifetime_hint| is measured from when the ticket was issued. */
+ ssl_session_refresh_time(ssl, session);
+
if (!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c
index e0186800..3b66ab7d 100644
--- a/src/ssl/handshake_server.c
+++ b/src/ssl/handshake_server.c
@@ -231,6 +231,7 @@ int ssl3_accept(SSL *ssl) {
case SSL3_ST_SR_CLNT_HELLO_B:
case SSL3_ST_SR_CLNT_HELLO_C:
case SSL3_ST_SR_CLNT_HELLO_D:
+ case SSL3_ST_SR_CLNT_HELLO_E:
ret = ssl3_get_client_hello(ssl);
if (ssl->state == SSL_ST_TLS13) {
break;
@@ -415,7 +416,7 @@ int ssl3_accept(SSL *ssl) {
case SSL3_ST_SW_SESSION_TICKET_A:
case SSL3_ST_SW_SESSION_TICKET_B:
- if (ssl->tlsext_ticket_expected) {
+ if (ssl->s3->hs->ticket_expected) {
ret = ssl3_send_new_session_ticket(ssl);
if (ret <= 0) {
goto end;
@@ -476,18 +477,16 @@ int ssl3_accept(SSL *ssl) {
break;
case SSL_ST_OK:
- /* Clean a few things up. */
- ssl3_cleanup_key_block(ssl);
ssl->method->release_current_message(ssl, 1 /* free_buffer */);
/* If we aren't retaining peer certificates then we can discard it
* now. */
if (ssl->s3->new_session != NULL &&
- ssl->ctx->retain_only_sha256_of_client_certs) {
- X509_free(ssl->s3->new_session->peer);
- ssl->s3->new_session->peer = NULL;
- sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
- ssl->s3->new_session->cert_chain = NULL;
+ ssl->retain_only_sha256_of_client_certs) {
+ X509_free(ssl->s3->new_session->x509_peer);
+ ssl->s3->new_session->x509_peer = NULL;
+ sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+ ssl->s3->new_session->x509_chain = NULL;
}
SSL_SESSION_free(ssl->s3->established_session);
@@ -503,15 +502,13 @@ int ssl3_accept(SSL *ssl) {
/* remove buffering on output */
ssl_free_wbio_buffer(ssl);
- ssl_handshake_free(ssl->s3->hs);
- ssl->s3->hs = NULL;
-
ssl->s3->initial_handshake_complete = 1;
-
ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER);
- ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
+ ssl_handshake_free(ssl->s3->hs);
+ ssl->s3->hs = NULL;
+ ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1);
ret = 1;
goto end;
@@ -556,7 +553,7 @@ int ssl_client_cipher_list_contains_cipher(
}
static int negotiate_version(
- SSL *ssl, int *out_alert,
+ SSL *ssl, uint8_t *out_alert,
const struct ssl_early_callback_ctx *client_hello) {
uint16_t min_version, max_version;
if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
@@ -578,6 +575,9 @@ static int negotiate_version(
return 0;
}
+ /* Choose the newest commonly-supported version advertised by the client.
+ * The client orders the versions according to its preferences, but we're
+ * not required to honor the client's preferences. */
int found_version = 0;
while (CBS_len(&versions) != 0) {
uint16_t ext_version;
@@ -590,10 +590,10 @@ static int negotiate_version(
continue;
}
if (min_version <= ext_version &&
- ext_version <= max_version) {
+ ext_version <= max_version &&
+ (!found_version || version < ext_version)) {
version = ext_version;
found_version = 1;
- break;
}
}
@@ -662,7 +662,8 @@ unsupported_protocol:
}
static int ssl3_get_client_hello(SSL *ssl) {
- int al = SSL_AD_INTERNAL_ERROR, ret = -1;
+ uint8_t al = SSL_AD_INTERNAL_ERROR;
+ int ret = -1;
SSL_SESSION *session = NULL;
if (ssl->state == SSL3_ST_SR_CLNT_HELLO_A) {
@@ -729,76 +730,6 @@ static int ssl3_get_client_hello(SSL *ssl) {
memcpy(ssl->s3->client_random, client_hello.random,
client_hello.random_len);
- /* Determine whether we are doing session resumption. */
- int send_new_ticket = 0;
- switch (
- ssl_get_prev_session(ssl, &session, &send_new_ticket, &client_hello)) {
- case ssl_session_success:
- break;
- case ssl_session_error:
- goto err;
- case ssl_session_retry:
- ssl->rwstate = SSL_PENDING_SESSION;
- goto err;
- }
- ssl->tlsext_ticket_expected = send_new_ticket;
-
- /* The EMS state is needed when making the resumption decision, but
- * extensions are not normally parsed until later. This detects the EMS
- * extension for the resumption decision and it's checked against the result
- * of the normal parse later in this function. */
- CBS ems;
- int have_extended_master_secret =
- ssl->version != SSL3_VERSION &&
- ssl_early_callback_get_extension(&client_hello, &ems,
- TLSEXT_TYPE_extended_master_secret) &&
- CBS_len(&ems) == 0;
-
- int has_session = 0;
- if (session != NULL) {
- if (session->extended_master_secret &&
- !have_extended_master_secret) {
- /* A ClientHello without EMS that attempts to resume a session with EMS
- * is fatal to the connection. */
- al = SSL_AD_HANDSHAKE_FAILURE;
- OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
- goto f_err;
- }
-
- has_session =
- /* Only resume if the session's version matches the negotiated
- * version: most clients do not accept a mismatch. */
- ssl->version == session->ssl_version &&
- /* If the client offers the EMS extension, but the previous session
- * didn't use it, then negotiate a new session. */
- have_extended_master_secret == session->extended_master_secret;
- }
-
- if (has_session) {
- /* Use the old session. */
- ssl->session = session;
- session = NULL;
- ssl->s3->session_reused = 1;
- } else {
- ssl_set_session(ssl, NULL);
- if (!ssl_get_new_session(ssl, 1 /* server */)) {
- goto err;
- }
-
- /* Clear the session ID if we want the session to be single-use. */
- if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
- ssl->s3->new_session->session_id_length = 0;
- }
- }
-
- if (ssl->ctx->dos_protection_cb != NULL &&
- ssl->ctx->dos_protection_cb(&client_hello) == 0) {
- /* Connection rejected for DOS reasons. */
- al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
- goto f_err;
- }
-
/* Only null compression is supported. */
if (memchr(client_hello.compression_methods, 0,
client_hello.compression_methods_len) == NULL) {
@@ -813,30 +744,10 @@ static int ssl3_get_client_hello(SSL *ssl) {
goto err;
}
- if (have_extended_master_secret != ssl->s3->tmp.extended_master_secret) {
- al = SSL_AD_INTERNAL_ERROR;
- OPENSSL_PUT_ERROR(SSL, SSL_R_EMS_STATE_INCONSISTENT);
- goto f_err;
- }
-
ssl->state = SSL3_ST_SR_CLNT_HELLO_D;
}
- /* Determine the remaining connection parameters. This is a separate state so
- * |cert_cb| does not cause earlier logic to run multiple times. */
- assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_D);
-
- if (ssl->session != NULL) {
- /* Check that the cipher is in the list. */
- if (!ssl_client_cipher_list_contains_cipher(
- &client_hello, (uint16_t)ssl->session->cipher->id)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- OPENSSL_PUT_ERROR(SSL, SSL_R_REQUIRED_CIPHER_MISSING);
- goto f_err;
- }
-
- ssl->s3->tmp.new_cipher = ssl->session->cipher;
- } else {
+ if (ssl->state == SSL3_ST_SR_CLNT_HELLO_D) {
/* Call |cert_cb| to update server certificates if required. */
if (ssl->cert->cert_cb != NULL) {
int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
@@ -851,16 +762,92 @@ static int ssl3_get_client_hello(SSL *ssl) {
}
}
- const SSL_CIPHER *c =
+ /* Negotiate the cipher suite. This must be done after |cert_cb| so the
+ * certificate is finalized. */
+ ssl->s3->tmp.new_cipher =
ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
- if (c == NULL) {
+ if (ssl->s3->tmp.new_cipher == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
goto f_err;
}
- ssl->s3->new_session->cipher = c;
- ssl->s3->tmp.new_cipher = c;
+ ssl->state = SSL3_ST_SR_CLNT_HELLO_E;
+ }
+
+ assert(ssl->state == SSL3_ST_SR_CLNT_HELLO_E);
+
+ /* Determine whether we are doing session resumption. */
+ int tickets_supported = 0, renew_ticket = 0;
+ switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket,
+ &client_hello)) {
+ case ssl_session_success:
+ break;
+ case ssl_session_error:
+ goto err;
+ case ssl_session_retry:
+ ssl->rwstate = SSL_PENDING_SESSION;
+ goto err;
+ }
+
+ if (session != NULL) {
+ if (session->extended_master_secret &&
+ !ssl->s3->tmp.extended_master_secret) {
+ /* A ClientHello without EMS that attempts to resume a session with EMS
+ * is fatal to the connection. */
+ al = SSL_AD_HANDSHAKE_FAILURE;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_RESUMED_EMS_SESSION_WITHOUT_EMS_EXTENSION);
+ goto f_err;
+ }
+
+ if (!ssl_session_is_resumable(ssl, session) ||
+ /* If the client offers the EMS extension, but the previous session
+ * didn't use it, then negotiate a new session. */
+ ssl->s3->tmp.extended_master_secret !=
+ session->extended_master_secret) {
+ SSL_SESSION_free(session);
+ session = NULL;
+ }
+ }
+
+ if (session != NULL) {
+ /* Use the old session. */
+ ssl->s3->hs->ticket_expected = renew_ticket;
+ ssl->session = session;
+ session = NULL;
+ ssl->s3->session_reused = 1;
+ } else {
+ ssl->s3->hs->ticket_expected = tickets_supported;
+ ssl_set_session(ssl, NULL);
+ if (!ssl_get_new_session(ssl, 1 /* server */)) {
+ goto err;
+ }
+
+ /* Clear the session ID if we want the session to be single-use. */
+ if (!(ssl->ctx->session_cache_mode & SSL_SESS_CACHE_SERVER)) {
+ ssl->s3->new_session->session_id_length = 0;
+ }
+ }
+
+ if (ssl->ctx->dos_protection_cb != NULL &&
+ ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+ /* Connection rejected for DOS reasons. */
+ al = SSL_AD_INTERNAL_ERROR;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ goto f_err;
+ }
+
+ if (ssl->session == NULL) {
+ ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher;
+
+ /* On new sessions, stash the SNI value in the session. */
+ if (ssl->s3->hs->hostname != NULL) {
+ ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname);
+ if (ssl->s3->new_session->tlsext_hostname == NULL) {
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
+ }
+ }
/* Determine whether to request a client certificate. */
ssl->s3->hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER);
@@ -881,7 +868,13 @@ static int ssl3_get_client_hello(SSL *ssl) {
}
}
- /* Now that the cipher is known, initialize the handshake hash. */
+ /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+ * deferred. Complete it now. */
+ if (!ssl_negotiate_alpn(ssl, &al, &client_hello)) {
+ goto f_err;
+ }
+
+ /* Now that all parameters are known, initialize the handshake hash. */
if (!ssl3_init_handshake_hash(ssl)) {
goto f_err;
}
@@ -953,7 +946,7 @@ static int ssl3_send_server_hello(SSL *ssl) {
!CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
!CBB_add_u8(&body, 0 /* no compression */) ||
!ssl_add_serverhello_tlsext(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return -1;
@@ -992,7 +985,7 @@ static int ssl3_send_certificate_status(SSL *ssl) {
!CBB_add_u24_length_prefixed(&body, &ocsp_response) ||
!CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
ssl->ctx->ocsp_response_length) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return -1;
@@ -1173,7 +1166,7 @@ static int ssl3_send_server_key_exchange(SSL *ssl) {
}
}
- if (!ssl->method->finish_message(ssl, &cbb)) {
+ if (!ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -1255,7 +1248,7 @@ static int ssl3_send_certificate_request(SSL *ssl) {
}
if (!ssl_add_client_CA_list(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -1275,7 +1268,7 @@ static int ssl3_send_server_hello_done(SSL *ssl) {
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO_DONE) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return -1;
@@ -1320,7 +1313,7 @@ static int ssl3_get_client_certificate(SSL *ssl) {
CBS_init(&certificate_msg, ssl->init_msg, ssl->init_num);
uint8_t alert;
STACK_OF(X509) *chain = ssl_parse_cert_chain(
- ssl, &alert, ssl->ctx->retain_only_sha256_of_client_certs
+ ssl, &alert, ssl->retain_only_sha256_of_client_certs
? ssl->s3->new_session->peer_sha256
: NULL,
&certificate_msg);
@@ -1359,7 +1352,7 @@ static int ssl3_get_client_certificate(SSL *ssl) {
ssl->s3->new_session->verify_result = X509_V_OK;
} else {
/* The hash would have been filled in. */
- if (ssl->ctx->retain_only_sha256_of_client_certs) {
+ if (ssl->retain_only_sha256_of_client_certs) {
ssl->s3->new_session->peer_sha256_valid = 1;
}
@@ -1369,12 +1362,12 @@ static int ssl3_get_client_certificate(SSL *ssl) {
}
}
- X509_free(ssl->s3->new_session->peer);
- ssl->s3->new_session->peer = sk_X509_shift(chain);
+ X509_free(ssl->s3->new_session->x509_peer);
+ ssl->s3->new_session->x509_peer = sk_X509_shift(chain);
- sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
- ssl->s3->new_session->cert_chain = chain;
- /* Inconsistency alert: cert_chain does *not* include the peer's own
+ sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+ ssl->s3->new_session->x509_chain = chain;
+ /* Inconsistency alert: x509_chain does *not* include the peer's own
* certificate, while we do include it in s3_clnt.c */
return 1;
@@ -1656,7 +1649,7 @@ err:
static int ssl3_get_cert_verify(SSL *ssl) {
int al, ret = 0;
CBS certificate_verify, signature;
- X509 *peer = ssl->s3->new_session->peer;
+ X509 *peer = ssl->s3->new_session->x509_peer;
EVP_PKEY *pkey = NULL;
/* Only RSA and ECDSA client certificates are supported, so a
@@ -1750,7 +1743,7 @@ static int ssl3_get_cert_verify(SSL *ssl) {
/* The handshake buffer is no longer necessary, and we may hash the current
* message.*/
ssl3_free_handshake_buffer(ssl);
- if (!ssl->method->hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(ssl)) {
goto err;
}
@@ -1796,109 +1789,17 @@ static int ssl3_get_next_proto(SSL *ssl) {
/* ssl3_get_channel_id reads and verifies a ClientID handshake message. */
static int ssl3_get_channel_id(SSL *ssl) {
- int ret = -1;
- uint8_t channel_id_hash[EVP_MAX_MD_SIZE];
- size_t channel_id_hash_len;
- const uint8_t *p;
- uint16_t extension_type;
- EC_GROUP *p256 = NULL;
- EC_KEY *key = NULL;
- EC_POINT *point = NULL;
- ECDSA_SIG sig;
- BIGNUM x, y;
- CBS encrypted_extensions, extension;
-
int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID,
ssl_dont_hash_message);
if (msg_ret <= 0) {
return msg_ret;
}
- /* Before incorporating the EncryptedExtensions message to the handshake
- * hash, compute the hash that should have been signed. */
- if (!tls1_channel_id_hash(ssl, channel_id_hash, &channel_id_hash_len)) {
- return -1;
- }
- assert(channel_id_hash_len == SHA256_DIGEST_LENGTH);
-
- if (!ssl->method->hash_current_message(ssl)) {
- return -1;
- }
-
- CBS_init(&encrypted_extensions, ssl->init_msg, ssl->init_num);
-
- /* EncryptedExtensions could include multiple extensions, but the only
- * extension that could be negotiated is Channel ID, so there can only be one
- * entry. */
- if (!CBS_get_u16(&encrypted_extensions, &extension_type) ||
- !CBS_get_u16_length_prefixed(&encrypted_extensions, &extension) ||
- CBS_len(&encrypted_extensions) != 0 ||
- extension_type != TLSEXT_TYPE_channel_id ||
- CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return -1;
- }
-
- p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
- if (!p256) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
+ if (!tls1_verify_channel_id(ssl) ||
+ !ssl_hash_current_message(ssl)) {
return -1;
}
-
- BN_init(&x);
- BN_init(&y);
- sig.r = BN_new();
- sig.s = BN_new();
- if (sig.r == NULL || sig.s == NULL) {
- goto err;
- }
-
- p = CBS_data(&extension);
- if (BN_bin2bn(p + 0, 32, &x) == NULL ||
- BN_bin2bn(p + 32, 32, &y) == NULL ||
- BN_bin2bn(p + 64, 32, sig.r) == NULL ||
- BN_bin2bn(p + 96, 32, sig.s) == NULL) {
- goto err;
- }
-
- point = EC_POINT_new(p256);
- if (!point ||
- !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
- goto err;
- }
-
- key = EC_KEY_new();
- if (!key || !EC_KEY_set_group(key, p256) ||
- !EC_KEY_set_public_key(key, point)) {
- goto err;
- }
-
- /* We stored the handshake hash in |tlsext_channel_id| the first time that we
- * were called. */
- int sig_ok = ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key);
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
- sig_ok = 1;
-#endif
- if (!sig_ok) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
- ssl->s3->tlsext_channel_id_valid = 0;
- goto err;
- }
-
- memcpy(ssl->s3->tlsext_channel_id, p, 64);
- ret = 1;
-
-err:
- BN_free(&x);
- BN_free(&y);
- BN_free(sig.r);
- BN_free(sig.s);
- EC_KEY_free(key);
- EC_POINT_free(point);
- EC_GROUP_free(p256);
- return ret;
+ return 1;
}
static int ssl3_send_new_session_ticket(SSL *ssl) {
@@ -1906,20 +1807,37 @@ static int ssl3_send_new_session_ticket(SSL *ssl) {
return ssl->method->write_message(ssl);
}
+ const SSL_SESSION *session;
+ SSL_SESSION *session_copy = NULL;
+ if (ssl->session == NULL) {
+ /* Fix the timeout to measure from the ticket issuance time. */
+ ssl_session_refresh_time(ssl, ssl->s3->new_session);
+ session = ssl->s3->new_session;
+ } else {
+ /* We are renewing an existing session. Duplicate the session to adjust the
+ * timeout. */
+ session_copy = SSL_SESSION_dup(ssl->session, SSL_SESSION_INCLUDE_NONAUTH);
+ if (session_copy == NULL) {
+ return -1;
+ }
+
+ ssl_session_refresh_time(ssl, session_copy);
+ session = session_copy;
+ }
+
CBB cbb, body, ticket;
- if (!ssl->method->init_message(ssl, &cbb, &body,
- SSL3_MT_NEW_SESSION_TICKET) ||
- /* Ticket lifetime hint (advisory only): We leave this unspecified for
- * resumed session (for simplicity), and guess that tickets for new
- * sessions will live as long as their sessions. */
- !CBB_add_u32(&body,
- ssl->session != NULL ? 0 : ssl->s3->new_session->timeout) ||
- !CBB_add_u16_length_prefixed(&body, &ticket) ||
- !ssl_encrypt_ticket(ssl, &ticket, ssl->session != NULL
- ? ssl->session
- : ssl->s3->new_session) ||
- !ssl->method->finish_message(ssl, &cbb)) {
- return 0;
+ int ok =
+ ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) &&
+ CBB_add_u32(&body, session->timeout) &&
+ CBB_add_u16_length_prefixed(&body, &ticket) &&
+ ssl_encrypt_ticket(ssl, &ticket, session) &&
+ ssl_complete_message(ssl, &cbb);
+
+ SSL_SESSION_free(session_copy);
+ CBB_cleanup(&cbb);
+
+ if (!ok) {
+ return -1;
}
ssl->state = SSL3_ST_SW_SESSION_TICKET_B;
diff --git a/src/ssl/internal.h b/src/ssl/internal.h
index 7e9954d1..1d78ec17 100644
--- a/src/ssl/internal.h
+++ b/src/ssl/internal.h
@@ -230,14 +230,12 @@ const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf);
/* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
* |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
- * |ssl_cipher_preference_list_st| containing the result.
- * |*out_cipher_list_by_id| is set to a list of selected ciphers sorted by
- * id. It returns |(*out_cipher_list)->ciphers| on success and NULL on
+ * |ssl_cipher_preference_list_st| containing the result. It returns
+ * |(*out_cipher_list)->ciphers| on success and NULL on
* failure. */
STACK_OF(SSL_CIPHER) *
ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
struct ssl_cipher_preference_list_st **out_cipher_list,
- STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
const char *rule_str);
/* ssl_cipher_get_value returns the cipher suite id of |cipher|. */
@@ -269,7 +267,7 @@ size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
* an SSL connection. */
-struct ssl_aead_ctx_st {
+typedef struct ssl_aead_ctx_st {
const SSL_CIPHER *cipher;
EVP_AEAD_CTX ctx;
/* fixed_nonce contains any bytes of the nonce that are fixed for all
@@ -294,7 +292,7 @@ struct ssl_aead_ctx_st {
/* xor_fixed_nonce is non-zero if the fixed nonce should be XOR'd into the
* variable nonce rather than prepended. */
char xor_fixed_nonce;
-} /* SSL_AEAD_CTX */;
+} SSL_AEAD_CTX;
/* SSL_AEAD_CTX_new creates a newly-allocated |SSL_AEAD_CTX| using the supplied
* key material. It returns NULL on error. Only one of |SSL_AEAD_CTX_open| or
@@ -420,13 +418,6 @@ enum ssl_open_record_t dtls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
* buffer-free APIs are available. */
size_t ssl_seal_align_prefix_len(const SSL *ssl);
-/* ssl_max_seal_overhead returns the maximum overhead of sealing a record with
- * |ssl|.
- *
- * TODO(davidben): Expose this as part of public API once the high-level
- * buffer-free APIs are available. */
-size_t ssl_max_seal_overhead(const SSL *ssl);
-
/* tls_seal_record seals a new record of type |type| and body |in| and writes it
* to |out|. At most |max_out| bytes will be written. It returns one on success
* and zero on error. If enabled, |tls_seal_record| implements TLS 1.0 CBC 1/n-1
@@ -434,7 +425,7 @@ size_t ssl_max_seal_overhead(const SSL *ssl);
*
* For a large record, the bulk of the ciphertext will begin
* |ssl_seal_align_prefix_len| bytes into out. Aligning |out| appropriately may
- * improve performance. It writes at most |in_len| + |ssl_max_seal_overhead|
+ * improve performance. It writes at most |in_len| + |SSL_max_seal_overhead|
* bytes to |out|.
*
* |in| and |out| may not alias. */
@@ -557,9 +548,11 @@ int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
/* ECDH groups. */
+typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX;
+
/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
* TLS. */
-struct ssl_ecdh_method_st {
+typedef struct ssl_ecdh_method_st {
int nid;
uint16_t group_id;
const char name[8];
@@ -599,7 +592,12 @@ struct ssl_ecdh_method_st {
* be passed to |offer| or |accept|. It returns one on success and zero on
* error. */
int (*add_key)(CBB *cbb, CBB *out_contents);
-} /* SSL_ECDH_METHOD */;
+} SSL_ECDH_METHOD;
+
+struct ssl_ecdh_ctx_st {
+ const SSL_ECDH_METHOD *method;
+ void *data;
+};
/* ssl_nid_to_group_id looks up the group corresponding to |nid|. On success, it
* sets |*out_group_id| to the group ID and returns one. Otherwise, it returns
@@ -750,6 +748,10 @@ void ssl_write_buffer_clear(SSL *ssl);
* configured and zero otherwise. */
int ssl_has_certificate(const SSL *ssl);
+/* ssl_parse_x509 parses a X509 certificate from |cbs|. It returns NULL
+ * on error. */
+X509 *ssl_parse_x509(CBS *cbs);
+
/* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used
* by a TLS Certificate message. On success, it returns a newly-allocated
* |X509| list and advances |cbs|. Otherwise, it returns NULL and sets
@@ -794,21 +796,19 @@ int ssl_do_client_cert_cb(SSL *ssl, int *out_should_retry);
/* TLS 1.3 key derivation. */
/* tls13_init_key_schedule initializes the handshake hash and key derivation
- * state with the given resumption context. The cipher suite and PRF hash must
- * have been selected at this point. It returns one on success and zero on
- * error. */
-int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx,
- size_t resumption_ctx_len);
+ * state. The cipher suite and PRF hash must have been selected at this point.
+ * It returns one on success and zero on error. */
+int tls13_init_key_schedule(SSL *ssl);
/* tls13_advance_key_schedule incorporates |in| into the key schedule with
* HKDF-Extract. It returns one on success and zero on error. */
int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len);
-/* tls13_get_context_hashes writes Hash(Handshake Context) +
- * Hash(resumption_context) to |out| which much have room for at least 2 *
- * |EVP_MAX_MD_SIZE| bytes. On success, it returns one and sets |*out_len| to
- * the number of bytes written. Otherwise, it returns zero. */
-int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len);
+/* tls13_get_context_hash writes Hash(Handshake Context) to |out| which must
+ * have room for at least |EVP_MAX_MD_SIZE| bytes. On success, it returns one
+ * and sets |*out_len| to the number of bytes written. Otherwise, it returns
+ * zero. */
+int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len);
enum tls_record_type_t {
type_early_handshake,
@@ -817,11 +817,9 @@ enum tls_record_type_t {
type_data,
};
-/* tls13_set_traffic_key sets the read or write traffic keys to |traffic_secret|
- * for the given traffic phase |type|. It returns one on success and zero on
- * error. */
-int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
- enum evp_aead_direction_t direction,
+/* tls13_set_traffic_key sets the read or write traffic keys to
+ * |traffic_secret|. It returns one on success and zero on error. */
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
const uint8_t *traffic_secret,
size_t traffic_secret_len);
@@ -834,15 +832,15 @@ int tls13_set_handshake_traffic(SSL *ssl);
* returns one on success and zero on error. */
int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction);
-/* tls13_derive_traffic_secret_0 derives the initial application data traffic
- * secret based on the handshake transcripts and |master_secret|. It returns one
- * on success and zero on error. */
-int tls13_derive_traffic_secret_0(SSL *ssl);
+/* tls13_derive_application_secrets derives the initial application data traffic
+ * and exporter secrets based on the handshake transcripts and |master_secret|.
+ * It returns one on success and zero on error. */
+int tls13_derive_application_secrets(SSL *ssl);
-/* tls13_finalize_keys derives the |exporter_secret| and |resumption_secret|. */
-int tls13_finalize_keys(SSL *ssl);
+/* tls13_derive_resumption_secret derives the |resumption_secret|. */
+int tls13_derive_resumption_secret(SSL *ssl);
-/* tls13_export_keying_material provides and exporter interface to use the
+/* tls13_export_keying_material provides an exporter interface to use the
* |exporter_secret|. */
int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
const char *label, size_t label_len,
@@ -855,17 +853,15 @@ int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
* 0 for the Client Finished. */
int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server);
-/* tls13_resumption_psk calculates the PSK to use for the resumption of
- * |session| and stores the result in |out|. It returns one on success, and
- * zero on failure. */
-int tls13_resumption_psk(SSL *ssl, uint8_t *out, size_t out_len,
- const SSL_SESSION *session);
+/* tls13_write_psk_binder calculates the PSK binder value and replaces the last
+ * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
+ * failure. */
+int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len);
-/* tls13_resumption_context derives the context to be used for the handshake
- * transcript on the resumption of |session|. It returns one on success, and
- * zero on failure. */
-int tls13_resumption_context(SSL *ssl, uint8_t *out, size_t out_len,
- const SSL_SESSION *session);
+/* tls13_verify_psk_binder verifies that the handshake transcript, truncated
+ * up to the binders has a valid signature using the value of |session|'s
+ * resumption secret. It returns 1 on success, and 0 on failure. */
+int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, CBS *binders);
/* Handshake functions. */
@@ -878,10 +874,11 @@ enum ssl_hs_wait_t {
ssl_hs_flush,
ssl_hs_flush_and_read_message,
ssl_hs_x509_lookup,
+ ssl_hs_channel_id_lookup,
ssl_hs_private_key_operation,
};
-struct ssl_handshake_st {
+typedef struct ssl_handshake_st {
/* wait contains the operation |do_handshake| is currently blocking on or
* |ssl_hs_ok| if none. */
enum ssl_hs_wait_t wait;
@@ -894,7 +891,6 @@ struct ssl_handshake_st {
int state;
size_t hash_len;
- uint8_t resumption_hash[EVP_MAX_MD_SIZE];
uint8_t secret[EVP_MAX_MD_SIZE];
uint8_t client_traffic_secret_0[EVP_MAX_MD_SIZE];
uint8_t server_traffic_secret_0[EVP_MAX_MD_SIZE];
@@ -923,8 +919,19 @@ struct ssl_handshake_st {
/* ecdh_ctx is the current ECDH instance. */
SSL_ECDH_CTX ecdh_ctx;
+ /* scts_requested is one if the SCT extension is in the ClientHello. */
+ unsigned scts_requested:1;
+
+ /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be
+ * filled in. */
+ unsigned needs_psk_binder:1;
+
unsigned received_hello_retry_request:1;
+ /* accept_psk_mode stores whether the client's PSK mode is compatible with our
+ * preferences. */
+ unsigned accept_psk_mode:1;
+
/* retry_group is the group ID selected by the server in HelloRetryRequest in
* TLS 1.3. */
uint16_t retry_group;
@@ -992,6 +999,10 @@ struct ssl_handshake_st {
/* next_proto_neg_seen is one of NPN was negotiated. */
unsigned next_proto_neg_seen:1;
+ /* ticket_expected is one if a TLS 1.2 NewSessionTicket message is to be sent
+ * or received. */
+ unsigned ticket_expected:1;
+
/* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the
* server when using a TLS 1.2 PSK key exchange. */
char *peer_psk_identity_hint;
@@ -1004,7 +1015,14 @@ struct ssl_handshake_st {
* received in a CertificateRequest message. */
uint8_t *certificate_types;
size_t num_certificate_types;
-} /* SSL_HANDSHAKE */;
+
+ /* key_block is the record-layer key block for TLS 1.2 and earlier. */
+ uint8_t *key_block;
+ uint8_t key_block_len;
+
+ /* hostname, on the server, is the value of the SNI extension. */
+ char *hostname;
+} SSL_HANDSHAKE;
SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl));
@@ -1051,15 +1069,56 @@ int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert,
CBS *contents);
int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl,
SSL_SESSION **out_session,
+ CBS *out_binders,
uint8_t *out_alert, CBS *contents);
int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out);
-int ssl_add_client_hello_body(SSL *ssl, CBB *body);
+/* ssl_is_sct_list_valid does a shallow parse of the SCT list in |contents| and
+ * returns one iff it's valid. */
+int ssl_is_sct_list_valid(const CBS *contents);
+
+int ssl_write_client_hello(SSL *ssl);
/* ssl_clear_tls13_state releases client state only needed for TLS 1.3. It
* should be called once the version is known to be TLS 1.2 or earlier. */
void ssl_clear_tls13_state(SSL *ssl);
+enum ssl_cert_verify_context_t {
+ ssl_cert_verify_server,
+ ssl_cert_verify_client,
+ ssl_cert_verify_channel_id,
+};
+
+/* tls13_get_cert_verify_signature_input generates the message to be signed for
+ * TLS 1.3's CertificateVerify message. |cert_verify_context| determines the
+ * type of signature. It sets |*out| and |*out_len| to a newly allocated buffer
+ * containing the result. The caller must free it with |OPENSSL_free| to release
+ * it. This function returns one on success and zero on failure. */
+int tls13_get_cert_verify_signature_input(
+ SSL *ssl, uint8_t **out, size_t *out_len,
+ enum ssl_cert_verify_context_t cert_verify_context);
+
+/* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns
+ * one on successful negotiation or if nothing was negotiated. It returns zero
+ * and sets |*out_alert| to an alert on error. */
+int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert,
+ const struct ssl_early_callback_ctx *client_hello);
+
+typedef struct {
+ uint16_t type;
+ int *out_present;
+ CBS *out_data;
+} SSL_EXTENSION_TYPE;
+
+/* ssl_parse_extensions parses a TLS extensions block out of |cbs| and advances
+ * it. It writes the parsed extensions to pointers denoted by |ext_types|. On
+ * success, it fills in the |out_present| and |out_data| fields and returns one.
+ * Otherwise, it sets |*out_alert| to an alert to send and returns zero. Unknown
+ * extensions are rejected. */
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+ const SSL_EXTENSION_TYPE *ext_types,
+ size_t num_ext_types);
+
/* SSLKEYLOGFILE functions. */
@@ -1147,10 +1206,9 @@ enum ssl_hash_message_t {
};
typedef struct cert_st {
- X509 *x509;
EVP_PKEY *privatekey;
- /* Chain for this certificate */
- STACK_OF(X509) *chain;
+ X509 *x509_leaf;
+ STACK_OF(X509) *x509_chain;
/* key_method, if non-NULL, is a set of callbacks to call for private key
* operations. */
@@ -1220,10 +1278,9 @@ struct ssl_protocol_method_st {
* Otherwise, it returns <= 0. */
int (*ssl_get_message)(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message);
- /* hash_current_message incorporates the current handshake message into the
- * handshake hash. It returns one on success and zero on allocation
- * failure. */
- int (*hash_current_message)(SSL *ssl);
+ /* get_current_message sets |*out| to the current handshake message. This
+ * includes the protocol-specific message header. */
+ void (*get_current_message)(const SSL *ssl, CBS *out);
/* release_current_message is called to release the current handshake message.
* If |free_buffer| is one, buffers will also be released. */
void (*release_current_message)(SSL *ssl, int free_buffer);
@@ -1245,9 +1302,15 @@ struct ssl_protocol_method_st {
* root CBB to be passed into |finish_message|. |*body| is set to a child CBB
* the caller should write to. It returns one on success and zero on error. */
int (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
- /* finish_message finishes a handshake message and prepares it to be
- * written. It returns one on success and zero on error. */
- int (*finish_message)(SSL *ssl, CBB *cbb);
+ /* finish_message finishes a handshake message. It sets |*out_msg| to a
+ * newly-allocated buffer with the serialized message. The caller must
+ * release it with |OPENSSL_free| when done. It returns one on success and
+ * zero on error. */
+ int (*finish_message)(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+ /* queue_message queues a handshake message and prepares it to be written. It
+ * takes ownership of |msg| and releases it with |OPENSSL_free| when done. It
+ * returns one on success and zero on error. */
+ int (*queue_message)(SSL *ssl, uint8_t *msg, size_t len);
/* write_message writes the next message to the transport. It returns one on
* success and <= 0 on error. */
int (*write_message)(SSL *ssl);
@@ -1271,7 +1334,7 @@ struct ssl_protocol_method_st {
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit
* of a mess of functions, but hell, think of it as an opaque structure. */
-struct ssl3_enc_method {
+typedef struct ssl3_enc_method {
/* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
* |out|, using |secret| as the secret and |label| as the label. |seed1| and
* |seed2| are concatenated to form the seed parameter. It returns one on
@@ -1281,7 +1344,7 @@ struct ssl3_enc_method {
size_t label_len, const uint8_t *seed1, size_t seed1_len,
const uint8_t *seed2, size_t seed2_len);
int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
-};
+} SSL3_ENC_METHOD;
typedef struct ssl3_record_st {
/* type is the record type. */
@@ -1415,9 +1478,6 @@ typedef struct ssl3_state_st {
int reuse_message;
- uint8_t *key_block;
- uint8_t key_block_length;
-
uint8_t new_mac_secret_len;
uint8_t new_key_len;
uint8_t new_fixed_iv_len;
@@ -1569,12 +1629,9 @@ typedef struct dtls1_state_st {
extern const SSL3_ENC_METHOD TLSv1_enc_data;
extern const SSL3_ENC_METHOD SSLv3_enc_data;
-/* From draft-ietf-tls-tls13-16, used in determining PSK modes. */
-#define SSL_PSK_KE 0x0
-#define SSL_PSK_DHE_KE 0x1
-
-#define SSL_PSK_AUTH 0x0
-#define SSL_PSK_SIGN_AUTH 0x1
+/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
+#define SSL_PSK_KE 0x0
+#define SSL_PSK_DHE_KE 0x1
/* From draft-ietf-tls-tls13-16, used in determining whether to respond with a
* KeyUpdate. */
@@ -1596,6 +1653,10 @@ int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session);
* it has expired. */
int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session);
+/* ssl_session_is_resumable returns one if |session| is resumable for |ssl| and
+ * zero otherwise. */
+int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session);
+
void ssl_set_session(SSL *ssl, SSL_SESSION *session);
enum ssl_session_result_t {
@@ -1605,14 +1666,13 @@ enum ssl_session_result_t {
};
/* ssl_get_prev_session looks up the previous session based on |ctx|. On
- * success, it sets |*out_session| to the session or NULL if none was found. It
- * sets |*out_send_ticket| to whether a ticket should be sent at the end of the
- * handshake. If the session could not be looked up synchronously, it returns
+ * success, it sets |*out_session| to the session or NULL if none was found. If
+ * the session could not be looked up synchronously, it returns
* |ssl_session_retry| and should be called again. Otherwise, it returns
* |ssl_session_error|. */
enum ssl_session_result_t ssl_get_prev_session(
- SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
- const struct ssl_early_callback_ctx *ctx);
+ SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+ int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx);
/* The following flags determine which parts of the session are duplicated. */
#define SSL_SESSION_DUP_AUTH_ONLY 0x0
@@ -1627,9 +1687,17 @@ enum ssl_session_result_t ssl_get_prev_session(
OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session,
int dup_flags);
+/* ssl_session_refresh_time updates |session|'s start time to the current time,
+ * adjusting the timeout so the expiration time is unchanged. */
+void ssl_session_refresh_time(SSL *ssl, SSL_SESSION *session);
+
void ssl_cipher_preference_list_free(
struct ssl_cipher_preference_list_st *cipher_list);
-struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl);
+
+/* ssl_get_cipher_preferences returns the cipher preference list for TLS 1.2 and
+ * below. */
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+ const SSL *ssl);
int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain);
int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain);
@@ -1649,16 +1717,14 @@ void ssl_update_cache(SSL *ssl, int mode);
void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
uint32_t *out_mask_a);
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl);
int ssl_verify_alarm_type(long type);
int ssl3_get_finished(SSL *ssl);
int ssl3_send_change_cipher_spec(SSL *ssl);
-void ssl3_cleanup_key_block(SSL *ssl);
int ssl3_send_alert(SSL *ssl, int level, int desc);
int ssl3_get_message(SSL *ssl, int msg_type,
enum ssl_hash_message_t hash_message);
-int ssl3_hash_current_message(SSL *ssl);
+void ssl3_get_current_message(const SSL *ssl, CBS *out);
void ssl3_release_current_message(SSL *ssl, int free_buffer);
/* ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify hash into the
@@ -1679,6 +1745,7 @@ int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len);
int ssl3_write_app_data(SSL *ssl, const void *buf, int len);
int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len);
int ssl3_output_cert_chain(SSL *ssl);
+
const SSL_CIPHER *ssl3_choose_cipher(
SSL *ssl, const struct ssl_early_callback_ctx *client_hello,
const struct ssl_cipher_preference_list_st *srvr);
@@ -1689,16 +1756,27 @@ int ssl3_accept(SSL *ssl);
int ssl3_connect(SSL *ssl);
int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int ssl3_finish_message(SSL *ssl, CBB *cbb);
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len);
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len);
int ssl3_write_message(SSL *ssl);
void ssl3_expect_flight(SSL *ssl);
void ssl3_received_flight(SSL *ssl);
int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type);
-int dtls1_finish_message(SSL *ssl, CBB *cbb);
+int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len);
+int dtls1_queue_message(SSL *ssl, uint8_t *msg, size_t len);
int dtls1_write_message(SSL *ssl);
+/* ssl_complete_message calls |finish_message| and |queue_message| on |cbb| to
+ * queue the message for writing. */
+int ssl_complete_message(SSL *ssl, CBB *cbb);
+
+/* ssl_hash_current_message incorporates the current handshake message into the
+ * handshake hash. It returns one on success and zero on allocation failure. */
+int ssl_hash_current_message(SSL *ssl);
+
/* dtls1_get_record reads a new input record. On success, it places it in
* |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
* more data is needed. */
@@ -1740,7 +1818,7 @@ int dtls1_connect(SSL *ssl);
void dtls1_free(SSL *ssl);
int dtls1_get_message(SSL *ssl, int mt, enum ssl_hash_message_t hash_message);
-int dtls1_hash_current_message(SSL *ssl);
+void dtls1_get_current_message(const SSL *ssl, CBS *out);
void dtls1_release_current_message(SSL *ssl, int free_buffer);
int dtls1_dispatch_alert(SSL *ssl);
@@ -1752,7 +1830,6 @@ int ssl_init_wbio_buffer(SSL *ssl);
void ssl_free_wbio_buffer(SSL *ssl);
int tls1_change_cipher_state(SSL *ssl, int which);
-int tls1_setup_key_block(SSL *ssl);
int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
size_t premaster_len);
@@ -1808,6 +1885,16 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session,
size_t ticket_len, const uint8_t *session_id,
size_t session_id_len);
+/* tls1_verify_channel_id processes the current message as a Channel ID message,
+ * and verifies the signature. If the key is valid, it saves the Channel ID and
+ * returns one. Otherwise, it returns zero. */
+int tls1_verify_channel_id(SSL *ssl);
+
+/* tls1_write_channel_id generates a Channel ID message and puts the output in
+ * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling.
+ * This function returns one on success and zero on error. */
+int tls1_write_channel_id(SSL *ssl, CBB *cbb);
+
/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
* it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
* one on success and zero on failure. */
@@ -1815,6 +1902,12 @@ int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len);
int tls1_record_handshake_hashes_for_channel_id(SSL *ssl);
+/* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if
+ * necessary. It returns one on success and zero on fatal error. Note that, on
+ * success, |ssl->tlsext_channel_id_private| may be unset, in which case the
+ * operation should be retried later. */
+int ssl_do_channel_id_callback(SSL *ssl);
+
/* ssl3_can_false_start returns one if |ssl| is allowed to False Start and zero
* otherwise. */
int ssl3_can_false_start(const SSL *ssl);
diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c
index 1e7e4e11..d8720205 100644
--- a/src/ssl/s3_both.c
+++ b/src/ssl/s3_both.c
@@ -163,6 +163,13 @@ void ssl_handshake_free(SSL_HANDSHAKE *hs) {
OPENSSL_free(hs->peer_psk_identity_hint);
sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
OPENSSL_free(hs->certificate_types);
+
+ if (hs->key_block != NULL) {
+ OPENSSL_cleanse(hs->key_block, hs->key_block_len);
+ OPENSSL_free(hs->key_block);
+ }
+
+ OPENSSL_free(hs->hostname);
OPENSSL_free(hs);
}
@@ -199,18 +206,21 @@ int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type) {
return 1;
}
-int ssl3_finish_message(SSL *ssl, CBB *cbb) {
- if (ssl->s3->pending_message != NULL) {
+int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg,
+ size_t *out_len) {
+ if (!CBB_finish(cbb, out_msg, out_len)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- uint8_t *msg = NULL;
- size_t len;
- if (!CBB_finish(cbb, &msg, &len) ||
+ return 1;
+}
+
+int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len) {
+ if (ssl->s3->pending_message != NULL ||
len > 0xffffffffu) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
OPENSSL_free(msg);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
@@ -221,6 +231,17 @@ int ssl3_finish_message(SSL *ssl, CBB *cbb) {
return 1;
}
+int ssl_complete_message(SSL *ssl, CBB *cbb) {
+ uint8_t *msg;
+ size_t len;
+ if (!ssl->method->finish_message(ssl, cbb, &msg, &len) ||
+ !ssl->method->queue_message(ssl, msg, len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
int ssl3_write_message(SSL *ssl) {
if (ssl->s3->pending_message == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
@@ -278,7 +299,7 @@ int ssl3_send_finished(SSL *ssl, int a, int b) {
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
!CBB_add_bytes(&body, finished, finished_len) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return -1;
@@ -300,7 +321,7 @@ int ssl3_get_finished(SSL *ssl) {
size_t finished_len =
ssl->s3->enc_method->final_finish_mac(ssl, !ssl->server, finished);
if (finished_len == 0 ||
- !ssl->method->hash_current_message(ssl)) {
+ !ssl_hash_current_message(ssl)) {
return -1;
}
@@ -346,7 +367,7 @@ int ssl3_output_cert_chain(SSL *ssl) {
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
!ssl_add_cert_chain(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
return 0;
@@ -640,16 +661,21 @@ again:
}
/* Feed this message into MAC computation. */
- if (hash_message == ssl_hash_message && !ssl3_hash_current_message(ssl)) {
+ if (hash_message == ssl_hash_message && !ssl_hash_current_message(ssl)) {
return -1;
}
return 1;
}
-int ssl3_hash_current_message(SSL *ssl) {
- return ssl3_update_handshake_hash(ssl, (uint8_t *)ssl->init_buf->data,
- ssl->init_buf->length);
+void ssl3_get_current_message(const SSL *ssl, CBS *out) {
+ CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
+}
+
+int ssl_hash_current_message(SSL *ssl) {
+ CBS cbs;
+ ssl->method->get_current_message(ssl, &cbs);
+ return ssl3_update_handshake_hash(ssl, CBS_data(&cbs), CBS_len(&cbs));
}
void ssl3_release_current_message(SSL *ssl, int free_buffer) {
@@ -742,3 +768,51 @@ int ssl_verify_alarm_type(long type) {
return al;
}
+
+int ssl_parse_extensions(const CBS *cbs, uint8_t *out_alert,
+ const SSL_EXTENSION_TYPE *ext_types,
+ size_t num_ext_types) {
+ /* Reset everything. */
+ for (size_t i = 0; i < num_ext_types; i++) {
+ *ext_types[i].out_present = 0;
+ CBS_init(ext_types[i].out_data, NULL, 0);
+ }
+
+ CBS copy = *cbs;
+ while (CBS_len(&copy) != 0) {
+ uint16_t type;
+ CBS data;
+ if (!CBS_get_u16(&copy, &type) ||
+ !CBS_get_u16_length_prefixed(&copy, &data)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ const SSL_EXTENSION_TYPE *ext_type = NULL;
+ for (size_t i = 0; i < num_ext_types; i++) {
+ if (type == ext_types[i].type) {
+ ext_type = &ext_types[i];
+ break;
+ }
+ }
+
+ if (ext_type == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION;
+ return 0;
+ }
+
+ /* Duplicate ext_types are forbidden. */
+ if (*ext_type->out_present) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
+ *out_alert = SSL_AD_ILLEGAL_PARAMETER;
+ return 0;
+ }
+
+ *ext_type->out_present = 1;
+ *ext_type->out_data = data;
+ }
+
+ return 1;
+}
diff --git a/src/ssl/s3_enc.c b/src/ssl/s3_enc.c
index 2209e80a..7cdc294b 100644
--- a/src/ssl/s3_enc.c
+++ b/src/ssl/s3_enc.c
@@ -209,15 +209,6 @@ static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
return 1;
}
-void ssl3_cleanup_key_block(SSL *ssl) {
- if (ssl->s3->tmp.key_block != NULL) {
- OPENSSL_cleanse(ssl->s3->tmp.key_block, ssl->s3->tmp.key_block_length);
- OPENSSL_free(ssl->s3->tmp.key_block);
- ssl->s3->tmp.key_block = NULL;
- }
- ssl->s3->tmp.key_block_length = 0;
-}
-
int ssl3_init_handshake_buffer(SSL *ssl) {
ssl3_free_handshake_buffer(ssl);
ssl3_free_handshake_hash(ssl);
diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c
index 69d3a9dc..901b8afe 100644
--- a/src/ssl/s3_lib.c
+++ b/src/ssl/s3_lib.c
@@ -200,7 +200,6 @@ void ssl3_free(SSL *ssl) {
return;
}
- ssl3_cleanup_key_block(ssl);
ssl_read_buffer_clear(ssl);
ssl_write_buffer_clear(ssl);
@@ -220,7 +219,8 @@ void ssl3_free(SSL *ssl) {
ssl->s3 = NULL;
}
-struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl) {
+const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(
+ const SSL *ssl) {
if (ssl->cipher_list != NULL) {
return ssl->cipher_list;
}
diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c
index fda9a251..e4116fb2 100644
--- a/src/ssl/s3_pkt.c
+++ b/src/ssl/s3_pkt.c
@@ -245,8 +245,8 @@ int ssl3_write_bytes(SSL *ssl, int type, const void *buf_, int len) {
static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf,
unsigned int len) {
if (ssl->s3->wpend_tot > (int)len ||
- (ssl->s3->wpend_buf != buf &&
- !(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER)) ||
+ (!(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) &&
+ ssl->s3->wpend_buf != buf) ||
ssl->s3->wpend_type != type) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY);
return -1;
@@ -284,7 +284,7 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) {
return 0;
}
- size_t max_out = len + ssl_max_seal_overhead(ssl);
+ size_t max_out = len + SSL_max_seal_overhead(ssl);
if (max_out < len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return -1;
diff --git a/src/ssl/ssl_aead_ctx.c b/src/ssl/ssl_aead_ctx.c
index 0f6f64fa..b05df0b1 100644
--- a/src/ssl/ssl_aead_ctx.c
+++ b/src/ssl/ssl_aead_ctx.c
@@ -34,8 +34,12 @@ SSL_AEAD_CTX *SSL_AEAD_CTX_new(enum evp_aead_direction_t direction,
const uint8_t *mac_key, size_t mac_key_len,
const uint8_t *fixed_iv, size_t fixed_iv_len) {
const EVP_AEAD *aead;
- size_t discard;
- if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, cipher, version)) {
+ size_t expected_mac_key_len, expected_fixed_iv_len;
+ if (!ssl_cipher_get_evp_aead(&aead, &expected_mac_key_len,
+ &expected_fixed_iv_len, cipher, version) ||
+ /* Ensure the caller returned correct key sizes. */
+ expected_fixed_iv_len != fixed_iv_len ||
+ expected_mac_key_len != mac_key_len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c
index eeea8261..2a7b7d4b 100644
--- a/src/ssl/ssl_asn1.c
+++ b/src/ssl/ssl_asn1.c
@@ -97,13 +97,13 @@
/* An SSL_SESSION is serialized as the following ASN.1 structure:
*
* SSLSession ::= SEQUENCE {
- * version INTEGER (1), -- ignored
+ * version INTEGER (1), -- session structure version
* sslVersion INTEGER, -- protocol version number
* cipher OCTET STRING, -- two bytes long
* sessionID OCTET STRING,
* masterKey OCTET STRING,
- * time [1] INTEGER OPTIONAL, -- seconds since UNIX epoch
- * timeout [2] INTEGER OPTIONAL, -- in seconds
+ * time [1] INTEGER, -- seconds since UNIX epoch
+ * timeout [2] INTEGER, -- in seconds
* peer [3] Certificate OPTIONAL,
* sessionIDContext [4] OCTET STRING OPTIONAL,
* verifyResult [5] INTEGER OPTIONAL, -- one of X509_V_* codes
@@ -196,30 +196,36 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
goto err;
}
- if (in->time != 0) {
- if (!CBB_add_asn1(&session, &child, kTimeTag) ||
- !CBB_add_asn1_uint64(&child, in->time)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
+ if (in->time < 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
}
- if (in->timeout != 0) {
- if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
- !CBB_add_asn1_uint64(&child, in->timeout)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
- }
+ if (!CBB_add_asn1(&session, &child, kTimeTag) ||
+ !CBB_add_asn1_uint64(&child, in->time)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (in->timeout < 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
+ goto err;
+ }
+
+ if (!CBB_add_asn1(&session, &child, kTimeoutTag) ||
+ !CBB_add_asn1_uint64(&child, in->timeout)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
}
/* The peer certificate is only serialized if the SHA-256 isn't
* serialized instead. */
- if (in->peer && !in->peer_sha256_valid) {
+ if (in->x509_peer && !in->peer_sha256_valid) {
if (!CBB_add_asn1(&session, &child, kPeerTag)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- if (!ssl_add_cert_to_cbb(&child, in->peer)) {
+ if (!ssl_add_cert_to_cbb(&child, in->x509_peer)) {
goto err;
}
}
@@ -334,13 +340,13 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
/* The certificate chain is only serialized if the leaf's SHA-256 isn't
* serialized instead. */
- if (in->cert_chain != NULL && !in->peer_sha256_valid) {
+ if (in->x509_chain != NULL && !in->peer_sha256_valid) {
if (!CBB_add_asn1(&session, &child, kCertChainTag)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
- for (size_t i = 0; i < sk_X509_num(in->cert_chain); i++) {
- if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->cert_chain, i))) {
+ for (size_t i = 0; i < sk_X509_num(in->x509_chain); i++) {
+ if (!ssl_add_cert_to_cbb(&child, sk_X509_value(in->x509_chain, i))) {
goto err;
}
}
@@ -505,20 +511,6 @@ static int SSL_SESSION_parse_u32(CBS *cbs, uint32_t *out, unsigned tag,
return 1;
}
-static X509 *parse_x509(CBS *cbs) {
- if (CBS_len(cbs) > LONG_MAX) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
- return NULL;
- }
- const uint8_t *ptr = CBS_data(cbs);
- X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
- if (ret == NULL) {
- return NULL;
- }
- CBS_skip(cbs, ptr - CBS_data(cbs));
- return ret;
-}
-
static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
SSL_SESSION *ret = SSL_SESSION_new();
if (ret == NULL) {
@@ -563,23 +555,32 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key));
ret->master_key_length = CBS_len(&master_key);
- if (!SSL_SESSION_parse_long(&session, &ret->time, kTimeTag, time(NULL)) ||
- !SSL_SESSION_parse_long(&session, &ret->timeout, kTimeoutTag, 3)) {
+ CBS child;
+ uint64_t time, timeout;
+ if (!CBS_get_asn1(&session, &child, kTimeTag) ||
+ !CBS_get_asn1_uint64(&child, &time) ||
+ time > LONG_MAX ||
+ !CBS_get_asn1(&session, &child, kTimeoutTag) ||
+ !CBS_get_asn1_uint64(&child, &timeout) ||
+ timeout > LONG_MAX) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
+ ret->time = (long)time;
+ ret->timeout = (long)timeout;
+
CBS peer;
int has_peer;
if (!CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
- X509_free(ret->peer);
- ret->peer = NULL;
+ X509_free(ret->x509_peer);
+ ret->x509_peer = NULL;
if (has_peer) {
- ret->peer = parse_x509(&peer);
- if (ret->peer == NULL) {
+ ret->x509_peer = ssl_parse_x509(&peer);
+ if (ret->x509_peer == NULL) {
goto err;
}
if (CBS_len(&peer) != 0) {
@@ -605,7 +606,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
}
if (CBS_peek_asn1_tag(&session, kPeerSHA256Tag)) {
- CBS child, peer_sha256;
+ CBS peer_sha256;
if (!CBS_get_asn1(&session, &child, kPeerSHA256Tag) ||
!CBS_get_asn1(&child, &peer_sha256, CBS_ASN1_OCTETSTRING) ||
CBS_len(&peer_sha256) != sizeof(ret->peer_sha256) ||
@@ -655,20 +656,20 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
goto err;
}
- sk_X509_pop_free(ret->cert_chain, X509_free);
- ret->cert_chain = NULL;
+ sk_X509_pop_free(ret->x509_chain, X509_free);
+ ret->x509_chain = NULL;
if (has_cert_chain) {
- ret->cert_chain = sk_X509_new_null();
- if (ret->cert_chain == NULL) {
+ ret->x509_chain = sk_X509_new_null();
+ if (ret->x509_chain == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
while (CBS_len(&cert_chain) > 0) {
- X509 *x509 = parse_x509(&cert_chain);
+ X509 *x509 = ssl_parse_x509(&cert_chain);
if (x509 == NULL) {
goto err;
}
- if (!sk_X509_push(ret->cert_chain, x509)) {
+ if (!sk_X509_push(ret->x509_chain, x509)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
X509_free(x509);
goto err;
diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c
index 55b464fe..7f6cf636 100644
--- a/src/ssl/ssl_cert.c
+++ b/src/ssl/ssl_cert.c
@@ -115,6 +115,7 @@
#include <openssl/ssl.h>
#include <assert.h>
+#include <limits.h>
#include <string.h>
#include <openssl/bn.h>
@@ -158,9 +159,9 @@ CERT *ssl_cert_dup(CERT *cert) {
}
memset(ret, 0, sizeof(CERT));
- if (cert->x509 != NULL) {
- X509_up_ref(cert->x509);
- ret->x509 = cert->x509;
+ if (cert->x509_leaf != NULL) {
+ X509_up_ref(cert->x509_leaf);
+ ret->x509_leaf = cert->x509_leaf;
}
if (cert->privatekey != NULL) {
@@ -168,9 +169,9 @@ CERT *ssl_cert_dup(CERT *cert) {
ret->privatekey = cert->privatekey;
}
- if (cert->chain) {
- ret->chain = X509_chain_up_ref(cert->chain);
- if (!ret->chain) {
+ if (cert->x509_chain) {
+ ret->x509_chain = X509_chain_up_ref(cert->x509_chain);
+ if (!ret->x509_chain) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -220,12 +221,12 @@ void ssl_cert_clear_certs(CERT *cert) {
return;
}
- X509_free(cert->x509);
- cert->x509 = NULL;
+ X509_free(cert->x509_leaf);
+ cert->x509_leaf = NULL;
EVP_PKEY_free(cert->privatekey);
cert->privatekey = NULL;
- sk_X509_pop_free(cert->chain, X509_free);
- cert->chain = NULL;
+ sk_X509_pop_free(cert->x509_chain, X509_free);
+ cert->x509_chain = NULL;
cert->key_method = NULL;
}
@@ -244,8 +245,8 @@ void ssl_cert_free(CERT *c) {
}
int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) {
- sk_X509_pop_free(cert->chain, X509_free);
- cert->chain = chain;
+ sk_X509_pop_free(cert->x509_chain, X509_free);
+ cert->x509_chain = chain;
return 1;
}
@@ -269,10 +270,10 @@ int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) {
}
int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) {
- if (cert->chain == NULL) {
- cert->chain = sk_X509_new_null();
+ if (cert->x509_chain == NULL) {
+ cert->x509_chain = sk_X509_new_null();
}
- if (cert->chain == NULL || !sk_X509_push(cert->chain, x509)) {
+ if (cert->x509_chain == NULL || !sk_X509_push(cert->x509_chain, x509)) {
return 0;
}
@@ -443,7 +444,21 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) {
}
int ssl_has_certificate(const SSL *ssl) {
- return ssl->cert->x509 != NULL && ssl_has_private_key(ssl);
+ return ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl);
+}
+
+X509 *ssl_parse_x509(CBS *cbs) {
+ if (CBS_len(cbs) > LONG_MAX) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ return NULL;
+ }
+ const uint8_t *ptr = CBS_data(cbs);
+ X509 *ret = d2i_X509(NULL, &ptr, (long)CBS_len(cbs));
+ if (ret == NULL) {
+ return NULL;
+ }
+ CBS_skip(cbs, ptr - CBS_data(cbs));
+ return ret;
}
STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
@@ -476,10 +491,8 @@ STACK_OF(X509) *ssl_parse_cert_chain(SSL *ssl, uint8_t *out_alert,
SHA256(CBS_data(&certificate), CBS_len(&certificate), out_leaf_sha256);
}
- /* A u24 length cannot overflow a long. */
- const uint8_t *data = CBS_data(&certificate);
- x = d2i_X509(NULL, &data, (long)CBS_len(&certificate));
- if (x == NULL || data != CBS_data(&certificate) + CBS_len(&certificate)) {
+ x = ssl_parse_x509(&certificate);
+ if (x == NULL || CBS_len(&certificate) != 0) {
*out_alert = SSL_AD_DECODE_ERROR;
goto err;
}
@@ -528,7 +541,7 @@ int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
}
CERT *cert = ssl->cert;
- X509 *x = cert->x509;
+ X509 *x = cert->x509_leaf;
CBB child;
if (!CBB_add_u24_length_prefixed(cbb, &child)) {
@@ -537,7 +550,7 @@ int ssl_add_cert_chain(SSL *ssl, CBB *cbb) {
}
int no_chain = 0;
- STACK_OF(X509) *chain = cert->chain;
+ STACK_OF(X509) *chain = cert->x509_chain;
if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || chain != NULL) {
no_chain = 1;
}
@@ -763,7 +776,7 @@ int SSL_clear_chain_certs(SSL *ssl) {
}
int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) {
- *out_chain = ctx->cert->chain;
+ *out_chain = ctx->cert->x509_chain;
return 1;
}
@@ -773,7 +786,7 @@ int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx,
}
int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) {
- *out_chain = ssl->cert->chain;
+ *out_chain = ssl->cert->x509_chain;
return 1;
}
diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c
index 6d48c89b..99aba72c 100644
--- a/src/ssl/ssl_cipher.c
+++ b/src/ssl/ssl_cipher.c
@@ -738,9 +738,6 @@ static const CIPHER_ALIAS kCipherAliases[] = {
{"TLSv1", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, SSL3_VERSION},
{"TLSv1.2", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, TLS1_2_VERSION},
- /* AEAD-only ciphers for TLS 1.3. */
- {"GENERIC", SSL_kGENERIC, SSL_aGENERIC, ~0u, ~0u, 0},
-
/* Legacy strength classes. */
{"HIGH", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
{"FIPS", ~SSL_kCECPQ1, ~0u, ~SSL_eNULL, ~0u, 0},
@@ -761,10 +758,6 @@ static int ssl_cipher_id_cmp(const void *in_a, const void *in_b) {
}
}
-static int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **a, const SSL_CIPHER **b) {
- return ssl_cipher_id_cmp(*a, *b);
-}
-
const SSL_CIPHER *SSL_get_cipher_by_value(uint16_t value) {
SSL_CIPHER c;
@@ -781,125 +774,93 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead,
*out_mac_secret_len = 0;
*out_fixed_iv_len = 0;
- switch (cipher->algorithm_enc) {
- case SSL_AES128GCM:
+ if (cipher->algorithm_mac == SSL_AEAD) {
+ if (cipher->algorithm_enc == SSL_AES128GCM) {
*out_aead = EVP_aead_aes_128_gcm();
*out_fixed_iv_len = 4;
- break;
-
- case SSL_AES256GCM:
+ } else if (cipher->algorithm_enc == SSL_AES256GCM) {
*out_aead = EVP_aead_aes_256_gcm();
*out_fixed_iv_len = 4;
- break;
-
#if !defined(BORINGSSL_ANDROID_SYSTEM)
- case SSL_CHACHA20POLY1305_OLD:
+ } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305_OLD) {
*out_aead = EVP_aead_chacha20_poly1305_old();
*out_fixed_iv_len = 0;
- break;
#endif
-
- case SSL_CHACHA20POLY1305:
+ } else if (cipher->algorithm_enc == SSL_CHACHA20POLY1305) {
*out_aead = EVP_aead_chacha20_poly1305();
*out_fixed_iv_len = 12;
- break;
+ } else {
+ return 0;
+ }
- case SSL_AES128:
- switch (cipher->algorithm_mac) {
- case SSL_SHA1:
- if (version == SSL3_VERSION) {
- *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3();
- *out_fixed_iv_len = 16;
- } else if (version == TLS1_VERSION) {
- *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv();
- *out_fixed_iv_len = 16;
- } else {
- *out_aead = EVP_aead_aes_128_cbc_sha1_tls();
- }
- *out_mac_secret_len = SHA_DIGEST_LENGTH;
- break;
- case SSL_SHA256:
- *out_aead = EVP_aead_aes_128_cbc_sha256_tls();
- *out_mac_secret_len = SHA256_DIGEST_LENGTH;
- break;
- default:
- return 0;
+ /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
+ * above computes the TLS 1.2 construction. */
+ if (version >= TLS1_3_VERSION) {
+ *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead);
+ }
+ } else if (cipher->algorithm_mac == SSL_SHA1) {
+ if (cipher->algorithm_enc == SSL_eNULL) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_null_sha1_ssl3();
+ } else {
+ *out_aead = EVP_aead_null_sha1_tls();
}
- break;
-
- case SSL_AES256:
- switch (cipher->algorithm_mac) {
- case SSL_SHA1:
- if (version == SSL3_VERSION) {
- *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3();
- *out_fixed_iv_len = 16;
- } else if (version == TLS1_VERSION) {
- *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv();
- *out_fixed_iv_len = 16;
- } else {
- *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
- }
- *out_mac_secret_len = SHA_DIGEST_LENGTH;
- break;
- case SSL_SHA256:
- *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
- *out_mac_secret_len = SHA256_DIGEST_LENGTH;
- break;
- case SSL_SHA384:
- *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
- *out_mac_secret_len = SHA384_DIGEST_LENGTH;
- break;
- default:
- return 0;
+ } else if (cipher->algorithm_enc == SSL_3DES) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 8;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 8;
+ } else {
+ *out_aead = EVP_aead_des_ede3_cbc_sha1_tls();
}
- break;
-
- case SSL_3DES:
- switch (cipher->algorithm_mac) {
- case SSL_SHA1:
- if (version == SSL3_VERSION) {
- *out_aead = EVP_aead_des_ede3_cbc_sha1_ssl3();
- *out_fixed_iv_len = 8;
- } else if (version == TLS1_VERSION) {
- *out_aead = EVP_aead_des_ede3_cbc_sha1_tls_implicit_iv();
- *out_fixed_iv_len = 8;
- } else {
- *out_aead = EVP_aead_des_ede3_cbc_sha1_tls();
- }
- *out_mac_secret_len = SHA_DIGEST_LENGTH;
- break;
- default:
- return 0;
+ } else if (cipher->algorithm_enc == SSL_AES128) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 16;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 16;
+ } else {
+ *out_aead = EVP_aead_aes_128_cbc_sha1_tls();
}
- break;
-
- case SSL_eNULL:
- switch (cipher->algorithm_mac) {
- case SSL_SHA1:
- if (version == SSL3_VERSION) {
- *out_aead = EVP_aead_null_sha1_ssl3();
- } else {
- *out_aead = EVP_aead_null_sha1_tls();
- }
- *out_mac_secret_len = SHA_DIGEST_LENGTH;
- break;
- default:
- return 0;
+ } else if (cipher->algorithm_enc == SSL_AES256) {
+ if (version == SSL3_VERSION) {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_ssl3();
+ *out_fixed_iv_len = 16;
+ } else if (version == TLS1_VERSION) {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_tls_implicit_iv();
+ *out_fixed_iv_len = 16;
+ } else {
+ *out_aead = EVP_aead_aes_256_cbc_sha1_tls();
}
- break;
+ } else {
+ return 0;
+ }
- default:
+ *out_mac_secret_len = SHA_DIGEST_LENGTH;
+ } else if (cipher->algorithm_mac == SSL_SHA256) {
+ if (cipher->algorithm_enc == SSL_AES128) {
+ *out_aead = EVP_aead_aes_128_cbc_sha256_tls();
+ } else if (cipher->algorithm_enc == SSL_AES256) {
+ *out_aead = EVP_aead_aes_256_cbc_sha256_tls();
+ } else {
return 0;
- }
+ }
+
+ *out_mac_secret_len = SHA256_DIGEST_LENGTH;
+ } else if (cipher->algorithm_mac == SSL_SHA384) {
+ if (cipher->algorithm_enc != SSL_AES256) {
+ return 0;
+ }
- /* In TLS 1.3, the iv_len is equal to the AEAD nonce length whereas the code
- * above computes the TLS 1.2 construction.
- *
- * TODO(davidben,svaldez): Avoid computing the wrong value and fixing it. */
- if (version >= TLS1_3_VERSION) {
- *out_fixed_iv_len = EVP_AEAD_nonce_length(*out_aead);
- assert(*out_fixed_iv_len >= 8);
+ *out_aead = EVP_aead_aes_256_cbc_sha384_tls();
+ *out_mac_secret_len = SHA384_DIGEST_LENGTH;
+ } else {
+ return 0;
}
+
return 1;
}
@@ -975,7 +936,9 @@ static void ssl_cipher_collect_ciphers(const SSL_PROTOCOL_METHOD *ssl_method,
size_t co_list_num = 0;
for (size_t i = 0; i < kCiphersLen; i++) {
const SSL_CIPHER *cipher = &kCiphers[i];
- if (ssl_method->supports_cipher(cipher)) {
+ if (ssl_method->supports_cipher(cipher) &&
+ /* TLS 1.3 ciphers do not participate in this mechanism. */
+ cipher->algorithm_mkey != SSL_kGENERIC) {
co_list[co_list_num].cipher = cipher;
co_list[co_list_num].next = NULL;
co_list[co_list_num].prev = NULL;
@@ -1389,11 +1352,8 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method,
STACK_OF(SSL_CIPHER) *
ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
struct ssl_cipher_preference_list_st **out_cipher_list,
- STACK_OF(SSL_CIPHER) **out_cipher_list_by_id,
const char *rule_str) {
- int ok;
- STACK_OF(SSL_CIPHER) *cipherstack = NULL, *tmp_cipher_list = NULL;
- const char *rule_p;
+ STACK_OF(SSL_CIPHER) *cipherstack = NULL;
CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr;
uint8_t *in_group_flags = NULL;
unsigned int num_in_group_flags = 0;
@@ -1418,11 +1378,8 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
/* Now arrange all ciphers by preference:
* TODO(davidben): Compute this order once and copy it. */
- /* Everything else being equal, prefer TLS 1.3 ciphers then ECDHE_ECDSA then
- * ECDHE_RSA over other key exchange mechanisms */
-
- ssl_cipher_apply_rule(0, SSL_kGENERIC, SSL_aGENERIC, ~0u, ~0u, 0, CIPHER_ADD,
- -1, 0, &head, &tail);
+ /* Everything else being equal, prefer ECDHE_ECDSA and ECDHE_RSA over other
+ * key exchange mechanisms */
ssl_cipher_apply_rule(0, SSL_kECDHE, SSL_aECDSA, ~0u, ~0u, 0, CIPHER_ADD, -1,
0, &head, &tail);
ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_ADD, -1, 0,
@@ -1477,22 +1434,20 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
/* If the rule_string begins with DEFAULT, apply the default rule before
* using the (possibly available) additional rules. */
- ok = 1;
- rule_p = rule_str;
+ const char *rule_p = rule_str;
if (strncmp(rule_str, "DEFAULT", 7) == 0) {
- ok = ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
- &tail);
+ if (!ssl_cipher_process_rulestr(ssl_method, SSL_DEFAULT_CIPHER_LIST, &head,
+ &tail)) {
+ goto err;
+ }
rule_p += 7;
if (*rule_p == ':') {
rule_p++;
}
}
- if (ok && strlen(rule_p) > 0) {
- ok = ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail);
- }
-
- if (!ok) {
+ if (*rule_p != '\0' &&
+ !ssl_cipher_process_rulestr(ssl_method, rule_p, &head, &tail)) {
goto err;
}
@@ -1521,10 +1476,6 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
OPENSSL_free(co_list); /* Not needed any longer */
co_list = NULL;
- tmp_cipher_list = sk_SSL_CIPHER_dup(cipherstack);
- if (tmp_cipher_list == NULL) {
- goto err;
- }
pref_list = OPENSSL_malloc(sizeof(struct ssl_cipher_preference_list_st));
if (!pref_list) {
goto err;
@@ -1543,26 +1494,12 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method,
*out_cipher_list = pref_list;
pref_list = NULL;
- if (out_cipher_list_by_id != NULL) {
- sk_SSL_CIPHER_free(*out_cipher_list_by_id);
- *out_cipher_list_by_id = tmp_cipher_list;
- tmp_cipher_list = NULL;
- (void) sk_SSL_CIPHER_set_cmp_func(*out_cipher_list_by_id,
- ssl_cipher_ptr_id_cmp);
-
- sk_SSL_CIPHER_sort(*out_cipher_list_by_id);
- } else {
- sk_SSL_CIPHER_free(tmp_cipher_list);
- tmp_cipher_list = NULL;
- }
-
return cipherstack;
err:
OPENSSL_free(co_list);
OPENSSL_free(in_group_flags);
sk_SSL_CIPHER_free(cipherstack);
- sk_SSL_CIPHER_free(tmp_cipher_list);
if (pref_list) {
OPENSSL_free(pref_list->in_group_flags);
}
diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c
index 491c408c..70a39ea4 100644
--- a/src/ssl/ssl_lib.c
+++ b/src/ssl/ssl_lib.c
@@ -276,7 +276,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
}
ssl_create_cipher_list(ret->method, &ret->cipher_list,
- &ret->cipher_list_by_id, SSL_DEFAULT_CIPHER_LIST);
+ SSL_DEFAULT_CIPHER_LIST);
if (ret->cipher_list == NULL ||
sk_SSL_CIPHER_num(ret->cipher_list->ciphers) <= 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_LIBRARY_HAS_NO_CIPHERS);
@@ -304,6 +304,10 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) {
ret->options |= SSL_OP_NO_TICKET;
}
+ /* Disable the auto-chaining feature by default. Once this has stuck without
+ * problems, the feature will be removed entirely. */
+ ret->mode = SSL_MODE_NO_AUTO_CHAIN;
+
/* Lock the SSL_CTX to the specified version, for compatibility with legacy
* uses of SSL_METHOD. */
if (!SSL_CTX_set_max_proto_version(ret, method->version) ||
@@ -348,7 +352,6 @@ void SSL_CTX_free(SSL_CTX *ctx) {
lh_SSL_SESSION_free(ctx->sessions);
X509_STORE_free(ctx->cert_store);
ssl_cipher_preference_list_free(ctx->cipher_list);
- sk_SSL_CIPHER_free(ctx->cipher_list_by_id);
ssl_cipher_preference_list_free(ctx->cipher_list_tls10);
ssl_cipher_preference_list_free(ctx->cipher_list_tls11);
ssl_cert_free(ctx->cert);
@@ -409,6 +412,8 @@ SSL *SSL_new(SSL_CTX *ctx) {
assert(ssl->sid_ctx_length <= sizeof ssl->sid_ctx);
memcpy(&ssl->sid_ctx, &ctx->sid_ctx, sizeof(ssl->sid_ctx));
ssl->verify_callback = ctx->default_verify_callback;
+ ssl->retain_only_sha256_of_client_certs =
+ ctx->retain_only_sha256_of_client_certs;
ssl->param = X509_VERIFY_PARAM_new();
if (!ssl->param) {
@@ -500,7 +505,6 @@ void SSL_free(SSL *ssl) {
/* add extra stuff */
ssl_cipher_preference_list_free(ssl->cipher_list);
- sk_SSL_CIPHER_free(ssl->cipher_list_by_id);
SSL_SESSION_free(ssl->session);
@@ -1046,11 +1050,11 @@ X509 *SSL_get_peer_certificate(const SSL *ssl) {
return NULL;
}
SSL_SESSION *session = SSL_get_session(ssl);
- if (session == NULL || session->peer == NULL) {
+ if (session == NULL || session->x509_peer == NULL) {
return NULL;
}
- X509_up_ref(session->peer);
- return session->peer;
+ X509_up_ref(session->x509_peer);
+ return session->x509_peer;
}
STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
@@ -1061,7 +1065,7 @@ STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *ssl) {
if (session == NULL) {
return NULL;
}
- return session->cert_chain;
+ return session->x509_chain;
}
int SSL_get_tls_unique(const SSL *ssl, uint8_t *out, size_t *out_len,
@@ -1334,32 +1338,34 @@ int SSL_pending(const SSL *ssl) {
/* Fix this so it checks all the valid key/cert options */
int SSL_CTX_check_private_key(const SSL_CTX *ctx) {
- if (ctx->cert->x509 == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
+ if (ctx->cert->privatekey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- if (ctx->cert->privatekey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ X509 *x509 = ctx->cert->x509_leaf;
+ if (x509 == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- return X509_check_private_key(ctx->cert->x509, ctx->cert->privatekey);
+ return X509_check_private_key(x509, ctx->cert->privatekey);
}
/* Fix this function so that it takes an optional type parameter */
int SSL_check_private_key(const SSL *ssl) {
- if (ssl->cert->x509 == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
+ if (ssl->cert->privatekey == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
return 0;
}
- if (ssl->cert->privatekey == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED);
+ X509 *x509 = ssl->cert->x509_leaf;
+ if (x509 == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED);
return 0;
}
- return X509_check_private_key(ssl->cert->x509, ssl->cert->privatekey);
+ return X509_check_private_key(x509, ssl->cert->privatekey);
}
long SSL_get_default_timeout(const SSL *ssl) {
@@ -1564,41 +1570,13 @@ STACK_OF(SSL_CIPHER) *SSL_get_ciphers(const SSL *ssl) {
return NULL;
}
- if (ssl->cipher_list != NULL) {
- return ssl->cipher_list->ciphers;
- }
-
- if (ssl->version >= TLS1_1_VERSION && ssl->ctx->cipher_list_tls11 != NULL) {
- return ssl->ctx->cipher_list_tls11->ciphers;
- }
-
- if (ssl->version >= TLS1_VERSION && ssl->ctx->cipher_list_tls10 != NULL) {
- return ssl->ctx->cipher_list_tls10->ciphers;
- }
-
- if (ssl->ctx->cipher_list != NULL) {
- return ssl->ctx->cipher_list->ciphers;
- }
-
- return NULL;
-}
-
-/* return a STACK of the ciphers available for the SSL and in order of
- * algorithm id */
-STACK_OF(SSL_CIPHER) *ssl_get_ciphers_by_id(SSL *ssl) {
- if (ssl == NULL) {
+ const struct ssl_cipher_preference_list_st *prefs =
+ ssl_get_cipher_preferences(ssl);
+ if (prefs == NULL) {
return NULL;
}
- if (ssl->cipher_list_by_id != NULL) {
- return ssl->cipher_list_by_id;
- }
-
- if (ssl->ctx->cipher_list_by_id != NULL) {
- return ssl->ctx->cipher_list_by_id;
- }
-
- return NULL;
+ return prefs->ciphers;
}
const char *SSL_get_cipher_list(const SSL *ssl, int n) {
@@ -1623,8 +1601,8 @@ const char *SSL_get_cipher_list(const SSL *ssl, int n) {
}
int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
- ctx->method, &ctx->cipher_list, &ctx->cipher_list_by_id, str);
+ STACK_OF(SSL_CIPHER) *cipher_list =
+ ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str);
if (cipher_list == NULL) {
return 0;
}
@@ -1639,8 +1617,8 @@ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) {
}
int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
- ctx->method, &ctx->cipher_list_tls10, NULL, str);
+ STACK_OF(SSL_CIPHER) *cipher_list =
+ ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls10, str);
if (cipher_list == NULL) {
return 0;
}
@@ -1655,8 +1633,8 @@ int SSL_CTX_set_cipher_list_tls10(SSL_CTX *ctx, const char *str) {
}
int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
- STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
- ctx->method, &ctx->cipher_list_tls11, NULL, str);
+ STACK_OF(SSL_CIPHER) *cipher_list =
+ ssl_create_cipher_list(ctx->method, &ctx->cipher_list_tls11, str);
if (cipher_list == NULL) {
return 0;
}
@@ -1671,8 +1649,8 @@ int SSL_CTX_set_cipher_list_tls11(SSL_CTX *ctx, const char *str) {
}
int SSL_set_cipher_list(SSL *ssl, const char *str) {
- STACK_OF(SSL_CIPHER) *cipher_list = ssl_create_cipher_list(
- ssl->ctx->method, &ssl->cipher_list, &ssl->cipher_list_by_id, str);
+ STACK_OF(SSL_CIPHER) *cipher_list =
+ ssl_create_cipher_list(ssl->ctx->method, &ssl->cipher_list, str);
if (cipher_list == NULL) {
return 0;
}
@@ -1730,6 +1708,15 @@ const char *SSL_get_servername(const SSL *ssl, const int type) {
return ssl->tlsext_hostname;
}
+ /* During the handshake, report the handshake value. */
+ if (ssl->s3->hs != NULL) {
+ return ssl->s3->hs->hostname;
+ }
+
+ /* SSL_get_servername may also be called after the handshake to look up the
+ * SNI value.
+ *
+ * TODO(davidben): This is almost unused. Can we remove it? */
SSL_SESSION *session = SSL_get_session(ssl);
if (session == NULL) {
return NULL;
@@ -1792,16 +1779,15 @@ void SSL_get0_ocsp_response(const SSL *ssl, const uint8_t **out,
int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list,
size_t list_len) {
- OPENSSL_free(ctx->signed_cert_timestamp_list);
- ctx->signed_cert_timestamp_list_length = 0;
-
- ctx->signed_cert_timestamp_list = BUF_memdup(list, list_len);
- if (ctx->signed_cert_timestamp_list == NULL) {
+ CBS sct_list;
+ CBS_init(&sct_list, list, list_len);
+ if (!ssl_is_sct_list_valid(&sct_list)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST);
return 0;
}
- ctx->signed_cert_timestamp_list_length = list_len;
- return 1;
+ return CBS_stow(&sct_list, &ctx->signed_cert_timestamp_list,
+ &ctx->signed_cert_timestamp_list_length);
}
int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
@@ -2056,7 +2042,7 @@ void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k,
uint32_t mask_k = 0;
uint32_t mask_a = 0;
- if (ssl->cert->x509 != NULL && ssl_has_private_key(ssl)) {
+ if (ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl)) {
int type = ssl_private_key_type(ssl);
if (type == NID_rsaEncryption) {
mask_k |= SSL_kRSA;
@@ -2105,7 +2091,7 @@ void ssl_update_cache(SSL *ssl, int mode) {
* decides to renew the ticket. Once the handshake is completed, it should be
* inserted into the cache. */
if (ssl->s3->established_session != ssl->session ||
- (!ssl->server && ssl->tlsext_ticket_expected)) {
+ (!ssl->server && ssl->s3->hs->ticket_expected)) {
if (use_internal_cache) {
SSL_CTX_add_session(ctx, ssl->s3->established_session);
}
@@ -2177,7 +2163,7 @@ const char *SSL_SESSION_get_version(const SSL_SESSION *session) {
X509 *SSL_get_certificate(const SSL *ssl) {
if (ssl->cert != NULL) {
- return ssl->cert->x509;
+ return ssl->cert->x509_leaf;
}
return NULL;
@@ -2193,7 +2179,7 @@ EVP_PKEY *SSL_get_privatekey(const SSL *ssl) {
X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) {
if (ctx->cert != NULL) {
- return ctx->cert->x509;
+ return ctx->cert->x509_leaf;
}
return NULL;
@@ -2923,6 +2909,10 @@ const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) {
return ssl->s3->tmp.new_cipher;
}
+void SSL_set_retain_only_sha256_of_client_certs(SSL *ssl, int enabled) {
+ ssl->retain_only_sha256_of_client_certs = !!enabled;
+}
+
void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) {
ctx->retain_only_sha256_of_client_certs = !!enabled;
}
@@ -3060,7 +3050,7 @@ void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) {
return;
}
-#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
out_clock->tv_sec = 1234;
out_clock->tv_usec = 1234;
#elif defined(OPENSSL_WINDOWS)
diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c
index 29e5f194..e9840127 100644
--- a/src/ssl/ssl_rsa.c
+++ b/src/ssl/ssl_rsa.c
@@ -134,13 +134,14 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) {
return 0;
}
- if (c->x509 != NULL) {
+ X509 *x509_leaf = c->x509_leaf;
+ if (x509_leaf != NULL) {
/* Sanity-check that the private key and the certificate match, unless the
* key is opaque (in case of, say, a smartcard). */
if (!EVP_PKEY_is_opaque(pkey) &&
- !X509_check_private_key(c->x509, pkey)) {
- X509_free(c->x509);
- c->x509 = NULL;
+ !X509_check_private_key(x509_leaf, pkey)) {
+ X509_free(c->x509_leaf);
+ c->x509_leaf = NULL;
return 0;
}
}
@@ -248,9 +249,9 @@ static int ssl_set_cert(CERT *c, X509 *x) {
EVP_PKEY_free(pkey);
- X509_free(c->x509);
+ X509_free(c->x509_leaf);
X509_up_ref(x);
- c->x509 = x;
+ c->x509_leaf = x;
return 1;
}
diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c
index c2396b17..a6b669d0 100644
--- a/src/ssl/ssl_session.c
+++ b/src/ssl/ssl_session.c
@@ -199,13 +199,13 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
goto err;
}
}
- if (session->peer != NULL) {
- X509_up_ref(session->peer);
- new_session->peer = session->peer;
+ if (session->x509_peer != NULL) {
+ X509_up_ref(session->x509_peer);
+ new_session->x509_peer = session->x509_peer;
}
- if (session->cert_chain != NULL) {
- new_session->cert_chain = X509_chain_up_ref(session->cert_chain);
- if (new_session->cert_chain == NULL) {
+ if (session->x509_chain != NULL) {
+ new_session->x509_chain = X509_chain_up_ref(session->x509_chain);
+ if (new_session->x509_chain == NULL) {
goto err;
}
}
@@ -234,6 +234,13 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
memcpy(new_session->peer_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH);
new_session->peer_sha256_valid = session->peer_sha256_valid;
+ if (session->tlsext_hostname != NULL) {
+ new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
+ if (new_session->tlsext_hostname == NULL) {
+ goto err;
+ }
+ }
+
new_session->timeout = session->timeout;
new_session->time = session->time;
@@ -245,13 +252,6 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) {
new_session->key_exchange_info = session->key_exchange_info;
- if (session->tlsext_hostname != NULL) {
- new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname);
- if (new_session->tlsext_hostname == NULL) {
- goto err;
- }
- }
-
memcpy(new_session->original_handshake_hash,
session->original_handshake_hash,
session->original_handshake_hash_len);
@@ -285,6 +285,31 @@ err:
return 0;
}
+void ssl_session_refresh_time(SSL *ssl, SSL_SESSION *session) {
+ struct timeval now;
+ ssl_get_current_time(ssl, &now);
+
+ /* To avoid overflows and underflows, if we've gone back in time or any value
+ * is negative, update the time, but mark the session expired. */
+ if (session->time > now.tv_sec ||
+ session->time < 0 ||
+ now.tv_sec < 0) {
+ session->time = now.tv_sec;
+ session->timeout = 0;
+ return;
+ }
+
+ /* Adjust the session time and timeout. If the session has already expired,
+ * clamp the timeout at zero. */
+ long delta = now.tv_sec - session->time;
+ session->time = now.tv_sec;
+ if (session->timeout < delta) {
+ session->timeout = 0;
+ } else {
+ session->timeout -= delta;
+ }
+}
+
int SSL_SESSION_up_ref(SSL_SESSION *session) {
CRYPTO_refcount_inc(&session->references);
return 1;
@@ -300,8 +325,8 @@ void SSL_SESSION_free(SSL_SESSION *session) {
OPENSSL_cleanse(session->master_key, sizeof(session->master_key));
OPENSSL_cleanse(session->session_id, sizeof(session->session_id));
- X509_free(session->peer);
- sk_X509_pop_free(session->cert_chain, X509_free);
+ X509_free(session->x509_peer);
+ sk_X509_pop_free(session->x509_chain, X509_free);
OPENSSL_free(session->tlsext_hostname);
OPENSSL_free(session->tlsext_tick);
OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
@@ -332,7 +357,7 @@ long SSL_SESSION_get_time(const SSL_SESSION *session) {
}
X509 *SSL_SESSION_get0_peer(const SSL_SESSION *session) {
- return session->peer;
+ return session->x509_peer;
}
size_t SSL_SESSION_get_master_key(const SSL_SESSION *session, uint8_t *out,
@@ -448,7 +473,7 @@ int ssl_get_new_session(SSL *ssl, int is_server) {
session->ssl_version = ssl->version;
if (is_server) {
- if (ssl->tlsext_ticket_expected) {
+ if (ssl->s3->hs->ticket_expected) {
/* Don't set session IDs for sessions resumed with tickets. This will keep
* them out of the session cache. */
session->session_id_length = 0;
@@ -599,7 +624,30 @@ int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session) {
struct timeval now;
ssl_get_current_time(ssl, &now);
- return session->timeout >= (long)now.tv_sec - session->time;
+
+ /* Reject tickets from the future to avoid underflow. */
+ if ((long)now.tv_sec < session->time) {
+ return 0;
+ }
+
+ return session->timeout > (long)now.tv_sec - session->time;
+}
+
+int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session) {
+ return ssl_session_is_context_valid(ssl, session) &&
+ /* The session must not be expired. */
+ ssl_session_is_time_valid(ssl, session) &&
+ /* Only resume if the session's version matches the negotiated
+ * version. */
+ ssl->version == session->ssl_version &&
+ /* Only resume if the session's cipher matches the negotiated one. */
+ ssl->s3->tmp.new_cipher == session->cipher &&
+ /* If the session contains a client certificate (either the full
+ * certificate or just the hash) then require that the form of the
+ * certificate matches the current configuration. */
+ ((session->x509_peer == NULL && !session->peer_sha256_valid) ||
+ session->peer_sha256_valid ==
+ ssl->retain_only_sha256_of_client_certs);
}
/* ssl_lookup_session looks up |session_id| in the session cache and sets
@@ -662,15 +710,8 @@ static enum ssl_session_result_t ssl_lookup_session(
}
}
- if (session == NULL) {
- return ssl_session_success;
- }
-
- if (!ssl_session_is_context_valid(ssl, session)) {
- /* The client did not offer a suitable ticket or session ID. */
- SSL_SESSION_free(session);
- session = NULL;
- } else if (!ssl_session_is_time_valid(ssl, session)) {
+ if (session != NULL &&
+ !ssl_session_is_time_valid(ssl, session)) {
/* The session was from the cache, so remove it. */
SSL_CTX_remove_session(ssl->initial_ctx, session);
SSL_SESSION_free(session);
@@ -682,8 +723,8 @@ static enum ssl_session_result_t ssl_lookup_session(
}
enum ssl_session_result_t ssl_get_prev_session(
- SSL *ssl, SSL_SESSION **out_session, int *out_send_ticket,
- const struct ssl_early_callback_ctx *ctx) {
+ SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported,
+ int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx) {
/* This is used only by servers. */
assert(ssl->server);
SSL_SESSION *session = NULL;
@@ -712,11 +753,8 @@ enum ssl_session_result_t ssl_get_prev_session(
}
*out_session = session;
- if (session != NULL) {
- *out_send_ticket = renew_ticket;
- } else {
- *out_send_ticket = tickets_supported;
- }
+ *out_tickets_supported = tickets_supported;
+ *out_renew_ticket = renew_ticket;
return ssl_session_success;
}
diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc
index cfce2d0c..ae9d5ca4 100644
--- a/src/ssl/ssl_test.cc
+++ b/src/ssl/ssl_test.cc
@@ -23,11 +23,14 @@
#include <openssl/base64.h>
#include <openssl/bio.h>
+#include <openssl/cipher.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
+#include <openssl/hmac.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
#include <openssl/ssl.h>
+#include <openssl/rand.h>
#include <openssl/x509.h>
#include "internal.h"
@@ -269,7 +272,6 @@ static const char *kMustNotIncludeNull[] = {
"SSLv3",
"TLSv1",
"TLSv1.2",
- "GENERIC",
};
static const char *kMustNotIncludeCECPQ1[] = {
@@ -294,7 +296,6 @@ static const char *kMustNotIncludeCECPQ1[] = {
"AES256",
"AESGCM",
"CHACHA20",
- "GENERIC",
};
static const CurveTest kCurveTests[] = {
@@ -864,18 +865,22 @@ static bool TestCipherGetRFCName(void) {
return true;
}
-// CreateSessionWithTicket returns a sample |SSL_SESSION| with the ticket
-// replaced for one of length |ticket_len| or nullptr on failure.
-static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(size_t ticket_len) {
+// CreateSessionWithTicket returns a sample |SSL_SESSION| with the specified
+// version and ticket length or nullptr on failure.
+static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(uint16_t version,
+ size_t ticket_len) {
std::vector<uint8_t> der;
if (!DecodeBase64(&der, kOpenSSLSession)) {
return nullptr;
}
- bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(der.data(), der.size()));
+ bssl::UniquePtr<SSL_SESSION> session(
+ SSL_SESSION_from_bytes(der.data(), der.size()));
if (!session) {
return nullptr;
}
+ session->ssl_version = version;
+
// Swap out the ticket for a garbage one.
OPENSSL_free(session->tlsext_tick);
session->tlsext_tick = reinterpret_cast<uint8_t*>(OPENSSL_malloc(ticket_len));
@@ -886,7 +891,11 @@ static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(size_t ticket_len) {
session->tlsext_ticklen = ticket_len;
// Fix up the timeout.
+#if defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+ session->time = 1234;
+#else
session->time = time(NULL);
+#endif
return session;
}
@@ -914,27 +923,32 @@ static bool GetClientHello(SSL *ssl, std::vector<uint8_t> *out) {
return true;
}
-// GetClientHelloLen creates a client SSL connection with a ticket of length
-// |ticket_len| and records the ClientHello. It returns the length of the
-// ClientHello, not including the record header, on success and zero on error.
-static size_t GetClientHelloLen(size_t ticket_len) {
+// GetClientHelloLen creates a client SSL connection with the specified version
+// and ticket length. It returns the length of the ClientHello, not including
+// the record header, on success and zero on error.
+static size_t GetClientHelloLen(uint16_t max_version, uint16_t session_version,
+ size_t ticket_len) {
bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_SESSION> session = CreateSessionWithTicket(ticket_len);
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateSessionWithTicket(session_version, ticket_len);
if (!ctx || !session) {
return 0;
}
+
+ // Set a one-element cipher list so the baseline ClientHello is unpadded.
bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
- // Test at TLS 1.2. TLS 1.3 adds enough extensions that the ClientHello is
- // longer than our test vectors.
if (!ssl || !SSL_set_session(ssl.get(), session.get()) ||
- !SSL_set_max_proto_version(ssl.get(), TLS1_2_VERSION)) {
+ !SSL_set_cipher_list(ssl.get(), "ECDHE-RSA-AES128-GCM-SHA256") ||
+ !SSL_set_max_proto_version(ssl.get(), max_version)) {
return 0;
}
+
std::vector<uint8_t> client_hello;
if (!GetClientHello(ssl.get(), &client_hello) ||
client_hello.size() <= SSL3_RT_HEADER_LENGTH) {
return 0;
}
+
return client_hello.size() - SSL3_RT_HEADER_LENGTH;
}
@@ -963,28 +977,37 @@ static const PaddingTest kPaddingTests[] = {
{0x201, 0x201},
};
-static bool TestPaddingExtension() {
+static bool TestPaddingExtension(uint16_t max_version,
+ uint16_t session_version) {
// Sample a baseline length.
- size_t base_len = GetClientHelloLen(1);
+ size_t base_len = GetClientHelloLen(max_version, session_version, 1);
if (base_len == 0) {
return false;
}
for (const PaddingTest &test : kPaddingTests) {
if (base_len > test.input_len) {
- fprintf(stderr, "Baseline ClientHello too long.\n");
+ fprintf(stderr,
+ "Baseline ClientHello too long (max_version = %04x, "
+ "session_version = %04x).\n",
+ max_version, session_version);
return false;
}
- size_t padded_len = GetClientHelloLen(1 + test.input_len - base_len);
+ size_t padded_len = GetClientHelloLen(max_version, session_version,
+ 1 + test.input_len - base_len);
if (padded_len != test.padded_len) {
- fprintf(stderr, "%u-byte ClientHello padded to %u bytes, not %u.\n",
+ fprintf(stderr,
+ "%u-byte ClientHello padded to %u bytes, not %u (max_version = "
+ "%04x, session_version = %04x).\n",
static_cast<unsigned>(test.input_len),
static_cast<unsigned>(padded_len),
- static_cast<unsigned>(test.padded_len));
+ static_cast<unsigned>(test.padded_len), max_version,
+ session_version);
return false;
}
}
+
return true;
}
@@ -1273,115 +1296,104 @@ static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, bssl::Uniqu
return true;
}
-static uint16_t kTLSVersions[] = {
- SSL3_VERSION, TLS1_VERSION, TLS1_1_VERSION, TLS1_2_VERSION, TLS1_3_VERSION,
-};
-
-static uint16_t kDTLSVersions[] = {
- DTLS1_VERSION, DTLS1_2_VERSION,
-};
+static bool TestSequenceNumber(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !client_ctx ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
-static bool TestSequenceNumber() {
- for (bool is_dtls : std::vector<bool>{false, true}) {
- const SSL_METHOD *method = is_dtls ? DTLS_method() : TLS_method();
- const uint16_t *versions = is_dtls ? kDTLSVersions : kTLSVersions;
- size_t num_versions = is_dtls ? OPENSSL_ARRAY_SIZE(kDTLSVersions)
- : OPENSSL_ARRAY_SIZE(kTLSVersions);
- for (size_t i = 0; i < num_versions; i++) {
- uint16_t version = versions[i];
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
- if (!server_ctx || !client_ctx ||
- !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
- return false;
- }
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!cert || !key || !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
+ return false;
+ }
- bssl::UniquePtr<X509> cert = GetTestCertificate();
- bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- if (!cert || !key ||
- !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
- return false;
- }
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ return false;
+ }
- bssl::UniquePtr<SSL> client, server;
- if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), nullptr /* no session */)) {
- return false;
- }
+ // Drain any post-handshake messages to ensure there are no unread records
+ // on either end.
+ uint8_t byte = 0;
+ if (SSL_read(client.get(), &byte, 1) > 0 ||
+ SSL_read(server.get(), &byte, 1) > 0) {
+ fprintf(stderr, "Received unexpected data.\n");
+ return false;
+ }
- // Drain any post-handshake messages to ensure there are no unread records
- // on either end.
- uint8_t byte = 0;
- if (SSL_read(client.get(), &byte, 1) > 0 ||
- SSL_read(server.get(), &byte, 1) > 0) {
- fprintf(stderr, "Received unexpected data.\n");
- return false;
- }
+ uint64_t client_read_seq = SSL_get_read_sequence(client.get());
+ uint64_t client_write_seq = SSL_get_write_sequence(client.get());
+ uint64_t server_read_seq = SSL_get_read_sequence(server.get());
+ uint64_t server_write_seq = SSL_get_write_sequence(server.get());
- uint64_t client_read_seq = SSL_get_read_sequence(client.get());
- uint64_t client_write_seq = SSL_get_write_sequence(client.get());
- uint64_t server_read_seq = SSL_get_read_sequence(server.get());
- uint64_t server_write_seq = SSL_get_write_sequence(server.get());
-
- if (is_dtls) {
- // Both client and server must be at epoch 1.
- if (EpochFromSequence(client_read_seq) != 1 ||
- EpochFromSequence(client_write_seq) != 1 ||
- EpochFromSequence(server_read_seq) != 1 ||
- EpochFromSequence(server_write_seq) != 1) {
- fprintf(stderr, "Bad epochs.\n");
- return false;
- }
+ if (is_dtls) {
+ // Both client and server must be at epoch 1.
+ if (EpochFromSequence(client_read_seq) != 1 ||
+ EpochFromSequence(client_write_seq) != 1 ||
+ EpochFromSequence(server_read_seq) != 1 ||
+ EpochFromSequence(server_write_seq) != 1) {
+ fprintf(stderr, "Bad epochs.\n");
+ return false;
+ }
- // The next record to be written should exceed the largest received.
- if (client_write_seq <= server_read_seq ||
- server_write_seq <= client_read_seq) {
- fprintf(stderr, "Inconsistent sequence numbers.\n");
- return false;
- }
- } else {
- // The next record to be written should equal the next to be received.
- if (client_write_seq != server_read_seq ||
- server_write_seq != client_read_seq) {
- fprintf(stderr, "Inconsistent sequence numbers.\n");
- return false;
- }
- }
+ // The next record to be written should exceed the largest received.
+ if (client_write_seq <= server_read_seq ||
+ server_write_seq <= client_read_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ } else {
+ // The next record to be written should equal the next to be received.
+ if (client_write_seq != server_read_seq ||
+ server_write_seq != client_read_seq) {
+ fprintf(stderr, "Inconsistent sequence numbers.\n");
+ return false;
+ }
+ }
- // Send a record from client to server.
- if (SSL_write(client.get(), &byte, 1) != 1 ||
- SSL_read(server.get(), &byte, 1) != 1) {
- fprintf(stderr, "Could not send byte.\n");
- return false;
- }
+ // Send a record from client to server.
+ if (SSL_write(client.get(), &byte, 1) != 1 ||
+ SSL_read(server.get(), &byte, 1) != 1) {
+ fprintf(stderr, "Could not send byte.\n");
+ return false;
+ }
- // The client write and server read sequence numbers should have
- // incremented.
- if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
- server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
- fprintf(stderr, "Sequence numbers did not increment.\n");
- return false;
- }
- }
+ // The client write and server read sequence numbers should have
+ // incremented.
+ if (client_write_seq + 1 != SSL_get_write_sequence(client.get()) ||
+ server_read_seq + 1 != SSL_get_read_sequence(server.get())) {
+ fprintf(stderr, "Sequence numbers did not increment.\n");
+ return false;
}
return true;
}
-static bool TestOneSidedShutdown() {
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
- if (!client_ctx || !server_ctx) {
- return false;
+static bool TestOneSidedShutdown(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL_shutdown is a no-op in DTLS.
+ if (is_dtls) {
+ return true;
}
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
- if (!cert || !key ||
+ if (!client_ctx || !server_ctx || !cert || !key ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) {
return false;
@@ -1427,6 +1439,7 @@ static bool TestOneSidedShutdown() {
return true;
}
+
static bool TestSessionDuplication() {
bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
@@ -1631,63 +1644,63 @@ static bool TestSetBIO() {
static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; }
-static bool TestGetPeerCertificate() {
+static bool TestGetPeerCertificate(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!cert || !key) {
return false;
}
- for (uint16_t version : kTLSVersions) {
- // Configure both client and server to accept any certificate.
- bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
- if (!ctx ||
- !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
- !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
- return false;
- }
- SSL_CTX_set_verify(
- ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
- SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+ // Configure both client and server to accept any certificate.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+ SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
- bssl::UniquePtr<SSL> client, server;
- if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
- nullptr /* no session */)) {
- return false;
- }
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
- // Client and server should both see the leaf certificate.
- bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
- if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
- fprintf(stderr, "%x: Server peer certificate did not match.\n", version);
- return false;
- }
+ // Client and server should both see the leaf certificate.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+ if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
+ fprintf(stderr, "Server peer certificate did not match.\n");
+ return false;
+ }
- peer.reset(SSL_get_peer_certificate(client.get()));
- if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
- fprintf(stderr, "%x: Client peer certificate did not match.\n", version);
- return false;
- }
+ peer.reset(SSL_get_peer_certificate(client.get()));
+ if (!peer || X509_cmp(cert.get(), peer.get()) != 0) {
+ fprintf(stderr, "Client peer certificate did not match.\n");
+ return false;
+ }
- // However, for historical reasons, the chain includes the leaf on the
- // client, but does not on the server.
- if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1) {
- fprintf(stderr, "%x: Client peer chain was incorrect.\n", version);
- return false;
- }
+ // However, for historical reasons, the chain includes the leaf on the
+ // client, but does not on the server.
+ if (sk_X509_num(SSL_get_peer_cert_chain(client.get())) != 1) {
+ fprintf(stderr, "Client peer chain was incorrect.\n");
+ return false;
+ }
- if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
- fprintf(stderr, "%x: Server peer chain was incorrect.\n", version);
- return false;
- }
+ if (sk_X509_num(SSL_get_peer_cert_chain(server.get())) != 0) {
+ fprintf(stderr, "Server peer chain was incorrect.\n");
+ return false;
}
return true;
}
-static bool TestRetainOnlySHA256OfCerts() {
+static bool TestRetainOnlySHA256OfCerts(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!cert || !key) {
@@ -1704,45 +1717,43 @@ static bool TestRetainOnlySHA256OfCerts() {
uint8_t cert_sha256[SHA256_DIGEST_LENGTH];
SHA256(cert_der, cert_der_len, cert_sha256);
- for (uint16_t version : kTLSVersions) {
- // Configure both client and server to accept any certificate, but the
- // server must retain only the SHA-256 of the peer.
- bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
- if (!ctx ||
- !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
- !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
- return false;
- }
- SSL_CTX_set_verify(
- ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
- SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
- SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1);
-
- bssl::UniquePtr<SSL> client, server;
- if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
- nullptr /* no session */)) {
- return false;
- }
+ // Configure both client and server to accept any certificate, but the
+ // server must retain only the SHA-256 of the peer.
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx ||
+ !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version)) {
+ return false;
+ }
+ SSL_CTX_set_verify(
+ ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
+ SSL_CTX_set_cert_verify_callback(ctx.get(), VerifySucceed, NULL);
+ SSL_CTX_set_retain_only_sha256_of_client_certs(ctx.get(), 1);
- // The peer certificate has been dropped.
- bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
- if (peer) {
- fprintf(stderr, "%x: Peer certificate was retained.\n", version);
- return false;
- }
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
- SSL_SESSION *session = SSL_get_session(server.get());
- if (!session->peer_sha256_valid) {
- fprintf(stderr, "%x: peer_sha256_valid was not set.\n", version);
- return false;
- }
+ // The peer certificate has been dropped.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(server.get()));
+ if (peer) {
+ fprintf(stderr, "Peer certificate was retained.\n");
+ return false;
+ }
- if (memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != 0) {
- fprintf(stderr, "%x: peer_sha256 did not match.\n", version);
- return false;
- }
+ SSL_SESSION *session = SSL_get_session(server.get());
+ if (!session->peer_sha256_valid) {
+ fprintf(stderr, "peer_sha256_valid was not set.\n");
+ return false;
+ }
+
+ if (memcmp(cert_sha256, session->peer_sha256, SHA256_DIGEST_LENGTH) != 0) {
+ fprintf(stderr, "peer_sha256 did not match.\n");
+ return false;
}
return true;
@@ -1900,8 +1911,8 @@ static bool TestClientHello() {
0xc0, 0x28, 0x00, 0x39, 0x00, 0x6b, 0x00, 0x9c, 0x00, 0x9d, 0x00, 0x2f,
0x00, 0x3c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x37,
0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00,
- 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x08, 0x06, 0x06, 0x01, 0x08,
- 0x05, 0x05, 0x01, 0x05, 0x03, 0x08, 0x04, 0x04, 0x01, 0x04, 0x03, 0x02,
+ 0x00, 0x00, 0x0d, 0x00, 0x14, 0x00, 0x12, 0x04, 0x03, 0x08, 0x04, 0x04,
+ 0x01, 0x05, 0x03, 0x08, 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02,
0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00,
0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18,
};
@@ -1974,7 +1985,64 @@ static bool ExpectSessionReused(SSL_CTX *client_ctx, SSL_CTX *server_ctx,
return true;
}
-static bool TestSessionIDContext() {
+static bssl::UniquePtr<SSL_SESSION> ExpectSessionRenewed(SSL_CTX *client_ctx,
+ SSL_CTX *server_ctx,
+ SSL_SESSION *session) {
+ g_last_session = nullptr;
+ SSL_CTX_sess_set_new_cb(client_ctx, SaveLastSession);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx,
+ server_ctx, session)) {
+ fprintf(stderr, "Failed to connect client and server.\n");
+ return nullptr;
+ }
+
+ if (SSL_session_reused(client.get()) != SSL_session_reused(server.get())) {
+ fprintf(stderr, "Client and server were inconsistent.\n");
+ return nullptr;
+ }
+
+ if (!SSL_session_reused(client.get())) {
+ fprintf(stderr, "Session was not reused.\n");
+ return nullptr;
+ }
+
+ // Run the read loop to account for post-handshake tickets in TLS 1.3.
+ SSL_read(client.get(), nullptr, 0);
+
+ SSL_CTX_sess_set_new_cb(client_ctx, nullptr);
+
+ if (!g_last_session) {
+ fprintf(stderr, "Client did not receive a renewed session.\n");
+ return nullptr;
+ }
+ return std::move(g_last_session);
+}
+
+static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) {
+ static const uint8_t kContext[] = {3};
+
+ if (!SSL_set_session_id_context(ssl, kContext, sizeof(kContext))) {
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
+static int SwitchSessionIDContextEarly(
+ const struct ssl_early_callback_ctx *ctx) {
+ static const uint8_t kContext[] = {3};
+
+ if (!SSL_set_session_id_context(ctx->ssl, kContext, sizeof(kContext))) {
+ return -1;
+ }
+
+ return 1;
+}
+
+static bool TestSessionIDContext(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!cert || !key) {
@@ -1984,50 +2052,74 @@ static bool TestSessionIDContext() {
static const uint8_t kContext1[] = {1};
static const uint8_t kContext2[] = {2};
- for (uint16_t version : kTLSVersions) {
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- if (!server_ctx || !client_ctx ||
- !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
- !SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
- sizeof(kContext1)) ||
- !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
- return false;
- }
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !client_ctx ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+ !SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
+ sizeof(kContext1)) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) {
+ return false;
+ }
- SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
- SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
- bssl::UniquePtr<SSL_SESSION> session =
- CreateClientSession(client_ctx.get(), server_ctx.get());
- if (!session) {
- fprintf(stderr, "Error getting session (version = %04x).\n", version);
- return false;
- }
+ bssl::UniquePtr<SSL_SESSION> session =
+ CreateClientSession(client_ctx.get(), server_ctx.get());
+ if (!session) {
+ fprintf(stderr, "Error getting session.\n");
+ return false;
+ }
- if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
- true /* expect session reused */)) {
- fprintf(stderr, "Error resuming session (version = %04x).\n", version);
- return false;
- }
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
- // Change the session ID context.
- if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2,
- sizeof(kContext2))) {
- return false;
- }
+ // Change the session ID context.
+ if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext2,
+ sizeof(kContext2))) {
+ return false;
+ }
- if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
- false /* expect session not reused */)) {
- fprintf(stderr,
- "Error connection with different context (version = %04x).\n",
- version);
- return false;
- }
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error connecting with a different context.\n");
+ return false;
+ }
+
+ // Change the session ID context back and install an SNI callback to switch
+ // it.
+ if (!SSL_CTX_set_session_id_context(server_ctx.get(), kContext1,
+ sizeof(kContext1))) {
+ return false;
+ }
+
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(),
+ SwitchSessionIDContextSNI);
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error connecting with a context switch on SNI callback.\n");
+ return false;
+ }
+
+ // Switch the session ID context with the early callback instead.
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), nullptr);
+ SSL_CTX_set_select_certificate_cb(server_ctx.get(),
+ SwitchSessionIDContextEarly);
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr,
+ "Error connecting with a context switch on early callback.\n");
+ return false;
}
return true;
@@ -2039,16 +2131,78 @@ static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
*out_clock = g_current_time;
}
-static bool TestSessionTimeout() {
+static int RenewTicketCallback(SSL *ssl, uint8_t *key_name, uint8_t *iv,
+ EVP_CIPHER_CTX *ctx, HMAC_CTX *hmac_ctx,
+ int encrypt) {
+ static const uint8_t kZeros[16] = {0};
+
+ if (encrypt) {
+ memcpy(key_name, kZeros, sizeof(kZeros));
+ RAND_bytes(iv, 16);
+ } else if (memcmp(key_name, kZeros, 16) != 0) {
+ return 0;
+ }
+
+ if (!HMAC_Init_ex(hmac_ctx, kZeros, sizeof(kZeros), EVP_sha256(), NULL) ||
+ !EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, kZeros, iv, encrypt)) {
+ return -1;
+ }
+
+ // Returning two from the callback in decrypt mode renews the
+ // session in TLS 1.2 and below.
+ return encrypt ? 1 : 2;
+}
+
+static bool GetServerTicketTime(long *out, const SSL_SESSION *session) {
+ if (session->tlsext_ticklen < 16 + 16 + SHA256_DIGEST_LENGTH) {
+ return false;
+ }
+
+ const uint8_t *ciphertext = session->tlsext_tick + 16 + 16;
+ size_t len = session->tlsext_ticklen - 16 - 16 - SHA256_DIGEST_LENGTH;
+ std::unique_ptr<uint8_t[]> plaintext(new uint8_t[len]);
+
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ // Fuzzer-mode tickets are unencrypted.
+ memcpy(plaintext.get(), ciphertext, len);
+#else
+ static const uint8_t kZeros[16] = {0};
+ const uint8_t *iv = session->tlsext_tick + 16;
+ bssl::ScopedEVP_CIPHER_CTX ctx;
+ int len1, len2;
+ if (!EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_cbc(), nullptr, kZeros, iv) ||
+ !EVP_DecryptUpdate(ctx.get(), plaintext.get(), &len1, ciphertext, len) ||
+ !EVP_DecryptFinal_ex(ctx.get(), plaintext.get() + len1, &len2)) {
+ return false;
+ }
+
+ len = static_cast<size_t>(len1 + len2);
+#endif
+
+ bssl::UniquePtr<SSL_SESSION> server_session(
+ SSL_SESSION_from_bytes(plaintext.get(), len));
+ if (!server_session) {
+ return false;
+ }
+
+ *out = server_session->time;
+ return true;
+}
+
+static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!cert || !key) {
return false;
}
- for (uint16_t version : kTLSVersions) {
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
+ for (bool server_test : std::vector<bool>{false, true}) {
+ static const int kStartTime = 1000;
+ g_current_time.tv_sec = kStartTime;
+
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
if (!server_ctx || !client_ctx ||
!SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
!SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
@@ -2060,23 +2214,31 @@ static bool TestSessionTimeout() {
}
SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH);
-
SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH);
- SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
+
+ // Both client and server must enforce session timeouts.
+ if (server_test) {
+ SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback);
+ } else {
+ SSL_CTX_set_current_time_cb(client_ctx.get(), CurrentTimeCallback);
+ }
+
+ // Configure a ticket callback which renews tickets.
+ SSL_CTX_set_tlsext_ticket_key_cb(server_ctx.get(), RenewTicketCallback);
bssl::UniquePtr<SSL_SESSION> session =
CreateClientSession(client_ctx.get(), server_ctx.get());
if (!session) {
- fprintf(stderr, "Error getting session (version = %04x).\n", version);
+ fprintf(stderr, "Error getting session.\n");
return false;
}
// Advance the clock just behind the timeout.
- g_current_time.tv_sec += SSL_DEFAULT_SESSION_TIMEOUT;
+ g_current_time.tv_sec += SSL_DEFAULT_SESSION_TIMEOUT - 1;
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
true /* expect session reused */)) {
- fprintf(stderr, "Error resuming session (version = %04x).\n", version);
+ fprintf(stderr, "Error resuming session.\n");
return false;
}
@@ -2085,7 +2247,71 @@ static bool TestSessionTimeout() {
if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
false /* expect session not reused */)) {
- fprintf(stderr, "Error resuming session (version = %04x).\n", version);
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // Rewind the clock to before the session was minted.
+ g_current_time.tv_sec = kStartTime - 1;
+
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Error resuming session.\n");
+ return false;
+ }
+
+ // SSL 3.0 cannot renew sessions.
+ if (version == SSL3_VERSION) {
+ continue;
+ }
+
+ // Renew the session 10 seconds before expiration.
+ g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 10;
+ bssl::UniquePtr<SSL_SESSION> new_session =
+ ExpectSessionRenewed(client_ctx.get(), server_ctx.get(), session.get());
+ if (!new_session) {
+ fprintf(stderr, "Error renewing session.\n");
+ return false;
+ }
+
+ // This new session is not the same object as before.
+ if (session.get() == new_session.get()) {
+ fprintf(stderr, "New and old sessions alias.\n");
+ return false;
+ }
+
+ // Check the sessions have timestamps measured from issuance.
+ long session_time = 0;
+ if (server_test) {
+ if (!GetServerTicketTime(&session_time, new_session.get())) {
+ fprintf(stderr, "Failed to decode session ticket.\n");
+ return false;
+ }
+ } else {
+ session_time = new_session->time;
+ }
+
+ if (session_time != g_current_time.tv_sec) {
+ fprintf(stderr, "New session is not measured from issuance.\n");
+ return false;
+ }
+
+ // The new session is usable just before the old expiration.
+ g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT - 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ true /* expect session reused */)) {
+ fprintf(stderr, "Error resuming renewed session.\n");
+ return false;
+ }
+
+ // Renewal does not extend the lifetime, so it is not usable beyond the
+ // old expiration.
+ g_current_time.tv_sec = kStartTime + SSL_DEFAULT_SESSION_TIMEOUT + 1;
+ if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(),
+ new_session.get(),
+ false /* expect session not reused */)) {
+ fprintf(stderr, "Renewed session's lifetime is too long.\n");
return false;
}
}
@@ -2099,7 +2325,13 @@ static int SwitchContext(SSL *ssl, int *out_alert, void *arg) {
return SSL_TLSEXT_ERR_OK;
}
-static bool TestSNICallback() {
+static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL 3.0 lacks extensions.
+ if (version == SSL3_VERSION) {
+ return true;
+ }
+
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
bssl::UniquePtr<X509> cert2 = GetECDSATestCertificate();
@@ -2108,56 +2340,47 @@ static bool TestSNICallback() {
return false;
}
- // At each version, test that switching the |SSL_CTX| at the SNI callback
- // behaves correctly.
- for (uint16_t version : kTLSVersions) {
- if (version == SSL3_VERSION) {
- continue;
- }
-
- static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256;
+ // Test that switching the |SSL_CTX| at the SNI callback behaves correctly.
+ static const uint16_t kECDSAWithSHA256 = SSL_SIGN_ECDSA_SECP256R1_SHA256;
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(TLS_method()));
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method()));
- if (!server_ctx || !server_ctx2 || !client_ctx ||
- !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
- !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) ||
- // Historically signing preferences would be lost in some cases with the
- // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure
- // this doesn't happen when |version| is TLS 1.2, configure the private
- // key to only sign SHA-256.
- !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(),
- &kECDSAWithSHA256, 1) ||
- !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
- !SSL_CTX_set_min_proto_version(server_ctx2.get(), version) ||
- !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) {
- return false;
- }
-
- SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext);
- SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get());
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> server_ctx2(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ if (!server_ctx || !server_ctx2 || !client_ctx ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+ !SSL_CTX_use_certificate(server_ctx2.get(), cert2.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx2.get(), key2.get()) ||
+ // Historically signing preferences would be lost in some cases with the
+ // SNI callback, which triggers the TLS 1.2 SHA-1 default. To ensure
+ // this doesn't happen when |version| is TLS 1.2, configure the private
+ // key to only sign SHA-256.
+ !SSL_CTX_set_signing_algorithm_prefs(server_ctx2.get(), &kECDSAWithSHA256,
+ 1) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx2.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx2.get(), version)) {
+ return false;
+ }
+
+ SSL_CTX_set_tlsext_servername_callback(server_ctx.get(), SwitchContext);
+ SSL_CTX_set_tlsext_servername_arg(server_ctx.get(), server_ctx2.get());
- bssl::UniquePtr<SSL> client, server;
- if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), nullptr)) {
- fprintf(stderr, "Handshake failed at version %04x.\n", version);
- return false;
- }
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr)) {
+ fprintf(stderr, "Handshake failed.\n");
+ return false;
+ }
- // The client should have received |cert2|.
- bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get()));
- if (!peer ||
- X509_cmp(peer.get(), cert2.get()) != 0) {
- fprintf(stderr, "Incorrect certificate received at version %04x.\n",
- version);
- return false;
- }
+ // The client should have received |cert2|.
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(client.get()));
+ if (!peer || X509_cmp(peer.get(), cert2.get()) != 0) {
+ fprintf(stderr, "Incorrect certificate received.\n");
+ return false;
}
return true;
@@ -2280,45 +2503,120 @@ static bool TestSetVersion() {
return true;
}
-static bool TestVersions() {
+static bool TestVersion(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
bssl::UniquePtr<X509> cert = GetTestCertificate();
bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
if (!cert || !key) {
return false;
}
- for (bool is_dtls : std::vector<bool>{false, true}) {
- const SSL_METHOD *method = is_dtls ? DTLS_method() : TLS_method();
- const char *name = is_dtls ? "DTLS" : "TLS";
- const uint16_t *versions = is_dtls ? kDTLSVersions : kTLSVersions;
- size_t num_versions = is_dtls ? OPENSSL_ARRAY_SIZE(kDTLSVersions)
- : OPENSSL_ARRAY_SIZE(kTLSVersions);
- for (size_t i = 0; i < num_versions; i++) {
- uint16_t version = versions[i];
- bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
- bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
- bssl::UniquePtr<SSL> client, server;
- if (!server_ctx || !client_ctx ||
- !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
- !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
- !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
- !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
- !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
- !ConnectClientAndServer(&client, &server, client_ctx.get(),
- server_ctx.get(), nullptr /* no session */)) {
- fprintf(stderr, "Failed to connect %s at version %04x.\n", name,
- version);
- return false;
- }
+ bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method));
+ bssl::UniquePtr<SSL> client, server;
+ if (!server_ctx || !client_ctx ||
+ !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(client_ctx.get(), version) ||
+ !SSL_CTX_set_min_proto_version(server_ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(server_ctx.get(), version) ||
+ !ConnectClientAndServer(&client, &server, client_ctx.get(),
+ server_ctx.get(), nullptr /* no session */)) {
+ fprintf(stderr, "Failed to connect.\n");
+ return false;
+ }
- if (SSL_version(client.get()) != version ||
- SSL_version(server.get()) != version) {
- fprintf(stderr,
- "%s version mismatch. Got %04x and %04x, wanted %04x.\n", name,
- SSL_version(client.get()), SSL_version(server.get()), version);
- return false;
- }
+ if (SSL_version(client.get()) != version ||
+ SSL_version(server.get()) != version) {
+ fprintf(stderr, "Version mismatch. Got %04x and %04x, wanted %04x.\n",
+ SSL_version(client.get()), SSL_version(server.get()), version);
+ return false;
+ }
+
+ return true;
+}
+
+// Tests that that |SSL_get_pending_cipher| is available during the ALPN
+// selection callback.
+static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method,
+ uint16_t version) {
+ // SSL 3.0 lacks extensions.
+ if (version == SSL3_VERSION) {
+ return true;
+ }
+
+ static const uint8_t kALPNProtos[] = {0x03, 'f', 'o', 'o'};
+
+ bssl::UniquePtr<X509> cert = GetTestCertificate();
+ bssl::UniquePtr<EVP_PKEY> key = GetTestKey();
+ if (!cert || !key) {
+ return false;
+ }
+
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(method));
+ if (!ctx || !SSL_CTX_use_certificate(ctx.get(), cert.get()) ||
+ !SSL_CTX_use_PrivateKey(ctx.get(), key.get()) ||
+ !SSL_CTX_set_min_proto_version(ctx.get(), version) ||
+ !SSL_CTX_set_max_proto_version(ctx.get(), version) ||
+ SSL_CTX_set_alpn_protos(ctx.get(), kALPNProtos, sizeof(kALPNProtos)) !=
+ 0) {
+ return false;
+ }
+
+ // The ALPN callback does not fail the handshake on error, so have the
+ // callback write a boolean.
+ std::pair<uint16_t, bool> callback_state(version, false);
+ SSL_CTX_set_alpn_select_cb(
+ ctx.get(),
+ [](SSL *ssl, const uint8_t **out, uint8_t *out_len, const uint8_t *in,
+ unsigned in_len, void *arg) -> int {
+ auto state = reinterpret_cast<std::pair<uint16_t, bool> *>(arg);
+ if (SSL_get_pending_cipher(ssl) != nullptr &&
+ SSL_version(ssl) == state->first) {
+ state->second = true;
+ }
+ return SSL_TLSEXT_ERR_NOACK;
+ },
+ &callback_state);
+
+ bssl::UniquePtr<SSL> client, server;
+ if (!ConnectClientAndServer(&client, &server, ctx.get(), ctx.get(),
+ nullptr /* no session */)) {
+ return false;
+ }
+
+ if (!callback_state.second) {
+ fprintf(stderr, "The pending cipher was not known in the ALPN callback.\n");
+ return false;
+ }
+
+ return true;
+}
+
+static bool ForEachVersion(bool (*test_func)(bool is_dtls,
+ const SSL_METHOD *method,
+ uint16_t version)) {
+ static uint16_t kTLSVersions[] = {
+ SSL3_VERSION, TLS1_VERSION, TLS1_1_VERSION,
+ TLS1_2_VERSION, TLS1_3_VERSION,
+ };
+
+ static uint16_t kDTLSVersions[] = {
+ DTLS1_VERSION, DTLS1_2_VERSION,
+ };
+
+ for (uint16_t version : kTLSVersions) {
+ if (!test_func(false, TLS_method(), version)) {
+ fprintf(stderr, "Test failed at TLS version %04x.\n", version);
+ return false;
+ }
+ }
+
+ for (uint16_t version : kDTLSVersions) {
+ if (!test_func(true, DTLS_method(), version)) {
+ fprintf(stderr, "Test failed at DTLS version %04x.\n", version);
+ return false;
}
}
@@ -2346,23 +2644,31 @@ int main() {
!TestDefaultVersion(TLS1_1_VERSION, TLS1_1_VERSION, &DTLSv1_method) ||
!TestDefaultVersion(TLS1_2_VERSION, TLS1_2_VERSION, &DTLSv1_2_method) ||
!TestCipherGetRFCName() ||
- !TestPaddingExtension() ||
+ // Test the padding extension at TLS 1.2.
+ !TestPaddingExtension(TLS1_2_VERSION, TLS1_2_VERSION) ||
+ // Test the padding extension at TLS 1.3 with a TLS 1.2 session, so there
+ // will be no PSK binder after the padding extension.
+ !TestPaddingExtension(TLS1_3_VERSION, TLS1_2_VERSION) ||
+ // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there
+ // will be a PSK binder after the padding extension.
+ !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) ||
!TestClientCAList() ||
!TestInternalSessionCache() ||
- !TestSequenceNumber() ||
- !TestOneSidedShutdown() ||
+ !ForEachVersion(TestSequenceNumber) ||
+ !ForEachVersion(TestOneSidedShutdown) ||
!TestSessionDuplication() ||
!TestSetFD() ||
!TestSetBIO() ||
- !TestGetPeerCertificate() ||
- !TestRetainOnlySHA256OfCerts() ||
+ !ForEachVersion(TestGetPeerCertificate) ||
+ !ForEachVersion(TestRetainOnlySHA256OfCerts) ||
!TestClientHello() ||
- !TestSessionIDContext() ||
- !TestSessionTimeout() ||
- !TestSNICallback() ||
+ !ForEachVersion(TestSessionIDContext) ||
+ !ForEachVersion(TestSessionTimeout) ||
+ !ForEachVersion(TestSNICallback) ||
!TestEarlyCallbackVersionSwitch() ||
!TestSetVersion() ||
- !TestVersions()) {
+ !ForEachVersion(TestVersion) ||
+ !ForEachVersion(TestALPNCipherAvailable)) {
ERR_print_errors_fp(stderr);
return 1;
}
diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c
index 4b8fe455..4c7d3ee3 100644
--- a/src/ssl/t1_enc.c
+++ b/src/ssl/t1_enc.c
@@ -258,6 +258,63 @@ static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len,
return 1;
}
+static int tls1_setup_key_block(SSL *ssl) {
+ if (ssl->s3->hs->key_block_len != 0) {
+ return 1;
+ }
+
+ SSL_SESSION *session = ssl->session;
+ if (ssl->s3->new_session != NULL) {
+ session = ssl->s3->new_session;
+ }
+
+ const EVP_AEAD *aead = NULL;
+ size_t mac_secret_len, fixed_iv_len;
+ if (session->cipher == NULL ||
+ !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+ session->cipher, ssl3_protocol_version(ssl))) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
+ return 0;
+ }
+ size_t key_len = EVP_AEAD_key_length(aead);
+ if (mac_secret_len > 0) {
+ /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
+ * key length reported by |EVP_AEAD_key_length| will include the MAC key
+ * bytes and initial implicit IV. */
+ if (key_len < mac_secret_len + fixed_iv_len) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ key_len -= mac_secret_len + fixed_iv_len;
+ }
+
+ assert(mac_secret_len < 256);
+ assert(key_len < 256);
+ assert(fixed_iv_len < 256);
+
+ ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
+ ssl->s3->tmp.new_key_len = (uint8_t)key_len;
+ ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
+
+ size_t key_block_len = SSL_get_key_block_len(ssl);
+
+ uint8_t *keyblock = OPENSSL_malloc(key_block_len);
+ if (keyblock == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+
+ if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
+ OPENSSL_free(keyblock);
+ return 0;
+ }
+
+ assert(key_block_len < 256);
+ ssl->s3->hs->key_block_len = (uint8_t)key_block_len;
+ ssl->s3->hs->key_block = keyblock;
+ return 1;
+}
+
int tls1_change_cipher_state(SSL *ssl, int which) {
/* Ensure the key block is set up. */
if (!tls1_setup_key_block(ssl)) {
@@ -276,10 +333,9 @@ int tls1_change_cipher_state(SSL *ssl, int which) {
size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len;
size_t key_len = ssl->s3->tmp.new_key_len;
size_t iv_len = ssl->s3->tmp.new_fixed_iv_len;
- assert((mac_secret_len + key_len + iv_len) * 2 ==
- ssl->s3->tmp.key_block_length);
+ assert((mac_secret_len + key_len + iv_len) * 2 == ssl->s3->hs->key_block_len);
- const uint8_t *key_data = ssl->s3->tmp.key_block;
+ const uint8_t *key_data = ssl->s3->hs->key_block;
const uint8_t *client_write_mac_secret = key_data;
key_data += mac_secret_len;
const uint8_t *server_write_mac_secret = key_data;
@@ -333,65 +389,6 @@ int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
ssl->s3->client_random, SSL3_RANDOM_SIZE);
}
-int tls1_setup_key_block(SSL *ssl) {
- if (ssl->s3->tmp.key_block_length != 0) {
- return 1;
- }
-
- SSL_SESSION *session = ssl->session;
- if (ssl->s3->new_session != NULL) {
- session = ssl->s3->new_session;
- }
-
- const EVP_AEAD *aead = NULL;
- size_t mac_secret_len, fixed_iv_len;
- if (session->cipher == NULL ||
- !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
- session->cipher, ssl3_protocol_version(ssl))) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE);
- return 0;
- }
- size_t key_len = EVP_AEAD_key_length(aead);
- if (mac_secret_len > 0) {
- /* For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the
- * key length reported by |EVP_AEAD_key_length| will include the MAC key
- * bytes and initial implicit IV. */
- if (key_len < mac_secret_len + fixed_iv_len) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- key_len -= mac_secret_len + fixed_iv_len;
- }
-
- assert(mac_secret_len < 256);
- assert(key_len < 256);
- assert(fixed_iv_len < 256);
-
- ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len;
- ssl->s3->tmp.new_key_len = (uint8_t)key_len;
- ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len;
-
- size_t key_block_len = SSL_get_key_block_len(ssl);
-
- ssl3_cleanup_key_block(ssl);
-
- uint8_t *keyblock = OPENSSL_malloc(key_block_len);
- if (keyblock == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- if (!SSL_generate_key_block(ssl, keyblock, key_block_len)) {
- OPENSSL_free(keyblock);
- return 0;
- }
-
- assert(key_block_len < 256);
- ssl->s3->tmp.key_block_length = (uint8_t)key_block_len;
- ssl->s3->tmp.key_block = keyblock;
- return 1;
-}
-
static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len,
size_t max_out) {
int ret = 0;
@@ -505,6 +502,11 @@ int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
return 0;
}
+ /* Exporters may not be used in the middle of a renegotiation. */
+ if (SSL_in_init(ssl) && !SSL_in_false_start(ssl)) {
+ return 0;
+ }
+
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
return tls13_export_keying_material(ssl, out, out_len, label, label_len,
context, context_len, use_context);
diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c
index 9655b83d..421232f1 100644
--- a/src/ssl/t1_lib.c
+++ b/src/ssl/t1_lib.c
@@ -442,62 +442,73 @@ int tls1_check_group_id(SSL *ssl, uint16_t group_id) {
}
/* kVerifySignatureAlgorithms is the default list of accepted signature
- * algorithms for verifying. */
+ * algorithms for verifying.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
static const uint16_t kVerifySignatureAlgorithms[] = {
- /* For now, do not enable RSA-PSS signature algorithms on Android's system
- * BoringSSL. Once TLS 1.3 is finalized and the change in Chrome has stuck,
- * restore them. */
+ /* Prefer SHA-256 algorithms. */
+ SSL_SIGN_ECDSA_SECP256R1_SHA256,
#if !defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_SIGN_RSA_PSS_SHA512,
-#endif
- SSL_SIGN_RSA_PKCS1_SHA512,
- /* TODO(davidben): Remove this entry and SSL_CURVE_SECP521R1 from
- * kDefaultGroups. */
-#if defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_SIGN_ECDSA_SECP521R1_SHA512,
+ SSL_SIGN_RSA_PSS_SHA256,
#endif
+ SSL_SIGN_RSA_PKCS1_SHA256,
+ /* Larger hashes are acceptable. */
+ SSL_SIGN_ECDSA_SECP384R1_SHA384,
#if !defined(BORINGSSL_ANDROID_SYSTEM)
SSL_SIGN_RSA_PSS_SHA384,
#endif
SSL_SIGN_RSA_PKCS1_SHA384,
- SSL_SIGN_ECDSA_SECP384R1_SHA384,
+ /* TODO(davidben): Remove this entry and SSL_CURVE_SECP521R1 from
+ * kDefaultGroups. */
+#if defined(BORINGSSL_ANDROID_SYSTEM)
+ SSL_SIGN_ECDSA_SECP521R1_SHA512,
+#endif
#if !defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_SIGN_RSA_PSS_SHA256,
+ SSL_SIGN_RSA_PSS_SHA512,
#endif
- SSL_SIGN_RSA_PKCS1_SHA256,
- SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ SSL_SIGN_RSA_PKCS1_SHA512,
+ /* For now, SHA-1 is still accepted but least preferable. */
SSL_SIGN_RSA_PKCS1_SHA1,
+
};
/* kSignSignatureAlgorithms is the default list of supported signature
- * algorithms for signing. */
+ * algorithms for signing.
+ *
+ * For now, RSA-PSS signature algorithms are not enabled on Android's system
+ * BoringSSL. Once the change in Chrome has stuck and the values are finalized,
+ * restore them. */
static const uint16_t kSignSignatureAlgorithms[] = {
- /* For now, do not enable RSA-PSS signature algorithms on Android's system
- * BoringSSL. Once TLS 1.3 is finalized and the change in Chrome has stuck,
- * restore them. */
+ /* Prefer SHA-256 algorithms. */
+ SSL_SIGN_ECDSA_SECP256R1_SHA256,
#if !defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_SIGN_RSA_PSS_SHA512,
+ SSL_SIGN_RSA_PSS_SHA256,
#endif
- SSL_SIGN_RSA_PKCS1_SHA512,
- SSL_SIGN_ECDSA_SECP521R1_SHA512,
+ SSL_SIGN_RSA_PKCS1_SHA256,
+ /* If needed, sign larger hashes.
+ *
+ * TODO(davidben): Determine which of these may be pruned. */
+ SSL_SIGN_ECDSA_SECP384R1_SHA384,
#if !defined(BORINGSSL_ANDROID_SYSTEM)
SSL_SIGN_RSA_PSS_SHA384,
#endif
SSL_SIGN_RSA_PKCS1_SHA384,
- SSL_SIGN_ECDSA_SECP384R1_SHA384,
+ SSL_SIGN_ECDSA_SECP521R1_SHA512,
#if !defined(BORINGSSL_ANDROID_SYSTEM)
- SSL_SIGN_RSA_PSS_SHA256,
+ SSL_SIGN_RSA_PSS_SHA512,
#endif
- SSL_SIGN_RSA_PKCS1_SHA256,
- SSL_SIGN_ECDSA_SECP256R1_SHA256,
+ SSL_SIGN_RSA_PKCS1_SHA512,
- SSL_SIGN_RSA_PKCS1_SHA1,
+ /* If the peer supports nothing else, sign with SHA-1. */
SSL_SIGN_ECDSA_SHA1,
+ SSL_SIGN_RSA_PKCS1_SHA1,
};
size_t tls12_get_verify_sigalgs(const SSL *ssl, const uint16_t **out) {
@@ -694,28 +705,19 @@ static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert,
return 0;
}
- /* TODO(davidben): SNI should be resolved before resumption. We have the
- * early callback as a replacement, but we should fix the current callback
- * and avoid the need for |SSL_CTX_set_session_id_context|. */
- if (ssl->session == NULL) {
- assert(ssl->s3->new_session->tlsext_hostname == NULL);
-
- /* Copy the hostname as a string. */
- if (!CBS_strdup(&host_name, &ssl->s3->new_session->tlsext_hostname)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
-
- ssl->s3->hs->should_ack_sni = 1;
+ /* Copy the hostname as a string. */
+ if (!CBS_strdup(&host_name, &ssl->s3->hs->hostname)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
}
+ ssl->s3->hs->should_ack_sni = 1;
return 1;
}
static int ext_sni_add_serverhello(SSL *ssl, CBB *out) {
- if (ssl->session != NULL ||
- !ssl->s3->hs->should_ack_sni ||
- ssl->s3->new_session->tlsext_hostname == NULL) {
+ if (ssl->s3->session_reused ||
+ !ssl->s3->hs->should_ack_sni) {
return 1;
}
@@ -1019,8 +1021,6 @@ static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) {
static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert,
CBS *contents) {
- ssl->tlsext_ticket_expected = 0;
-
if (contents == NULL) {
return 1;
}
@@ -1038,17 +1038,16 @@ static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 0;
}
- ssl->tlsext_ticket_expected = 1;
+ ssl->s3->hs->ticket_expected = 1;
return 1;
}
static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) {
- if (!ssl->tlsext_ticket_expected) {
+ if (!ssl->s3->hs->ticket_expected) {
return 1;
}
- /* If |SSL_OP_NO_TICKET| is set, |tlsext_ticket_expected| should never be
- * true. */
+ /* If |SSL_OP_NO_TICKET| is set, |ticket_expected| should never be true. */
assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0);
if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) ||
@@ -1152,42 +1151,22 @@ static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 1;
}
- if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
- /* OCSP stapling is forbidden on non-certificate ciphers. */
- if (CBS_len(contents) != 0 ||
- !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- return 0;
- }
-
- /* Note this does not check for resumption in TLS 1.2. Sending
- * status_request here does not make sense, but OpenSSL does so and the
- * specification does not say anything. Tolerate it but ignore it. */
-
- ssl->s3->hs->certificate_status_expected = 1;
- return 1;
- }
-
- /* In TLS 1.3, OCSP stapling is forbidden on resumption. */
- if (ssl->s3->session_reused) {
+ /* TLS 1.3 OCSP responses are included in the Certificate extensions. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
return 0;
}
- uint8_t status_type;
- CBS ocsp_response;
- if (!CBS_get_u8(contents, &status_type) ||
- status_type != TLSEXT_STATUSTYPE_ocsp ||
- !CBS_get_u24_length_prefixed(contents, &ocsp_response) ||
- CBS_len(&ocsp_response) == 0 ||
- CBS_len(contents) != 0) {
+ /* OCSP stapling is forbidden on non-certificate ciphers. */
+ if (CBS_len(contents) != 0 ||
+ !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
return 0;
}
- if (!CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
- &ssl->s3->new_session->ocsp_response_length)) {
- *out_alert = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
+ /* Note this does not check for resumption in TLS 1.2. Sending
+ * status_request here does not make sense, but OpenSSL does so and the
+ * specification does not say anything. Tolerate it but ignore it. */
+ ssl->s3->hs->certificate_status_expected = 1;
return 1;
}
@@ -1210,34 +1189,18 @@ static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert,
}
static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) {
- if (!ssl->s3->hs->ocsp_stapling_requested ||
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ !ssl->s3->hs->ocsp_stapling_requested ||
ssl->ctx->ocsp_response_length == 0 ||
ssl->s3->session_reused ||
- (ssl3_protocol_version(ssl) < TLS1_3_VERSION &&
- !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher))) {
+ !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
return 1;
}
- if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
- /* The extension shouldn't be sent when resuming sessions. */
- if (ssl->session != NULL) {
- return 1;
- }
+ ssl->s3->hs->certificate_status_expected = 1;
- ssl->s3->hs->certificate_status_expected = 1;
-
- return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
- CBB_add_u16(out, 0 /* length */);
- }
-
- CBB body, ocsp_response;
return CBB_add_u16(out, TLSEXT_TYPE_status_request) &&
- CBB_add_u16_length_prefixed(out, &body) &&
- CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) &&
- CBB_add_u24_length_prefixed(&body, &ocsp_response) &&
- CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
- ssl->ctx->ocsp_response_length) &&
- CBB_flush(out);
+ CBB_add_u16(out, 0 /* length */);
}
@@ -1331,10 +1294,6 @@ static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
if (contents == NULL ||
ssl->s3->initial_handshake_complete ||
- /* If the ALPN extension is seen before NPN, ignore it. (If ALPN is seen
- * afterwards, parsing the ALPN extension will clear
- * |next_proto_neg_seen|. */
- ssl->s3->alpn_selected != NULL ||
ssl->ctx->next_protos_advertised_cb == NULL ||
SSL_is_dtls(ssl)) {
return 1;
@@ -1396,11 +1355,17 @@ static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 1;
}
+ /* TLS 1.3 SCTs are included in the Certificate extensions. */
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
/* If this is false then we should never have sent the SCT extension in the
* ClientHello and thus this function should never have been called. */
assert(ssl->signed_cert_timestamps_enabled);
- if (CBS_len(contents) == 0) {
+ if (!ssl_is_sct_list_valid(contents)) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
@@ -1424,12 +1389,22 @@ static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert,
static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert,
CBS *contents) {
- return contents == NULL || CBS_len(contents) == 0;
+ if (contents == NULL) {
+ return 1;
+ }
+
+ if (CBS_len(contents) != 0) {
+ return 0;
+ }
+
+ ssl->s3->hs->scts_requested = 1;
+ return 1;
}
static int ext_sct_add_serverhello(SSL *ssl, CBB *out) {
/* The extension shouldn't be sent when resuming sessions. */
- if (ssl->s3->session_reused ||
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
+ ssl->s3->session_reused ||
ssl->ctx->signed_cert_timestamp_list_length == 0) {
return 1;
}
@@ -1447,11 +1422,6 @@ static int ext_sct_add_serverhello(SSL *ssl, CBB *out) {
*
* https://tools.ietf.org/html/rfc7301 */
-static void ext_alpn_init(SSL *ssl) {
- OPENSSL_free(ssl->s3->alpn_selected);
- ssl->s3->alpn_selected = NULL;
-}
-
static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) {
if (ssl->alpn_client_proto_list == NULL ||
ssl->s3->initial_handshake_complete) {
@@ -1534,14 +1504,14 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 1;
}
-static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
- CBS *contents) {
- if (contents == NULL) {
- return 1;
- }
-
+int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert,
+ const struct ssl_early_callback_ctx *client_hello) {
+ CBS contents;
if (ssl->ctx->alpn_select_cb == NULL ||
- ssl->s3->initial_handshake_complete) {
+ !ssl_early_callback_get_extension(
+ client_hello, &contents,
+ TLSEXT_TYPE_application_layer_protocol_negotiation)) {
+ /* Ignore ALPN if not configured or no extension was supplied. */
return 1;
}
@@ -1549,9 +1519,11 @@ static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
ssl->s3->hs->next_proto_neg_seen = 0;
CBS protocol_name_list;
- if (!CBS_get_u16_length_prefixed(contents, &protocol_name_list) ||
- CBS_len(contents) != 0 ||
+ if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) ||
+ CBS_len(&contents) != 0 ||
CBS_len(&protocol_name_list) < 2) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
@@ -1563,6 +1535,8 @@ static int ext_alpn_parse_clienthello(SSL *ssl, uint8_t *out_alert,
if (!CBS_get_u8_length_prefixed(&protocol_name_list_copy, &protocol_name) ||
/* Empty protocol names are forbidden. */
CBS_len(&protocol_name) == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
+ *out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
}
@@ -1633,10 +1607,6 @@ static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 1;
}
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
- return 0;
- }
-
assert(!SSL_is_dtls(ssl));
assert(ssl->tlsext_channel_id_enabled);
@@ -1665,10 +1635,6 @@ static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert,
}
static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) {
- if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
- return 1;
- }
-
if (!ssl->s3->tlsext_channel_id_valid) {
return 1;
}
@@ -1836,26 +1802,6 @@ static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) {
*
* https://tools.ietf.org/html/rfc4492#section-5.1.2 */
-static int ssl_any_ec_cipher_suites_enabled(const SSL *ssl) {
- if (ssl->version < TLS1_VERSION && !SSL_is_dtls(ssl)) {
- return 0;
- }
-
- const STACK_OF(SSL_CIPHER) *cipher_stack = SSL_get_ciphers(ssl);
-
- for (size_t i = 0; i < sk_SSL_CIPHER_num(cipher_stack); i++) {
- const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(cipher_stack, i);
-
- const uint32_t alg_k = cipher->algorithm_mkey;
- const uint32_t alg_a = cipher->algorithm_auth;
- if ((alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA)) {
- return 1;
- }
- }
-
- return 0;
-}
-
static int ext_ec_point_add_extension(SSL *ssl, CBB *out) {
CBB contents, formats;
if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) ||
@@ -1870,7 +1816,13 @@ static int ext_ec_point_add_extension(SSL *ssl, CBB *out) {
}
static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) {
- if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ /* The point format extension is unneccessary in TLS 1.3. */
+ if (min_version >= TLS1_3_VERSION) {
return 1;
}
@@ -1929,9 +1881,30 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) {
return ext_ec_point_add_extension(ssl, out);
}
+
/* Pre Shared Key
*
- * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.6 */
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 */
+
+static size_t ext_pre_shared_key_clienthello_length(SSL *ssl) {
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ uint16_t session_version;
+ if (max_version < TLS1_3_VERSION || ssl->session == NULL ||
+ !ssl->method->version_from_wire(&session_version,
+ ssl->session->ssl_version) ||
+ session_version < TLS1_3_VERSION) {
+ return 0;
+ }
+
+ const EVP_MD *digest =
+ ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+ size_t binder_len = EVP_MD_size(digest);
+ return 15 + ssl->session->tlsext_ticklen + binder_len;
+}
static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) {
uint16_t min_version, max_version;
@@ -1947,20 +1920,33 @@ static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) {
return 1;
}
- CBB contents, identity, ke_modes, auth_modes, ticket;
+ struct timeval now;
+ ssl_get_current_time(ssl, &now);
+ uint32_t ticket_age = 1000 * (now.tv_sec - ssl->session->time);
+ uint32_t obfuscated_ticket_age = ticket_age + ssl->session->ticket_age_add;
+
+ /* Fill in a placeholder zero binder of the appropriate length. It will be
+ * computed and filled in later after length prefixes are computed. */
+ uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
+ const EVP_MD *digest =
+ ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+ size_t binder_len = EVP_MD_size(digest);
+
+ CBB contents, identity, ticket, binders, binder;
if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
!CBB_add_u16_length_prefixed(&contents, &identity) ||
- !CBB_add_u8_length_prefixed(&identity, &ke_modes) ||
- !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE) ||
- !CBB_add_u8_length_prefixed(&identity, &auth_modes) ||
- !CBB_add_u8(&auth_modes, SSL_PSK_AUTH) ||
!CBB_add_u16_length_prefixed(&identity, &ticket) ||
!CBB_add_bytes(&ticket, ssl->session->tlsext_tick,
- ssl->session->tlsext_ticklen)) {
+ ssl->session->tlsext_ticklen) ||
+ !CBB_add_u32(&identity, obfuscated_ticket_age) ||
+ !CBB_add_u16_length_prefixed(&contents, &binders) ||
+ !CBB_add_u8_length_prefixed(&binders, &binder) ||
+ !CBB_add_bytes(&binder, zero_binder, binder_len)) {
return 0;
}
+ ssl->s3->hs->needs_psk_binder = 1;
return CBB_flush(out);
}
@@ -1974,6 +1960,7 @@ int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert,
return 0;
}
+ /* We only advertise one PSK identity, so the only legal index is zero. */
if (psk_id != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
*out_alert = SSL_AD_UNKNOWN_PSK_IDENTITY;
@@ -1985,32 +1972,45 @@ int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert,
int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl,
SSL_SESSION **out_session,
+ CBS *out_binders,
uint8_t *out_alert,
CBS *contents) {
/* We only process the first PSK identity since we don't support pure PSK. */
- CBS identity, ke_modes, auth_modes, ticket;
+ uint32_t obfuscated_ticket_age;
+ CBS identity, ticket, binders;
if (!CBS_get_u16_length_prefixed(contents, &identity) ||
- !CBS_get_u8_length_prefixed(&identity, &ke_modes) ||
- !CBS_get_u8_length_prefixed(&identity, &auth_modes) ||
!CBS_get_u16_length_prefixed(&identity, &ticket) ||
- CBS_len(&identity) != 0) {
+ !CBS_get_u32(&identity, &obfuscated_ticket_age) ||
+ !CBS_get_u16_length_prefixed(contents, &binders) ||
+ CBS_len(contents) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
- /* We only support tickets with PSK_DHE_KE and PSK_AUTH. */
- if (memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) == NULL ||
- memchr(CBS_data(&auth_modes), SSL_PSK_AUTH, CBS_len(&auth_modes)) ==
- NULL) {
- *out_session = NULL;
- return 1;
+ *out_binders = binders;
+
+ /* The PSK identity must have a corresponding binder. */
+ CBS binder;
+ if (!CBS_get_u8_length_prefixed(&binders, &binder)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
}
+ /* TODO(svaldez): Check that the ticket_age is valid when attempting to use
+ * the PSK for 0-RTT. http://crbug.com/boringssl/113 */
+
/* TLS 1.3 session tickets are renewed separately as part of the
* NewSessionTicket. */
- int renew;
- return tls_process_ticket(ssl, out_session, &renew, CBS_data(&ticket),
- CBS_len(&ticket), NULL, 0);
+ int unused_renew;
+ if (!tls_process_ticket(ssl, out_session, &unused_renew, CBS_data(&ticket),
+ CBS_len(&ticket), NULL, 0)) {
+ *out_alert = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+
+ return 1;
}
int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) {
@@ -2031,6 +2031,53 @@ int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) {
}
+/* Pre-Shared Key Exchange Modes
+ *
+ * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 */
+static int ext_psk_key_exchange_modes_add_clienthello(SSL *ssl, CBB *out) {
+ uint16_t min_version, max_version;
+ if (!ssl_get_version_range(ssl, &min_version, &max_version)) {
+ return 0;
+ }
+
+ if (max_version < TLS1_3_VERSION) {
+ return 1;
+ }
+
+ CBB contents, ke_modes;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_psk_key_exchange_modes) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u8_length_prefixed(&contents, &ke_modes) ||
+ !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE)) {
+ return 0;
+ }
+
+ return CBB_flush(out);
+}
+
+static int ext_psk_key_exchange_modes_parse_clienthello(SSL *ssl,
+ uint8_t *out_alert,
+ CBS *contents) {
+ if (contents == NULL) {
+ return 1;
+ }
+
+ CBS ke_modes;
+ if (!CBS_get_u8_length_prefixed(contents, &ke_modes) ||
+ CBS_len(&ke_modes) == 0 ||
+ CBS_len(contents) != 0) {
+ *out_alert = SSL_AD_DECODE_ERROR;
+ return 0;
+ }
+
+ /* We only support tickets with PSK_DHE_KE. */
+ ssl->s3->hs->accept_psk_mode =
+ memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL;
+
+ return 1;
+}
+
+
/* Key Share
*
* https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.5 */
@@ -2052,21 +2099,18 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) {
return 0;
}
- uint16_t group_id;
+ uint16_t group_id = ssl->s3->hs->retry_group;
if (ssl->s3->hs->received_hello_retry_request) {
- /* Replay the old key shares. */
- if (!CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes,
+ /* We received a HelloRetryRequest without a new curve, so there is no new
+ * share to append. Leave |ecdh_ctx| as-is. */
+ if (group_id == 0 &&
+ !CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes,
ssl->s3->hs->key_share_bytes_len)) {
return 0;
}
OPENSSL_free(ssl->s3->hs->key_share_bytes);
ssl->s3->hs->key_share_bytes = NULL;
ssl->s3->hs->key_share_bytes_len = 0;
-
- group_id = ssl->s3->hs->retry_group;
-
- /* We received a HelloRetryRequest without a new curve, so there is no new
- * share to append. Leave |ecdh_ctx| as-is. */
if (group_id == 0) {
return CBB_flush(out);
}
@@ -2319,10 +2363,6 @@ static int ext_cookie_add_clienthello(SSL *ssl, CBB *out) {
* https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.4 */
static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) {
- if (!ssl_any_ec_cipher_suites_enabled(ssl)) {
- return 1;
- }
-
CBB contents, groups_bytes;
if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) ||
!CBB_add_u16_length_prefixed(out, &contents) ||
@@ -2473,10 +2513,11 @@ static const struct tls_extension kExtensions[] = {
},
{
TLSEXT_TYPE_application_layer_protocol_negotiation,
- ext_alpn_init,
+ NULL,
ext_alpn_add_clienthello,
ext_alpn_parse_serverhello,
- ext_alpn_parse_clienthello,
+ /* ALPN is negotiated late in |ssl_negotiate_alpn|. */
+ ignore_parse_clienthello,
ext_alpn_add_serverhello,
},
{
@@ -2512,11 +2553,11 @@ static const struct tls_extension kExtensions[] = {
dont_add_serverhello,
},
{
- TLSEXT_TYPE_pre_shared_key,
+ TLSEXT_TYPE_psk_key_exchange_modes,
NULL,
- ext_pre_shared_key_add_clienthello,
+ ext_psk_key_exchange_modes_add_clienthello,
forbid_parse_serverhello,
- ignore_parse_clienthello,
+ ext_psk_key_exchange_modes_parse_clienthello,
dont_add_serverhello,
},
{
@@ -2611,7 +2652,7 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
const size_t len_before = CBB_len(&extensions);
if (!kExtensions[i].add_clienthello(ssl, &extensions)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
goto err;
}
@@ -2643,7 +2684,8 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
}
if (!SSL_is_dtls(ssl)) {
- header_len += 2 + CBB_len(&extensions);
+ size_t psk_extension_len = ext_pre_shared_key_clienthello_length(ssl);
+ header_len += 2 + CBB_len(&extensions) + psk_extension_len;
if (header_len > 0xff && header_len < 0x200) {
/* Add padding to workaround bugs in F5 terminators. See RFC 7685.
*
@@ -2671,6 +2713,11 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) {
}
}
+ /* The PSK extension must be last, including after the padding. */
+ if (!ext_pre_shared_key_add_clienthello(ssl, &extensions)) {
+ goto err;
+ }
+
/* Discard empty extensions blocks. */
if (CBB_len(&extensions) == 0) {
CBB_discard_child(out);
@@ -2698,7 +2745,7 @@ int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) {
if (!kExtensions[i].add_serverhello(ssl, &extensions)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
goto err;
}
}
@@ -2768,7 +2815,7 @@ static int ssl_scan_clienthello_tlsext(
if (!ext->parse_clienthello(ssl, &alert, &extension)) {
*out_alert = alert;
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)type);
+ ERR_add_error_dataf("extension %u", (unsigned)type);
return 0;
}
}
@@ -2796,7 +2843,7 @@ static int ssl_scan_clienthello_tlsext(
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!kExtensions[i].parse_clienthello(ssl, &alert, contents)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
*out_alert = alert;
return 0;
}
@@ -2875,7 +2922,7 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!ext->parse_serverhello(ssl, &alert, &extension)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)type);
+ ERR_add_error_dataf("extension %u", (unsigned)type);
*out_alert = alert;
return 0;
}
@@ -2888,7 +2935,7 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) {
uint8_t alert = SSL_AD_DECODE_ERROR;
if (!kExtensions[i].parse_serverhello(ssl, &alert, NULL)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
- ERR_add_error_dataf("extension: %u", (unsigned)kExtensions[i].value);
+ ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value);
*out_alert = alert;
return 0;
}
@@ -3090,12 +3137,6 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session,
memcpy(session->session_id, session_id, session_id_len);
session->session_id_length = session_id_len;
- if (!ssl_session_is_context_valid(ssl, session) ||
- !ssl_session_is_time_valid(ssl, session)) {
- SSL_SESSION_free(session);
- session = NULL;
- }
-
*out_session = session;
done:
@@ -3207,45 +3248,184 @@ int tls1_choose_signature_algorithm(SSL *ssl, uint16_t *out) {
return 0;
}
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+int tls1_verify_channel_id(SSL *ssl) {
+ int ret = 0;
+ uint16_t extension_type;
+ CBS extension, channel_id;
+
+ /* A Channel ID handshake message is structured to contain multiple
+ * extensions, but the only one that can be present is Channel ID. */
+ CBS_init(&channel_id, ssl->init_msg, ssl->init_num);
+ if (!CBS_get_u16(&channel_id, &extension_type) ||
+ !CBS_get_u16_length_prefixed(&channel_id, &extension) ||
+ CBS_len(&channel_id) != 0 ||
+ extension_type != TLSEXT_TYPE_channel_id ||
+ CBS_len(&extension) != TLSEXT_CHANNEL_ID_SIZE) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return 0;
+ }
+
+ EC_GROUP *p256 = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ if (!p256) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_P256_SUPPORT);
+ return 0;
+ }
+
+ EC_KEY *key = NULL;
+ EC_POINT *point = NULL;
+ BIGNUM x, y;
+ ECDSA_SIG sig;
+ BN_init(&x);
+ BN_init(&y);
+ sig.r = BN_new();
+ sig.s = BN_new();
+ if (sig.r == NULL || sig.s == NULL) {
+ goto err;
+ }
+
+ const uint8_t *p = CBS_data(&extension);
+ if (BN_bin2bn(p + 0, 32, &x) == NULL ||
+ BN_bin2bn(p + 32, 32, &y) == NULL ||
+ BN_bin2bn(p + 64, 32, sig.r) == NULL ||
+ BN_bin2bn(p + 96, 32, sig.s) == NULL) {
+ goto err;
+ }
+
+ point = EC_POINT_new(p256);
+ if (point == NULL ||
+ !EC_POINT_set_affine_coordinates_GFp(p256, point, &x, &y, NULL)) {
+ goto err;
+ }
+
+ key = EC_KEY_new();
+ if (key == NULL ||
+ !EC_KEY_set_group(key, p256) ||
+ !EC_KEY_set_public_key(key, point)) {
+ goto err;
+ }
+
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+ goto err;
+ }
+
+ int sig_ok = ECDSA_do_verify(digest, digest_len, &sig, key);
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ sig_ok = 1;
+#endif
+ if (!sig_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_SIGNATURE_INVALID);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ ssl->s3->tlsext_channel_id_valid = 0;
+ goto err;
+ }
+
+ memcpy(ssl->s3->tlsext_channel_id, p, 64);
+ ret = 1;
+
+err:
+ BN_free(&x);
+ BN_free(&y);
+ BN_free(sig.r);
+ BN_free(sig.s);
+ EC_KEY_free(key);
+ EC_POINT_free(point);
+ EC_GROUP_free(p256);
+ return ret;
+}
+
+int tls1_write_channel_id(SSL *ssl, CBB *cbb) {
+ uint8_t digest[EVP_MAX_MD_SIZE];
+ size_t digest_len;
+ if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+ return 0;
+ }
+
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(ssl->tlsext_channel_id_private);
+ if (ec_key == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
int ret = 0;
- EVP_MD_CTX ctx;
+ BIGNUM *x = BN_new();
+ BIGNUM *y = BN_new();
+ ECDSA_SIG *sig = NULL;
+ if (x == NULL || y == NULL ||
+ !EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(ec_key),
+ EC_KEY_get0_public_key(ec_key),
+ x, y, NULL)) {
+ goto err;
+ }
- EVP_MD_CTX_init(&ctx);
- if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) {
+ sig = ECDSA_do_sign(digest, digest_len, ec_key);
+ if (sig == NULL) {
goto err;
}
+ CBB child;
+ if (!CBB_add_u16(cbb, TLSEXT_TYPE_channel_id) ||
+ !CBB_add_u16_length_prefixed(cbb, &child) ||
+ !BN_bn2cbb_padded(&child, 32, x) ||
+ !BN_bn2cbb_padded(&child, 32, y) ||
+ !BN_bn2cbb_padded(&child, 32, sig->r) ||
+ !BN_bn2cbb_padded(&child, 32, sig->s) ||
+ !CBB_flush(cbb)) {
+ goto err;
+ }
+
+ ret = 1;
+
+err:
+ BN_free(x);
+ BN_free(y);
+ ECDSA_SIG_free(sig);
+ return ret;
+}
+
+int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
+ uint8_t *msg;
+ size_t msg_len;
+ if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
+ ssl_cert_verify_channel_id)) {
+ return 0;
+ }
+ SHA256(msg, msg_len, out);
+ *out_len = SHA256_DIGEST_LENGTH;
+ OPENSSL_free(msg);
+ return 1;
+ }
+
+ SHA256_CTX ctx;
+
+ SHA256_Init(&ctx);
static const char kClientIDMagic[] = "TLS Channel ID signature";
- EVP_DigestUpdate(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
+ SHA256_Update(&ctx, kClientIDMagic, sizeof(kClientIDMagic));
if (ssl->session != NULL) {
static const char kResumptionMagic[] = "Resumption";
- EVP_DigestUpdate(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
+ SHA256_Update(&ctx, kResumptionMagic, sizeof(kResumptionMagic));
if (ssl->session->original_handshake_hash_len == 0) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
+ return 0;
}
- EVP_DigestUpdate(&ctx, ssl->session->original_handshake_hash,
- ssl->session->original_handshake_hash_len);
+ SHA256_Update(&ctx, ssl->session->original_handshake_hash,
+ ssl->session->original_handshake_hash_len);
}
uint8_t handshake_hash[EVP_MAX_MD_SIZE];
int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash,
sizeof(handshake_hash));
if (handshake_hash_len < 0) {
- goto err;
+ return 0;
}
- EVP_DigestUpdate(&ctx, handshake_hash, (size_t)handshake_hash_len);
- unsigned len_u;
- EVP_DigestFinal_ex(&ctx, out, &len_u);
- *out_len = len_u;
-
- ret = 1;
-
-err:
- EVP_MD_CTX_cleanup(&ctx);
- return ret;
+ SHA256_Update(&ctx, handshake_hash, (size_t)handshake_hash_len);
+ SHA256_Final(out, &ctx);
+ *out_len = SHA256_DIGEST_LENGTH;
+ return 1;
}
/* tls1_record_handshake_hashes_for_channel_id records the current handshake
@@ -3272,3 +3452,44 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) {
return 1;
}
+
+int ssl_do_channel_id_callback(SSL *ssl) {
+ if (ssl->tlsext_channel_id_private != NULL ||
+ ssl->ctx->channel_id_cb == NULL) {
+ return 1;
+ }
+
+ EVP_PKEY *key = NULL;
+ ssl->ctx->channel_id_cb(ssl, &key);
+ if (key == NULL) {
+ /* The caller should try again later. */
+ return 1;
+ }
+
+ int ret = SSL_set1_tls_channel_id(ssl, key);
+ EVP_PKEY_free(key);
+ return ret;
+}
+
+int ssl_is_sct_list_valid(const CBS *contents) {
+ /* Shallow parse the SCT list for sanity. By the RFC
+ * (https://tools.ietf.org/html/rfc6962#section-3.3) neither the list nor any
+ * of the SCTs may be empty. */
+ CBS copy = *contents;
+ CBS sct_list;
+ if (!CBS_get_u16_length_prefixed(&copy, &sct_list) ||
+ CBS_len(&copy) != 0 ||
+ CBS_len(&sct_list) == 0) {
+ return 0;
+ }
+
+ while (CBS_len(&sct_list) > 0) {
+ CBS sct;
+ if (!CBS_get_u16_length_prefixed(&sct_list, &sct) ||
+ CBS_len(&sct) == 0) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc
index 76caa4e6..97860c41 100644
--- a/src/ssl/test/bssl_shim.cc
+++ b/src/ssl/test/bssl_shim.cc
@@ -40,6 +40,7 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib"))
#include <inttypes.h>
#include <string.h>
+#include <openssl/aead.h>
#include <openssl/bio.h>
#include <openssl/buf.h>
#include <openssl/bytestring.h>
@@ -137,12 +138,46 @@ static TestState *GetTestState(const SSL *ssl) {
return (TestState *)SSL_get_ex_data(ssl, g_state_index);
}
-static bssl::UniquePtr<X509> LoadCertificate(const std::string &file) {
+static bool LoadCertificate(bssl::UniquePtr<X509> *out_x509,
+ bssl::UniquePtr<STACK_OF(X509)> *out_chain,
+ const std::string &file) {
bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_file()));
if (!bio || !BIO_read_filename(bio.get(), file.c_str())) {
- return nullptr;
+ return false;
+ }
+
+ out_x509->reset(PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ if (!*out_x509) {
+ return false;
+ }
+
+ out_chain->reset(sk_X509_new_null());
+ if (!*out_chain) {
+ return false;
+ }
+
+ // Keep reading the certificate chain.
+ for (;;) {
+ bssl::UniquePtr<X509> cert(
+ PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr));
+ if (!cert) {
+ break;
+ }
+
+ if (!sk_X509_push(out_chain->get(), cert.get())) {
+ return false;
+ }
+ cert.release(); // sk_X509_push takes ownership.
}
- return bssl::UniquePtr<X509>(PEM_read_bio_X509(bio.get(), NULL, NULL, NULL));
+
+ uint32_t err = ERR_peek_last_error();
+ if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
+ ERR_GET_REASON(err) != PEM_R_NO_START_LINE) {
+ return false;
+}
+
+ ERR_clear_error();
+ return true;
}
static bssl::UniquePtr<EVP_PKEY> LoadPrivateKey(const std::string &file) {
@@ -320,6 +355,7 @@ struct Free {
};
static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
+ bssl::UniquePtr<STACK_OF(X509)> *out_chain,
bssl::UniquePtr<EVP_PKEY> *out_pkey) {
const TestConfig *config = GetTestConfig(ssl);
@@ -358,14 +394,12 @@ static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
return false;
}
}
- if (!config->cert_file.empty()) {
- *out_x509 = LoadCertificate(config->cert_file.c_str());
- if (!*out_x509) {
- return false;
- }
+ if (!config->cert_file.empty() &&
+ !LoadCertificate(out_x509, out_chain, config->cert_file.c_str())) {
+ return false;
}
if (!config->ocsp_response.empty() &&
- !SSL_CTX_set_ocsp_response(ssl->ctx,
+ !SSL_CTX_set_ocsp_response(SSL_get_SSL_CTX(ssl),
(const uint8_t *)config->ocsp_response.data(),
config->ocsp_response.size())) {
return false;
@@ -375,8 +409,9 @@ static bool GetCertificate(SSL *ssl, bssl::UniquePtr<X509> *out_x509,
static bool InstallCertificate(SSL *ssl) {
bssl::UniquePtr<X509> x509;
+ bssl::UniquePtr<STACK_OF(X509)> chain;
bssl::UniquePtr<EVP_PKEY> pkey;
- if (!GetCertificate(ssl, &x509, &pkey)) {
+ if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
return false;
}
@@ -395,6 +430,11 @@ static bool InstallCertificate(SSL *ssl) {
return false;
}
+ if (sk_X509_num(chain.get()) > 0 &&
+ !SSL_set1_chain(ssl, chain.get())) {
+ return false;
+ }
+
return true;
}
@@ -456,8 +496,9 @@ static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
}
bssl::UniquePtr<X509> x509;
+ bssl::UniquePtr<STACK_OF(X509)> chain;
bssl::UniquePtr<EVP_PKEY> pkey;
- if (!GetCertificate(ssl, &x509, &pkey)) {
+ if (!GetCertificate(ssl, &x509, &chain, &pkey)) {
return -1;
}
@@ -466,7 +507,7 @@ static int ClientCertCallback(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) {
return 0;
}
- // Asynchronous private keys are not supported with client_cert_cb.
+ // Chains and asynchronous private keys are not supported with client_cert_cb.
*out_x509 = x509.release();
*out_pkey = pkey.release();
return 1;
@@ -594,8 +635,10 @@ static unsigned PskServerCallback(SSL *ssl, const char *identity,
return config->psk.size();
}
+static timeval g_clock;
+
static void CurrentTimeCallback(const SSL *ssl, timeval *out_clock) {
- *out_clock = PacketedBioGetClock(GetTestState(ssl)->packeted_bio);
+ *out_clock = g_clock;
}
static void ChannelIdCallback(SSL *ssl, EVP_PKEY **out_pkey) {
@@ -622,6 +665,10 @@ static int CertCallback(SSL *ssl, void *arg) {
}
}
+ if (config->fail_cert_callback) {
+ return 0;
+ }
+
// The certificate will be installed via other means.
if (!config->async || config->use_early_callback ||
config->use_old_client_cert_callback) {
@@ -774,6 +821,20 @@ static int CustomExtensionParseCallback(SSL *ssl, unsigned extension_value,
return 1;
}
+static int ServerNameCallback(SSL *ssl, int *out_alert, void *arg) {
+ // SNI must be accessible from the SNI callback.
+ const TestConfig *config = GetTestConfig(ssl);
+ const char *server_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (server_name == nullptr ||
+ std::string(server_name) != config->expected_server_name) {
+ fprintf(stderr, "servername mismatch (got %s; want %s)\n", server_name,
+ config->expected_server_name.c_str());
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+
+ return SSL_TLSEXT_ERR_OK;
+}
+
// Connect returns a new socket connected to localhost on |port| or -1 on
// error.
static int Connect(uint16_t port) {
@@ -923,9 +984,7 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
SSL_CTX_enable_tls_channel_id(ssl_ctx.get());
SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback);
- if (config->is_dtls) {
- SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
- }
+ SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback);
SSL_CTX_set_info_callback(ssl_ctx.get(), InfoCallback);
SSL_CTX_sess_set_new_cb(ssl_ctx.get(), NewSessionCallback);
@@ -971,6 +1030,16 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) {
SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1);
}
+ if (!config->expected_server_name.empty()) {
+ SSL_CTX_set_tlsext_servername_callback(ssl_ctx.get(), ServerNameCallback);
+ }
+
+ if (!config->ticket_key.empty() &&
+ !SSL_CTX_set_tlsext_ticket_keys(ssl_ctx.get(), config->ticket_key.data(),
+ config->ticket_key.size())) {
+ return nullptr;
+ }
+
return ssl_ctx;
}
@@ -1054,6 +1123,16 @@ static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) {
if (config->async) {
AsyncBioEnforceWriteQuota(test_state->async_bio, true);
}
+
+ // Run the exporter after each read. This is to test that the exporter fails
+ // during a renegotiation.
+ if (config->use_exporter_between_reads) {
+ uint8_t buf;
+ if (!SSL_export_keying_material(ssl, &buf, 1, NULL, 0, NULL, 0, 0)) {
+ fprintf(stderr, "failed to export keying material\n");
+ return -1;
+ }
+ }
} while (config->async && RetryAsync(ssl, ret));
if (config->peek_then_read && ret > 0) {
@@ -1171,7 +1250,8 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
if (!config->expected_server_name.empty()) {
const char *server_name =
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
- if (server_name != config->expected_server_name) {
+ if (server_name == nullptr ||
+ server_name != config->expected_server_name) {
fprintf(stderr, "servername mismatch (got %s; want %s)\n",
server_name, config->expected_server_name.c_str());
return false;
@@ -1285,6 +1365,25 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
}
}
+ uint16_t cipher_id =
+ static_cast<uint16_t>(SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)));
+ if (config->expect_cipher_aes != 0 &&
+ EVP_has_aes_hardware() &&
+ static_cast<uint16_t>(config->expect_cipher_aes) != cipher_id) {
+ fprintf(stderr, "Cipher ID was %04x, wanted %04x (has AES hardware)\n",
+ cipher_id, static_cast<uint16_t>(config->expect_cipher_aes));
+ return false;
+ }
+
+ if (config->expect_cipher_no_aes != 0 &&
+ !EVP_has_aes_hardware() &&
+ static_cast<uint16_t>(config->expect_cipher_no_aes) != cipher_id) {
+ fprintf(stderr, "Cipher ID was %04x, wanted %04x (no AES hardware)\n",
+ cipher_id, static_cast<uint16_t>(config->expect_cipher_no_aes));
+ return false;
+ }
+
+
if (!config->psk.empty()) {
if (SSL_get_peer_cert_chain(ssl) != nullptr) {
fprintf(stderr, "Received peer certificate on a PSK cipher.\n");
@@ -1297,6 +1396,65 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) {
}
}
+ if (!config->expect_peer_cert_file.empty()) {
+ bssl::UniquePtr<X509> expect_leaf;
+ bssl::UniquePtr<STACK_OF(X509)> expect_chain;
+ if (!LoadCertificate(&expect_leaf, &expect_chain,
+ config->expect_peer_cert_file)) {
+ return false;
+ }
+
+ // For historical reasons, clients report a chain with a leaf and servers
+ // without.
+ if (!config->is_server) {
+ if (!sk_X509_insert(expect_chain.get(), expect_leaf.get(), 0)) {
+ return false;
+ }
+ X509_up_ref(expect_leaf.get()); // sk_X509_push takes ownership.
+ }
+
+ bssl::UniquePtr<X509> leaf(SSL_get_peer_certificate(ssl));
+ STACK_OF(X509) *chain = SSL_get_peer_cert_chain(ssl);
+ if (X509_cmp(leaf.get(), expect_leaf.get()) != 0) {
+ fprintf(stderr, "Received a different leaf certificate than expected.\n");
+ return false;
+ }
+
+ if (sk_X509_num(chain) != sk_X509_num(expect_chain.get())) {
+ fprintf(stderr, "Received a chain of length %zu instead of %zu.\n",
+ sk_X509_num(chain), sk_X509_num(expect_chain.get()));
+ return false;
+ }
+
+ for (size_t i = 0; i < sk_X509_num(chain); i++) {
+ if (X509_cmp(sk_X509_value(chain, i),
+ sk_X509_value(expect_chain.get(), i)) != 0) {
+ fprintf(stderr, "Chain certificate %zu did not match.\n",
+ i + 1);
+ return false;
+ }
+ }
+ }
+
+ bool expected_sha256_client_cert = config->expect_sha256_client_cert_initial;
+ if (is_resume) {
+ expected_sha256_client_cert = config->expect_sha256_client_cert_resume;
+ }
+
+ if (SSL_get_session(ssl)->peer_sha256_valid != expected_sha256_client_cert) {
+ fprintf(stderr,
+ "Unexpected SHA-256 client cert state: expected:%d is_resume:%d.\n",
+ expected_sha256_client_cert, is_resume);
+ return false;
+ }
+
+ if (expected_sha256_client_cert &&
+ SSL_get_session(ssl)->x509_peer != nullptr) {
+ fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n",
+ is_resume);
+ return false;
+ }
+
return true;
}
@@ -1456,6 +1614,12 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
if (config->max_cert_list > 0) {
SSL_set_max_cert_list(ssl.get(), config->max_cert_list);
}
+ if (!is_resume && config->retain_only_sha256_client_cert_initial) {
+ SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+ }
+ if (is_resume && config->retain_only_sha256_client_cert_resume) {
+ SSL_set_retain_only_sha256_of_client_certs(ssl.get(), 1);
+ }
int sock = Connect(config->port);
if (sock == -1) {
@@ -1468,7 +1632,7 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session,
return false;
}
if (config->is_dtls) {
- bssl::UniquePtr<BIO> packeted = PacketedBioCreate(!config->async);
+ bssl::UniquePtr<BIO> packeted = PacketedBioCreate(&g_clock, !config->async);
if (!packeted) {
return false;
}
@@ -1743,6 +1907,11 @@ static int Main(int argc, char **argv) {
return Usage(argv[0]);
}
+ // Some code treats the zero time special, so initialize the clock to a
+ // non-zero time.
+ g_clock.tv_sec = 1234;
+ g_clock.tv_usec = 1234;
+
bssl::UniquePtr<SSL_CTX> ssl_ctx = SetupCtx(&config);
if (!ssl_ctx) {
ERR_print_errors_fp(stderr);
@@ -1764,6 +1933,10 @@ static int Main(int argc, char **argv) {
ERR_print_errors_fp(stderr);
return 1;
}
+
+ if (config.resumption_delay != 0) {
+ g_clock.tv_sec += config.resumption_delay;
+ }
}
return 0;
diff --git a/src/ssl/test/packeted_bio.cc b/src/ssl/test/packeted_bio.cc
index f7267fc6..8331b4b6 100644
--- a/src/ssl/test/packeted_bio.cc
+++ b/src/ssl/test/packeted_bio.cc
@@ -31,10 +31,9 @@ const uint8_t kOpcodeTimeout = 'T';
const uint8_t kOpcodeTimeoutAck = 't';
struct PacketedBio {
- explicit PacketedBio(bool advance_clock_arg)
- : advance_clock(advance_clock_arg) {
+ PacketedBio(timeval *clock_arg, bool advance_clock_arg)
+ : clock(clock_arg), advance_clock(advance_clock_arg) {
memset(&timeout, 0, sizeof(timeout));
- memset(&clock, 0, sizeof(clock));
memset(&read_deadline, 0, sizeof(read_deadline));
}
@@ -47,14 +46,14 @@ struct PacketedBio {
return true;
}
- if (clock.tv_sec == read_deadline.tv_sec) {
- return clock.tv_usec < read_deadline.tv_usec;
+ if (clock->tv_sec == read_deadline.tv_sec) {
+ return clock->tv_usec < read_deadline.tv_usec;
}
- return clock.tv_sec < read_deadline.tv_sec;
+ return clock->tv_sec < read_deadline.tv_sec;
}
timeval timeout;
- timeval clock;
+ timeval *clock;
timeval read_deadline;
bool advance_clock;
};
@@ -66,10 +65,6 @@ PacketedBio *GetData(BIO *bio) {
return (PacketedBio *)bio->ptr;
}
-const PacketedBio *GetData(const BIO *bio) {
- return GetData(const_cast<BIO*>(bio));
-}
-
// ReadAll reads |len| bytes from |bio| into |out|. It returns 1 on success and
// 0 or -1 on error.
static int ReadAll(BIO *bio, uint8_t *out, size_t len) {
@@ -272,19 +267,15 @@ const BIO_METHOD g_packeted_bio_method = {
} // namespace
-bssl::UniquePtr<BIO> PacketedBioCreate(bool advance_clock) {
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock) {
bssl::UniquePtr<BIO> bio(BIO_new(&g_packeted_bio_method));
if (!bio) {
return nullptr;
}
- bio->ptr = new PacketedBio(advance_clock);
+ bio->ptr = new PacketedBio(clock, advance_clock);
return bio;
}
-timeval PacketedBioGetClock(const BIO *bio) {
- return GetData(bio)->clock;
-}
-
bool PacketedBioAdvanceClock(BIO *bio) {
PacketedBio *data = GetData(bio);
if (data == nullptr) {
@@ -295,10 +286,10 @@ bool PacketedBioAdvanceClock(BIO *bio) {
return false;
}
- data->clock.tv_usec += data->timeout.tv_usec;
- data->clock.tv_sec += data->clock.tv_usec / 1000000;
- data->clock.tv_usec %= 1000000;
- data->clock.tv_sec += data->timeout.tv_sec;
+ data->clock->tv_usec += data->timeout.tv_usec;
+ data->clock->tv_sec += data->clock->tv_usec / 1000000;
+ data->clock->tv_usec %= 1000000;
+ data->clock->tv_sec += data->timeout.tv_sec;
memset(&data->timeout, 0, sizeof(data->timeout));
return true;
}
diff --git a/src/ssl/test/packeted_bio.h b/src/ssl/test/packeted_bio.h
index 07930d47..9d4cdcbb 100644
--- a/src/ssl/test/packeted_bio.h
+++ b/src/ssl/test/packeted_bio.h
@@ -28,21 +28,18 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
// PacketedBioCreate creates a filter BIO which implements a reliable in-order
-// blocking datagram socket. It internally maintains a clock and honors
-// |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
+// blocking datagram socket. It uses the value of |*clock| as the clock and
+// honors |BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT| based on it.
//
// During a |BIO_read|, the peer may signal the filter BIO to simulate a
// timeout. If |advance_clock| is true, it automatically advances the clock and
// continues reading, subject to the read deadline. Otherwise, it fails
// immediately. The caller must then call |PacketedBioAdvanceClock| before
// retrying |BIO_read|.
-bssl::UniquePtr<BIO> PacketedBioCreate(bool advance_clock);
+bssl::UniquePtr<BIO> PacketedBioCreate(timeval *clock, bool advance_clock);
-// PacketedBioGetClock returns the current time for |bio|.
-timeval PacketedBioGetClock(const BIO *bio);
-
-// PacketedBioAdvanceClock advances |bio|'s internal clock and returns true if
-// there is a pending timeout. Otherwise, it returns false.
+// PacketedBioAdvanceClock advances |bio|'s clock and returns true if there is a
+// pending timeout. Otherwise, it returns false.
bool PacketedBioAdvanceClock(BIO *bio);
diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go
index 656a3d0d..a9970169 100644
--- a/src/ssl/test/runner/cipher_suites.go
+++ b/src/ssl/test/runner/cipher_suites.go
@@ -480,12 +480,16 @@ func ecdhePSKKA(version uint16) keyAgreement {
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
for _, id := range have {
if id == want {
- for _, suite := range cipherSuites {
- if suite.id == want {
- return suite
- }
- }
- return nil
+ return cipherSuiteFromID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteFromID(id uint16) *cipherSuite {
+ for _, suite := range cipherSuites {
+ if suite.id == id {
+ return suite
}
}
return nil
diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go
index 62c8dd36..a6496fdd 100644
--- a/src/ssl/test/runner/common.go
+++ b/src/ssl/test/runner/common.go
@@ -27,7 +27,7 @@ const (
)
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
-const tls13DraftVersion = 0x7f10
+const tls13DraftVersion = 0x7f12
const (
maxPlaintext = 16384 // maximum plaintext payload length
@@ -94,6 +94,7 @@ const (
extensionEarlyData uint16 = 42 // draft-ietf-tls-tls13-16
extensionSupportedVersions uint16 = 43 // draft-ietf-tls-tls13-16
extensionCookie uint16 = 44 // draft-ietf-tls-tls13-16
+ extensionPSKKeyExchangeModes uint16 = 45 // draft-ietf-tls-tls13-18
extensionCustom uint16 = 1234 // not IANA assigned
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
extensionRenegotiationInfo uint16 = 0xff01
@@ -200,12 +201,6 @@ const (
pskDHEKEMode = 1
)
-// PskAuthenticationMode values (see draft-ietf-tls-tls13-16)
-const (
- pskAuthMode = 0
- pskSignAuthMode = 1
-)
-
// KeyUpdateRequest values (see draft-ietf-tls-tls13-16, section 4.5.3)
const (
keyUpdateNotRequested = 0
@@ -259,6 +254,7 @@ type ClientSessionState struct {
ocspResponse []byte
ticketCreationTime time.Time
ticketExpiration time.Time
+ ticketAgeAdd uint32
}
// ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -661,9 +657,9 @@ type ProtocolBugs struct {
// TLS 1.2 and 1.3 extensions.
SendBothTickets bool
- // CorruptTicket causes a client to corrupt a session ticket before
- // sending it in a resume handshake.
- CorruptTicket bool
+ // FilterTicket, if not nil, causes the client to modify a session
+ // ticket before sending it in a resume handshake.
+ FilterTicket func([]byte) ([]byte, error)
// OversizedSessionId causes the session id that is sent with a ticket
// resumption attempt to be too large (33 bytes).
@@ -753,9 +749,17 @@ type ProtocolBugs struct {
RequireSameRenegoClientVersion bool
// ExpectInitialRecordVersion, if non-zero, is the expected value of
- // record-layer version field before the version is determined.
+ // record-layer version field before the protocol version is determined.
ExpectInitialRecordVersion uint16
+ // SendRecordVersion, if non-zero, is the value to send as the
+ // record-layer version.
+ SendRecordVersion uint16
+
+ // SendInitialRecordVersion, if non-zero, is the value to send as the
+ // record-layer version before the protocol version is determined.
+ SendInitialRecordVersion uint16
+
// MaxPacketLength, if non-zero, is the maximum acceptable size for a
// packet.
MaxPacketLength int
@@ -765,6 +769,11 @@ type ProtocolBugs struct {
// the server believes it has actually negotiated.
SendCipherSuite uint16
+ // SendCipherSuites, if not nil, is the cipher suite list that the
+ // client will send in the ClientHello. This does not affect the cipher
+ // the client believes it has actually offered.
+ SendCipherSuites []uint16
+
// AppDataBeforeHandshake, if not nil, causes application data to be
// sent immediately before the first handshake message.
AppDataBeforeHandshake []byte
@@ -939,12 +948,17 @@ type ProtocolBugs struct {
// session ticket.
SendEmptySessionTicket bool
- // SnedPSKKeyExchangeModes, if present, determines the PSK key exchange modes
+ // SendPSKKeyExchangeModes, if present, determines the PSK key exchange modes
// to send.
SendPSKKeyExchangeModes []byte
- // SendPSKAuthModes, if present, determines the PSK auth modes to send.
- SendPSKAuthModes []byte
+ // ExpectNoNewSessionTicket, if present, means that the client will fail upon
+ // receipt of a NewSessionTicket message.
+ ExpectNoNewSessionTicket bool
+
+ // ExpectTicketAge, if non-zero, is the expected age of the ticket that the
+ // server receives from the client.
+ ExpectTicketAge time.Duration
// FailIfSessionOffered, if true, causes the server to fail any
// connections where the client offers a non-empty session ID or session
@@ -991,6 +1005,26 @@ type ProtocolBugs struct {
// supplied stapled response.
SendOCSPResponseOnResume []byte
+ // SendExtensionOnCertificate, if not nil, causes the runner to send the
+ // supplied bytes in the extensions on the Certificate message.
+ SendExtensionOnCertificate []byte
+
+ // SendOCSPOnIntermediates, if not nil, causes the server to send the
+ // supplied OCSP on intermediate certificates in the Certificate message.
+ SendOCSPOnIntermediates []byte
+
+ // SendSCTOnIntermediates, if not nil, causes the server to send the
+ // supplied SCT on intermediate certificates in the Certificate message.
+ SendSCTOnIntermediates []byte
+
+ // SendDuplicateCertExtensions, if true, causes the server to send an extra
+ // copy of the OCSP/SCT extensions in the Certificate message.
+ SendDuplicateCertExtensions bool
+
+ // ExpectNoExtensionsOnIntermediate, if true, causes the client to
+ // reject extensions on intermediate certificates.
+ ExpectNoExtensionsOnIntermediate bool
+
// CECPQ1BadX25519Part corrupts the X25519 part of a CECPQ1 key exchange, as
// a trivial proof that it is actually used.
CECPQ1BadX25519Part bool
@@ -1028,10 +1062,6 @@ type ProtocolBugs struct {
// Renegotiation Info to be negotiated at all versions.
NegotiateRenegotiationInfoAtAllVersions bool
- // NegotiateChannelIDAtAllVersions, if true, causes Channel ID to be
- // negotiated at all versions.
- NegotiateChannelIDAtAllVersions bool
-
// NegotiateNPNAtAllVersions, if true, causes NPN to be negotiated at
// all versions.
NegotiateNPNAtAllVersions bool
@@ -1056,13 +1086,9 @@ type ProtocolBugs struct {
// the specified PSK identity index rather than the actual value.
SelectPSKIdentityOnResume uint16
- // OmitServerHelloSignatureAlgorithms, if true, causes the server to omit the
- // signature_algorithms extension in the ServerHello.
- OmitServerHelloSignatureAlgorithms bool
-
- // IncludeServerHelloSignatureAlgorithms, if true, causes the server to
- // include the signature_algorithms extension in all ServerHellos.
- IncludeServerHelloSignatureAlgorithms bool
+ // ExtraPSKIdentity, if true, causes the client to send an extra PSK
+ // identity.
+ ExtraPSKIdentity bool
// MissingKeyShare, if true, causes the TLS 1.3 implementation to skip
// sending a key_share extension and use the zero ECDHE secret
@@ -1160,6 +1186,29 @@ type ProtocolBugs struct {
// ExpectGREASE, if true, causes messages without GREASE values to be
// rejected. See draft-davidben-tls-grease-01.
ExpectGREASE bool
+
+ // SendShortPSKBinder, if true, causes the client to send a PSK binder
+ // that is one byte shorter than it should be.
+ SendShortPSKBinder bool
+
+ // SendInvalidPSKBinder, if true, causes the client to send an invalid
+ // PSK binder.
+ SendInvalidPSKBinder bool
+
+ // SendNoPSKBinder, if true, causes the client to send no PSK binders.
+ SendNoPSKBinder bool
+
+ // PSKBinderFirst, if true, causes the client to send the PSK Binder
+ // extension as the first extension instead of the last extension.
+ PSKBinderFirst bool
+
+ // NoOCSPStapling, if true, causes the client to not request OCSP
+ // stapling.
+ NoOCSPStapling bool
+
+ // NoSignedCertificateTimestamps, if true, causes the client to not
+ // request signed certificate timestamps.
+ NoSignedCertificateTimestamps bool
}
func (c *Config) serverInit() {
diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go
index f5014d44..39c27850 100644
--- a/src/ssl/test/runner/conn.go
+++ b/src/ssl/test/runner/conn.go
@@ -208,9 +208,9 @@ func (hc *halfConn) changeCipherSpec(config *Config) error {
}
// useTrafficSecret sets the current cipher state for TLS 1.3.
-func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) {
+func (hc *halfConn) useTrafficSecret(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) {
hc.version = version
- hc.cipher = deriveTrafficAEAD(version, suite, secret, phase, side)
+ hc.cipher = deriveTrafficAEAD(version, suite, secret, side)
if hc.config.Bugs.NullAllCiphers {
hc.cipher = nullCipher{}
}
@@ -223,7 +223,7 @@ func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) {
if c.isClient == isOutgoing {
side = clientWrite
}
- hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), applicationPhase, side)
+ hc.useTrafficSecret(hc.version, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side)
}
// incSeq increments the sequence number.
@@ -753,16 +753,18 @@ func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) {
// record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer
// version is irrelevant.)
if typ != recordTypeAlert {
+ var expect uint16
if c.haveVers {
- if vers != c.vers && c.vers < VersionTLS13 {
- c.sendAlert(alertProtocolVersion)
- return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, c.vers))
+ expect = c.vers
+ if c.vers >= VersionTLS13 {
+ expect = VersionTLS10
}
} else {
- if expect := c.config.Bugs.ExpectInitialRecordVersion; expect != 0 && vers != expect {
- c.sendAlert(alertProtocolVersion)
- return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, expect))
- }
+ expect = c.config.Bugs.ExpectInitialRecordVersion
+ }
+ if expect != 0 && vers != expect {
+ c.sendAlert(alertProtocolVersion)
+ return 0, nil, c.in.setErrorLocked(fmt.Errorf("tls: received record with version %x when expecting version %x", vers, expect))
}
}
if n > maxCiphertext {
@@ -1063,6 +1065,12 @@ func (c *Conn) doWriteRecord(typ recordType, data []byte) (n int, err error) {
// layer to {3, 1}.
vers = VersionTLS10
}
+ if c.config.Bugs.SendRecordVersion != 0 {
+ vers = c.config.Bugs.SendRecordVersion
+ }
+ if c.vers == 0 && c.config.Bugs.SendInitialRecordVersion != 0 {
+ vers = c.config.Bugs.SendInitialRecordVersion
+ }
b.data[1] = byte(vers >> 8)
b.data[2] = byte(vers)
b.data[3] = byte(m >> 8)
@@ -1396,24 +1404,11 @@ func (c *Conn) handlePostHandshakeMessage() error {
return errors.New("tls: no GREASE ticket extension found")
}
- if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
- return nil
+ if c.config.Bugs.ExpectNoNewSessionTicket {
+ return errors.New("tls: received unexpected NewSessionTicket")
}
- var foundKE, foundAuth bool
- for _, mode := range newSessionTicket.keModes {
- if mode == pskDHEKEMode {
- foundKE = true
- }
- }
- for _, mode := range newSessionTicket.authModes {
- if mode == pskAuthMode {
- foundAuth = true
- }
- }
-
- // Ignore the ticket if the server preferences do not match a mode we implement.
- if !foundKE || !foundAuth {
+ if c.config.ClientSessionCache == nil || newSessionTicket.ticketLifetime == 0 {
return nil
}
@@ -1427,6 +1422,7 @@ func (c *Conn) handlePostHandshakeMessage() error {
ocspResponse: c.ocspResponse,
ticketCreationTime: c.config.time(),
ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second),
+ ticketAgeAdd: newSessionTicket.ticketAgeAdd,
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
@@ -1709,20 +1705,20 @@ func (c *Conn) SendNewSessionTicket() error {
peerCertificatesRaw = append(peerCertificatesRaw, cert.Raw)
}
+ addBuffer := make([]byte, 4)
+ _, err := io.ReadFull(c.config.rand(), addBuffer)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: short read from Rand: " + err.Error())
+ }
+ ticketAgeAdd := uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0])
+
// TODO(davidben): Allow configuring these values.
m := &newSessionTicketMsg{
version: c.vers,
ticketLifetime: uint32(24 * time.Hour / time.Second),
- keModes: []byte{pskDHEKEMode},
- authModes: []byte{pskAuthMode},
customExtension: c.config.Bugs.CustomTicketExtension,
- }
-
- if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
- m.keModes = c.config.Bugs.SendPSKKeyExchangeModes
- }
- if len(c.config.Bugs.SendPSKAuthModes) != 0 {
- m.authModes = c.config.Bugs.SendPSKAuthModes
+ ticketAgeAdd: ticketAgeAdd,
}
state := sessionState{
@@ -1732,6 +1728,7 @@ func (c *Conn) SendNewSessionTicket() error {
certificates: peerCertificatesRaw,
ticketCreationTime: c.config.time(),
ticketExpiration: c.config.time().Add(time.Duration(m.ticketLifetime) * time.Second),
+ ticketAgeAdd: uint32(addBuffer[3])<<24 | uint32(addBuffer[2])<<16 | uint32(addBuffer[1])<<8 | uint32(addBuffer[0]),
}
if !c.config.Bugs.SendEmptySessionTicket {
@@ -1744,7 +1741,7 @@ func (c *Conn) SendNewSessionTicket() error {
c.out.Lock()
defer c.out.Unlock()
- _, err := c.writeRecord(recordTypeHandshake, m.marshal())
+ _, err = c.writeRecord(recordTypeHandshake, m.marshal())
return err
}
diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json
index 8fc1a563..24f3bd66 100644
--- a/src/ssl/test/runner/fuzzer_mode.json
+++ b/src/ssl/test/runner/fuzzer_mode.json
@@ -1,14 +1,14 @@
{
"DisabledTests": {
"BadCBCPadding*": "Fuzzer mode has no CBC padding.",
- "BadECDSA-*": "Fuzzer mode ignores invalid signatures.",
- "*-InvalidSignature-*": "Fuzzer mode ignores invalid signatures.",
+
"BadFinished-*": "Fuzzer mode ignores Finished checks.",
"FalseStart-BadFinished": "Fuzzer mode ignores Finished checks.",
"TrailingMessageData-*Finished*": "Fuzzer mode ignores Finished checks.",
"DTLSIgnoreBadPackets*": "Fuzzer mode has no bad packets.",
"TLSFatalBadPackets": "Fuzzer mode has no bad packets.",
+ "*-BadRecord": "Fuzzer mode has no bad packets.",
"BadRSAClientKeyExchange*": "Fuzzer mode does not notice a bad premaster secret.",
"CECPQ1-*-BadNewhopePart": "Fuzzer mode does not notice a bad premaster secret.",
@@ -19,10 +19,20 @@
"UnknownUnencryptedExtension-Client-TLS13": "Fuzzer mode will not read the peer's alert as a MAC error",
"WrongMessageType-TLS13-ServerHello": "Fuzzer mode will not read the peer's alert as a MAC error",
+ "BadECDSA-*": "Fuzzer mode always accepts a signature.",
+ "*-InvalidSignature-*": "Fuzzer mode always accepts a signature.",
"*Auth-Verify-RSA-PKCS1-*-TLS13": "Fuzzer mode always accepts a signature.",
"*Auth-Verify-ECDSA-SHA1-TLS13": "Fuzzer mode always accepts a signature.",
"Verify-*Auth-SignatureType*": "Fuzzer mode always accepts a signature.",
"ECDSACurveMismatch-Verify-TLS13": "Fuzzer mode always accepts a signature.",
- "InvalidChannelIDSignature": "Fuzzer mode always accepts a signature."
+ "InvalidChannelIDSignature-*": "Fuzzer mode always accepts a signature.",
+
+ "Resume-Server-DeclineBadCipher*": "Fuzzer mode does not encrypt tickets.",
+ "Resume-Server-DeclineCrossVersion*": "Fuzzer mode does not encrypt tickets.",
+ "TicketCallback-SingleCall-*": "Fuzzer mode does not encrypt tickets.",
+ "CorruptTicket-*": "Fuzzer mode does not encrypt tickets.",
+ "ShimTicketRewritable": "Fuzzer mode does not encrypt tickets.",
+
+ "Resume-Server-*Binder*": "Fuzzer mode does not check binders."
}
}
diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go
index ae3228aa..d074778c 100644
--- a/src/ssl/test/runner/handshake_client.go
+++ b/src/ssl/test/runner/handshake_client.go
@@ -64,21 +64,23 @@ func (c *Conn) clientHandshake() error {
vers: versionToWire(maxVersion, c.isDTLS),
compressionMethods: []uint8{compressionNone},
random: make([]byte, 32),
- ocspStapling: true,
- sctListSupported: true,
+ ocspStapling: !c.config.Bugs.NoOCSPStapling,
+ sctListSupported: !c.config.Bugs.NoSignedCertificateTimestamps,
serverName: c.config.ServerName,
supportedCurves: c.config.curvePreferences(),
+ pskKEModes: []byte{pskDHEKEMode},
supportedPoints: []uint8{pointFormatUncompressed},
nextProtoNeg: len(c.config.NextProtos) > 0,
secureRenegotiation: []byte{},
alpnProtocols: c.config.NextProtos,
duplicateExtension: c.config.Bugs.DuplicateExtension,
channelIDSupported: c.config.ChannelID != nil,
- npnLast: c.config.Bugs.SwapNPNAndALPN,
+ npnAfterAlpn: c.config.Bugs.SwapNPNAndALPN,
extendedMasterSecret: maxVersion >= VersionTLS10,
srtpProtectionProfiles: c.config.SRTPProtectionProfiles,
srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer,
customExtension: c.config.Bugs.CustomExtension,
+ pskBinderFirst: c.config.Bugs.PSKBinderFirst,
}
disableEMS := c.config.Bugs.NoExtendedMasterSecret
@@ -94,6 +96,10 @@ func (c *Conn) clientHandshake() error {
hello.supportedCurves = nil
}
+ if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
+ hello.pskKEModes = c.config.Bugs.SendPSKKeyExchangeModes
+ }
+
if c.config.Bugs.SendCompressionMethods != nil {
hello.compressionMethods = c.config.Bugs.SendCompressionMethods
}
@@ -217,11 +223,17 @@ NextCipherSuite:
// Check that the ciphersuite/version used for the
// previous session are still valid.
cipherSuiteOk := false
- for _, id := range hello.cipherSuites {
- if id == candidateSession.cipherSuite {
- cipherSuiteOk = true
- break
+ if candidateSession.vers <= VersionTLS12 {
+ for _, id := range hello.cipherSuites {
+ if id == candidateSession.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
}
+ } else {
+ // TLS 1.3 allows the cipher to change on
+ // resumption.
+ cipherSuiteOk = true
}
versOk := candidateSession.vers >= minVersion &&
@@ -232,34 +244,37 @@ NextCipherSuite:
}
}
+ var pskCipherSuite *cipherSuite
if session != nil && c.config.time().Before(session.ticketExpiration) {
ticket := session.sessionTicket
- if c.config.Bugs.CorruptTicket && len(ticket) > 0 {
+ if c.config.Bugs.FilterTicket != nil && len(ticket) > 0 {
+ // Copy the ticket so FilterTicket may act in-place.
ticket = make([]byte, len(session.sessionTicket))
copy(ticket, session.sessionTicket)
- offset := 40
- if offset >= len(ticket) {
- offset = len(ticket) - 1
+
+ ticket, err = c.config.Bugs.FilterTicket(ticket)
+ if err != nil {
+ return err
}
- ticket[offset] ^= 0x40
}
if session.vers >= VersionTLS13 || c.config.Bugs.SendBothTickets {
+ pskCipherSuite = cipherSuiteFromID(session.cipherSuite)
+ if pskCipherSuite == nil {
+ return errors.New("tls: client session cache has invalid cipher suite")
+ }
// TODO(nharper): Support sending more
// than one PSK identity.
+ ticketAge := uint32(c.config.time().Sub(session.ticketCreationTime) / time.Millisecond)
psk := pskIdentity{
- keModes: []byte{pskDHEKEMode},
- authModes: []byte{pskAuthMode},
- ticket: ticket,
- }
- if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
- psk.keModes = c.config.Bugs.SendPSKKeyExchangeModes
- }
- if len(c.config.Bugs.SendPSKAuthModes) != 0 {
- psk.authModes = c.config.Bugs.SendPSKAuthModes
+ ticket: ticket,
+ obfuscatedTicketAge: session.ticketAgeAdd + ticketAge,
}
-
hello.pskIdentities = []pskIdentity{psk}
+
+ if c.config.Bugs.ExtraPSKIdentity {
+ hello.pskIdentities = append(hello.pskIdentities, psk)
+ }
}
if session.vers < VersionTLS13 || c.config.Bugs.SendBothTickets {
@@ -300,6 +315,10 @@ NextCipherSuite:
hello.vers = c.config.Bugs.SendClientVersion
}
+ if c.config.Bugs.SendCipherSuites != nil {
+ hello.cipherSuites = c.config.Bugs.SendCipherSuites
+ }
+
var helloBytes []byte
if c.config.Bugs.SendV2ClientHello {
// Test that the peer left-pads random.
@@ -314,7 +333,11 @@ NextCipherSuite:
helloBytes = v2Hello.marshal()
c.writeV2Record(helloBytes)
} else {
+ if len(hello.pskIdentities) > 0 {
+ generatePSKBinders(hello, pskCipherSuite, session.masterSecret, []byte{}, c.config)
+ }
helloBytes = hello.marshal()
+
if c.config.Bugs.PartialClientFinishedWithClientHello {
// Include one byte of Finished. We can compute it
// without completing the handshake. This assumes we
@@ -341,7 +364,7 @@ NextCipherSuite:
if c.isDTLS {
helloVerifyRequest, ok := msg.(*helloVerifyRequestMsg)
if ok {
- if helloVerifyRequest.vers != VersionTLS10 {
+ if helloVerifyRequest.vers != versionToWire(VersionTLS10, c.isDTLS) {
// Per RFC 6347, the version field in
// HelloVerifyRequest SHOULD be always DTLS
// 1.0. Enforce this for testing purposes.
@@ -419,10 +442,10 @@ NextCipherSuite:
return err
}
keyShares[group] = curve
- hello.keyShares = append(hello.keyShares, keyShareEntry{
+ hello.keyShares = []keyShareEntry{{
group: group,
keyExchange: publicKey,
- })
+ }}
}
if c.config.Bugs.SecondClientHelloMissingKeyShare {
@@ -430,9 +453,11 @@ NextCipherSuite:
}
hello.hasEarlyData = false
- hello.earlyDataContext = nil
hello.raw = nil
+ if len(hello.pskIdentities) > 0 {
+ generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config)
+ }
secondHelloBytes = hello.marshal()
c.writeRecord(recordTypeHandshake, secondHelloBytes)
c.flushHandshake()
@@ -599,35 +624,29 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// 0-RTT is implemented.
var psk []byte
if hs.serverHello.hasPSKIdentity {
- if hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
- c.sendAlert(alertUnsupportedExtension)
- return errors.New("tls: server omitted KeyShare or included SignatureAlgorithms on resumption.")
- }
-
// We send at most one PSK identity.
if hs.session == nil || hs.serverHello.pskIdentity != 0 {
c.sendAlert(alertUnknownPSKIdentity)
return errors.New("tls: server sent unknown PSK identity")
}
- if hs.session.cipherSuite != hs.suite.id {
+ sessionCipher := cipherSuiteFromID(hs.session.cipherSuite)
+ if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
c.sendAlert(alertHandshakeFailure)
- return errors.New("tls: server sent invalid cipher suite")
+ return errors.New("tls: server resumed an invalid session for the cipher suite")
}
- psk = deriveResumptionPSK(hs.suite, hs.session.masterSecret)
- hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.session.masterSecret))
+ psk = hs.session.masterSecret
c.didResume = true
} else {
- if !hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare {
- c.sendAlert(alertUnsupportedExtension)
- return errors.New("tls: server omitted KeyShare and SignatureAlgorithms on non-resumption.")
- }
-
psk = zeroSecret
- hs.finishedHash.setResumptionContext(zeroSecret)
}
earlySecret := hs.finishedHash.extractKey(zeroSecret, psk)
+ if !hs.serverHello.hasKeyShare {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server omitted KeyShare on resumption.")
+ }
+
// Resolve ECDHE and compute the handshake secret.
var ecdheSecret []byte
if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare {
@@ -652,9 +671,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
// Switch to handshake traffic keys.
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel)
- c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, handshakePhase, clientWrite)
+ c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel)
- c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, handshakePhase, serverWrite)
+ c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
msg, err := c.readHandshake()
if err != nil {
@@ -675,24 +694,12 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
var chainToSend *Certificate
var certReq *certificateRequestMsg
- if !hs.serverHello.useCertAuth {
- if encryptedExtensions.extensions.ocspResponse != nil {
- c.sendAlert(alertUnsupportedExtension)
- return errors.New("tls: server sent OCSP response without a certificate")
- }
- if encryptedExtensions.extensions.sctList != nil {
- c.sendAlert(alertUnsupportedExtension)
- return errors.New("tls: server sent SCT list without a certificate")
- }
-
+ if c.didResume {
// Copy over authentication from the session.
c.peerCertificates = hs.session.serverCertificates
c.sctList = hs.session.sctList
c.ocspResponse = hs.session.ocspResponse
} else {
- c.ocspResponse = encryptedExtensions.extensions.ocspResponse
- c.sctList = encryptedExtensions.extensions.sctList
-
msg, err := c.readHandshake()
if err != nil {
return err
@@ -729,10 +736,28 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
}
hs.writeServerHash(certMsg.marshal())
+ // Check for unsolicited extensions.
+ for i, cert := range certMsg.certificates {
+ if c.config.Bugs.NoOCSPStapling && cert.ocspResponse != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected OCSP response in the server certificate")
+ }
+ if c.config.Bugs.NoSignedCertificateTimestamps && cert.sctList != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected SCT list in the server certificate")
+ }
+ if i > 0 && c.config.Bugs.ExpectNoExtensionsOnIntermediate && (cert.ocspResponse != nil || cert.sctList != nil) {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected extensions in the server certificate")
+ }
+ }
+
if err := hs.verifyCertificates(certMsg); err != nil {
return err
}
leaf := c.peerCertificates[0]
+ c.ocspResponse = certMsg.certificates[0].ocspResponse
+ c.sctList = certMsg.certificates[0].sctList
msg, err = c.readHandshake()
if err != nil {
@@ -785,7 +810,12 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
requestContext: certReq.requestContext,
}
if chainToSend != nil {
- certMsg.certificates = chainToSend.Certificate
+ for _, certData := range chainToSend.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ extraExtension: c.config.Bugs.SendExtensionOnCertificate,
+ })
+ }
}
hs.writeClientHash(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -820,6 +850,17 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
}
}
+ if encryptedExtensions.extensions.channelIDRequested {
+ channelIDHash := crypto.SHA256.New()
+ channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+ channelIDMsgBytes, err := hs.writeChannelIDMessage(channelIDHash.Sum(nil))
+ if err != nil {
+ return err
+ }
+ hs.writeClientHash(channelIDMsgBytes)
+ c.writeRecord(recordTypeHandshake, channelIDMsgBytes)
+ }
+
// Send a client Finished message.
finished := new(finishedMsg)
finished.verifyData = hs.finishedHash.clientSum(clientHandshakeTrafficSecret)
@@ -839,8 +880,8 @@ func (hs *clientHandshakeState) doTLS13Handshake() error {
c.flushHandshake()
// Switch to application data keys.
- c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, applicationPhase, clientWrite)
- c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, applicationPhase, serverWrite)
+ c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
+ c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
@@ -953,7 +994,11 @@ func (hs *clientHandshakeState) doFullHandshake() error {
} else if !c.config.Bugs.SkipClientCertificate {
certMsg := new(certificateMsg)
if chainToSend != nil {
- certMsg.certificates = chainToSend.Certificate
+ for _, certData := range chainToSend.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ })
+ }
}
hs.writeClientHash(certMsg.marshal())
c.writeRecord(recordTypeHandshake, certMsg.marshal())
@@ -1041,8 +1086,8 @@ func (hs *clientHandshakeState) verifyCertificates(certMsg *certificateMsg) erro
}
certs := make([]*x509.Certificate, len(certMsg.certificates))
- for i, asn1Data := range certMsg.certificates {
- cert, err := x509.ParseCertificate(asn1Data)
+ for i, certEntry := range certMsg.certificates {
+ cert, err := x509.ParseCertificate(certEntry.data)
if err != nil {
c.sendAlert(alertBadCertificate)
return errors.New("tls: failed to parse certificate from server: " + err.Error())
@@ -1169,11 +1214,6 @@ func (hs *clientHandshakeState) processServerExtensions(serverExtensions *server
return errors.New("server advertised unrequested Channel ID extension")
}
- if serverExtensions.channelIDRequested && c.vers >= VersionTLS13 {
- c.sendAlert(alertHandshakeFailure)
- return errors.New("server advertised Channel ID over TLS 1.3")
- }
-
if serverExtensions.extendedMasterSecret && c.vers >= VersionTLS13 {
return errors.New("tls: server advertised extended master secret over TLS 1.3")
}
@@ -1182,6 +1222,22 @@ func (hs *clientHandshakeState) processServerExtensions(serverExtensions *server
return errors.New("tls: server advertised ticket extension over TLS 1.3")
}
+ if serverExtensions.ocspStapling && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised OCSP in ServerHello over TLS 1.3")
+ }
+
+ if serverExtensions.ocspStapling && c.config.Bugs.NoOCSPStapling {
+ return errors.New("tls: server advertised unrequested OCSP extension")
+ }
+
+ if len(serverExtensions.sctList) > 0 && c.vers >= VersionTLS13 {
+ return errors.New("tls: server advertised SCTs in ServerHello over TLS 1.3")
+ }
+
+ if len(serverExtensions.sctList) > 0 && c.config.Bugs.NoSignedCertificateTimestamps {
+ return errors.New("tls: server advertised unrequested SCTs")
+ }
+
if serverExtensions.srtpProtectionProfile != 0 {
if serverExtensions.srtpMasterKeyIdentifier != "" {
return errors.New("tls: server selected SRTP MKI value")
@@ -1287,7 +1343,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
vers: c.vers,
cipherSuite: hs.suite.id,
masterSecret: hs.masterSecret,
- handshakeHash: hs.finishedHash.server.Sum(nil),
+ handshakeHash: hs.finishedHash.Sum(),
serverCertificates: c.peerCertificates,
sctList: c.sctList,
ocspResponse: c.ocspResponse,
@@ -1346,31 +1402,14 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
}
if hs.serverHello.extensions.channelIDRequested {
- channelIDMsg := new(channelIDMsg)
- if c.config.ChannelID.Curve != elliptic.P256() {
- return fmt.Errorf("tls: Channel ID is not on P-256.")
- }
var resumeHash []byte
if isResume {
resumeHash = hs.session.handshakeHash
}
- r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, hs.finishedHash.hashForChannelID(resumeHash))
+ channelIDMsgBytes, err := hs.writeChannelIDMessage(hs.finishedHash.hashForChannelID(resumeHash))
if err != nil {
return err
}
- channelID := make([]byte, 128)
- writeIntPadded(channelID[0:32], c.config.ChannelID.X)
- writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
- writeIntPadded(channelID[64:96], r)
- writeIntPadded(channelID[96:128], s)
- if c.config.Bugs.InvalidChannelIDSignature {
- channelID[64] ^= 1
- }
- channelIDMsg.channelID = channelID
-
- c.channelID = &c.config.ChannelID.PublicKey
-
- channelIDMsgBytes := channelIDMsg.marshal()
hs.writeHash(channelIDMsgBytes, seqno)
seqno++
postCCSMsgs = append(postCCSMsgs, channelIDMsgBytes)
@@ -1431,6 +1470,31 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error {
return nil
}
+func (hs *clientHandshakeState) writeChannelIDMessage(channelIDHash []byte) ([]byte, error) {
+ c := hs.c
+ channelIDMsg := new(channelIDMsg)
+ if c.config.ChannelID.Curve != elliptic.P256() {
+ return nil, fmt.Errorf("tls: Channel ID is not on P-256.")
+ }
+ r, s, err := ecdsa.Sign(c.config.rand(), c.config.ChannelID, channelIDHash)
+ if err != nil {
+ return nil, err
+ }
+ channelID := make([]byte, 128)
+ writeIntPadded(channelID[0:32], c.config.ChannelID.X)
+ writeIntPadded(channelID[32:64], c.config.ChannelID.Y)
+ writeIntPadded(channelID[64:96], r)
+ writeIntPadded(channelID[96:128], s)
+ if c.config.Bugs.InvalidChannelIDSignature {
+ channelID[64] ^= 1
+ }
+ channelIDMsg.channelID = channelID
+
+ c.channelID = &c.config.ChannelID.PublicKey
+
+ return channelIDMsg.marshal(), nil
+}
+
func (hs *clientHandshakeState) writeClientHash(msg []byte) {
// writeClientHash is called before writeRecord.
hs.writeHash(msg, hs.c.sendHandshakeSeq)
@@ -1573,3 +1637,39 @@ func writeIntPadded(b []byte, x *big.Int) {
xb := x.Bytes()
copy(b[len(b)-len(xb):], xb)
}
+
+func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, transcript []byte, config *Config) {
+ if config.Bugs.SendNoPSKBinder {
+ return
+ }
+
+ binderLen := pskCipherSuite.hash().Size()
+ if config.Bugs.SendShortPSKBinder {
+ binderLen--
+ }
+
+ // Fill hello.pskBinders with appropriate length arrays of zeros so the
+ // length prefixes are correct when computing the binder over the truncated
+ // ClientHello message.
+ hello.pskBinders = make([][]byte, len(hello.pskIdentities))
+ for i := range hello.pskIdentities {
+ hello.pskBinders[i] = make([]byte, binderLen)
+ }
+
+ helloBytes := hello.marshal()
+ binderSize := len(hello.pskBinders)*(binderLen+1) + 2
+ truncatedHello := helloBytes[:len(helloBytes)-binderSize]
+ binder := computePSKBinder(psk, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+ if config.Bugs.SendShortPSKBinder {
+ binder = binder[:binderLen]
+ }
+ if config.Bugs.SendInvalidPSKBinder {
+ binder[0] ^= 1
+ }
+
+ for i := range hello.pskBinders {
+ hello.pskBinders[i] = binder
+ }
+
+ hello.raw = nil
+}
diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go
index 285587e1..8a338f0b 100644
--- a/src/ssl/test/runner/handshake_messages.go
+++ b/src/ssl/test/runner/handshake_messages.go
@@ -125,9 +125,8 @@ type keyShareEntry struct {
}
type pskIdentity struct {
- keModes []byte
- authModes []byte
- ticket []uint8
+ ticket []uint8
+ obfuscatedTicketAge uint32
}
type clientHelloMsg struct {
@@ -148,8 +147,9 @@ type clientHelloMsg struct {
keyShares []keyShareEntry
trailingKeyShareData bool
pskIdentities []pskIdentity
+ pskKEModes []byte
+ pskBinders [][]uint8
hasEarlyData bool
- earlyDataContext []byte
tls13Cookie []byte
ticketSupported bool
sessionTicket []uint8
@@ -159,13 +159,14 @@ type clientHelloMsg struct {
alpnProtocols []string
duplicateExtension bool
channelIDSupported bool
- npnLast bool
+ npnAfterAlpn bool
extendedMasterSecret bool
srtpProtectionProfiles []uint16
srtpMasterKeyIdentifier string
sctListSupported bool
customExtension string
hasGREASEExtension bool
+ pskBinderFirst bool
}
func (m *clientHelloMsg) equal(i interface{}) bool {
@@ -191,8 +192,9 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
eqKeyShareEntryLists(m.keyShares, m1.keyShares) &&
m.trailingKeyShareData == m1.trailingKeyShareData &&
eqPSKIdentityLists(m.pskIdentities, m1.pskIdentities) &&
+ bytes.Equal(m.pskKEModes, m1.pskKEModes) &&
+ eqByteSlices(m.pskBinders, m1.pskBinders) &&
m.hasEarlyData == m1.hasEarlyData &&
- bytes.Equal(m.earlyDataContext, m1.earlyDataContext) &&
bytes.Equal(m.tls13Cookie, m1.tls13Cookie) &&
m.ticketSupported == m1.ticketSupported &&
bytes.Equal(m.sessionTicket, m1.sessionTicket) &&
@@ -203,13 +205,14 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
m.duplicateExtension == m1.duplicateExtension &&
m.channelIDSupported == m1.channelIDSupported &&
- m.npnLast == m1.npnLast &&
+ m.npnAfterAlpn == m1.npnAfterAlpn &&
m.extendedMasterSecret == m1.extendedMasterSecret &&
eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) &&
m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier &&
m.sctListSupported == m1.sctListSupported &&
m.customExtension == m1.customExtension &&
- m.hasGREASEExtension == m1.hasGREASEExtension
+ m.hasGREASEExtension == m1.hasGREASEExtension &&
+ m.pskBinderFirst == m1.pskBinderFirst
}
func (m *clientHelloMsg) marshal() []byte {
@@ -236,12 +239,26 @@ func (m *clientHelloMsg) marshal() []byte {
compressionMethods.addBytes(m.compressionMethods)
extensions := hello.addU16LengthPrefixed()
+ if len(m.pskIdentities) > 0 && m.pskBinderFirst {
+ extensions.addU16(extensionPreSharedKey)
+ pskExtension := extensions.addU16LengthPrefixed()
+
+ pskIdentities := pskExtension.addU16LengthPrefixed()
+ for _, psk := range m.pskIdentities {
+ pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+ pskIdentities.addU32(psk.obfuscatedTicketAge)
+ }
+ pskBinders := pskExtension.addU16LengthPrefixed()
+ for _, binder := range m.pskBinders {
+ pskBinders.addU8LengthPrefixed().addBytes(binder)
+ }
+ }
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(0) // 0-length for empty extension
}
- if m.nextProtoNeg && !m.npnLast {
+ if m.nextProtoNeg && !m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extensions.addU16(0) // The length is always 0
}
@@ -316,23 +333,14 @@ func (m *clientHelloMsg) marshal() []byte {
keyShares.addU8(0)
}
}
- if len(m.pskIdentities) > 0 {
- extensions.addU16(extensionPreSharedKey)
- pskExtension := extensions.addU16LengthPrefixed()
-
- pskIdentities := pskExtension.addU16LengthPrefixed()
- for _, psk := range m.pskIdentities {
- pskIdentities.addU8LengthPrefixed().addBytes(psk.keModes)
- pskIdentities.addU8LengthPrefixed().addBytes(psk.authModes)
- pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
- }
+ if len(m.pskKEModes) > 0 {
+ extensions.addU16(extensionPSKKeyExchangeModes)
+ pskModesExtension := extensions.addU16LengthPrefixed()
+ pskModesExtension.addU8LengthPrefixed().addBytes(m.pskKEModes)
}
if m.hasEarlyData {
extensions.addU16(extensionEarlyData)
- earlyDataIndication := extensions.addU16LengthPrefixed()
-
- context := earlyDataIndication.addU8LengthPrefixed()
- context.addBytes(m.earlyDataContext)
+ extensions.addU16(0) // The length is zero.
}
if len(m.tls13Cookie) > 0 {
extensions.addU16(extensionCookie)
@@ -383,7 +391,7 @@ func (m *clientHelloMsg) marshal() []byte {
extensions.addU16(extensionChannelID)
extensions.addU16(0) // Length is always 0
}
- if m.nextProtoNeg && m.npnLast {
+ if m.nextProtoNeg && m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extensions.addU16(0) // Length is always 0
}
@@ -422,6 +430,21 @@ func (m *clientHelloMsg) marshal() []byte {
customExt := extensions.addU16LengthPrefixed()
customExt.addBytes([]byte(m.customExtension))
}
+ // The PSK extension must be last (draft-ietf-tls-tls13-18 section 4.2.6).
+ if len(m.pskIdentities) > 0 && !m.pskBinderFirst {
+ extensions.addU16(extensionPreSharedKey)
+ pskExtension := extensions.addU16LengthPrefixed()
+
+ pskIdentities := pskExtension.addU16LengthPrefixed()
+ for _, psk := range m.pskIdentities {
+ pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket)
+ pskIdentities.addU32(psk.obfuscatedTicketAge)
+ }
+ pskBinders := pskExtension.addU16LengthPrefixed()
+ for _, binder := range m.pskBinders {
+ pskBinders.addU8LengthPrefixed().addBytes(binder)
+ }
+ }
if extensions.len() == 0 {
hello.discardChild()
@@ -490,7 +513,6 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.keyShares = nil
m.pskIdentities = nil
m.hasEarlyData = false
- m.earlyDataContext = nil
m.ticketSupported = false
m.sessionTicket = nil
m.signatureAlgorithms = nil
@@ -614,63 +636,75 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
m.keyShares = append(m.keyShares, entry)
}
case extensionPreSharedKey:
- // draft-ietf-tls-tls13 section 6.3.2.4
+ // draft-ietf-tls-tls13-18 section 4.2.6
if length < 2 {
return false
}
l := int(data[0])<<8 | int(data[1])
- if l != length-2 {
- return false
- }
- d := data[2:length]
+ d := data[2 : l+2]
+ // Parse PSK identities.
for len(d) > 0 {
- var psk pskIdentity
-
- if len(d) < 1 {
+ if len(d) < 2 {
return false
}
- keModesLen := int(d[0])
- d = d[1:]
- if len(d) < keModesLen {
+ pskLen := int(d[0])<<8 | int(d[1])
+ d = d[2:]
+
+ if len(d) < pskLen+4 {
return false
}
- psk.keModes = d[:keModesLen]
- d = d[keModesLen:]
-
+ ticket := d[:pskLen]
+ obfuscatedTicketAge := uint32(d[pskLen])<<24 | uint32(d[pskLen+1])<<16 | uint32(d[pskLen+2])<<8 | uint32(d[pskLen+3])
+ psk := pskIdentity{
+ ticket: ticket,
+ obfuscatedTicketAge: obfuscatedTicketAge,
+ }
+ m.pskIdentities = append(m.pskIdentities, psk)
+ d = d[pskLen+4:]
+ }
+ d = data[l+2:]
+ if len(d) < 2 {
+ return false
+ }
+ l = int(d[0])<<8 | int(d[1])
+ d = d[2:]
+ if l != len(d) {
+ return false
+ }
+ // Parse PSK binders.
+ for len(d) > 0 {
if len(d) < 1 {
return false
}
- authModesLen := int(d[0])
+ binderLen := int(d[0])
d = d[1:]
- if len(d) < authModesLen {
+ if binderLen > len(d) {
return false
}
- psk.authModes = d[:authModesLen]
- d = d[authModesLen:]
- if len(d) < 2 {
- return false
- }
- pskLen := int(d[0])<<8 | int(d[1])
- d = d[2:]
+ m.pskBinders = append(m.pskBinders, d[:binderLen])
+ d = d[binderLen:]
+ }
- if len(d) < pskLen {
- return false
- }
- psk.ticket = d[:pskLen]
- m.pskIdentities = append(m.pskIdentities, psk)
- d = d[pskLen:]
+ // There must be the same number of identities as binders.
+ if len(m.pskIdentities) != len(m.pskBinders) {
+ return false
}
- case extensionEarlyData:
- // draft-ietf-tls-tls13 section 6.3.2.5
+ case extensionPSKKeyExchangeModes:
+ // draft-ietf-tls-tls13-18 section 4.2.7
if length < 1 {
return false
}
l := int(data[0])
- if length != l+1 {
+ if l != length-1 {
+ return false
+ }
+ m.pskKEModes = data[1:length]
+ case extensionEarlyData:
+ // draft-ietf-tls-tls13 section 6.3.2.5
+ if length != 0 {
return false
}
m.hasEarlyData = true
- m.earlyDataContext = data[1:length]
case extensionCookie:
if length < 2 {
return false
@@ -793,7 +827,6 @@ type serverHelloMsg struct {
keyShare keyShareEntry
hasPSKIdentity bool
pskIdentity uint16
- useCertAuth bool
earlyDataIndication bool
compressionMethod uint8
customExtension string
@@ -848,10 +881,6 @@ func (m *serverHelloMsg) marshal() []byte {
extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity)
}
- if m.useCertAuth {
- extensions.addU16(extensionSignatureAlgorithms)
- extensions.addU16(0) // Length
- }
if m.earlyDataIndication {
extensions.addU16(extensionEarlyData)
extensions.addU16(0) // Length
@@ -870,7 +899,7 @@ func (m *serverHelloMsg) marshal() []byte {
protocolName.addBytes([]byte(m.unencryptedALPN))
}
} else {
- m.extensions.marshal(extensions, vers)
+ m.extensions.marshal(extensions)
if extensions.len() == 0 {
hello.discardChild()
}
@@ -962,11 +991,6 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
}
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true
- case extensionSignatureAlgorithms:
- if len(d) != 0 {
- return false
- }
- m.useCertAuth = true
case extensionEarlyData:
if len(d) != 0 {
return false
@@ -1001,7 +1025,7 @@ func (m *encryptedExtensionsMsg) marshal() []byte {
encryptedExtensions := encryptedExtensionsMsg.addU24LengthPrefixed()
if !m.empty {
extensions := encryptedExtensions.addU16LengthPrefixed()
- m.extensions.marshal(extensions, VersionTLS13)
+ m.extensions.marshal(extensions)
}
m.raw = encryptedExtensionsMsg.finish()
@@ -1033,7 +1057,6 @@ type serverExtensions struct {
nextProtoNeg bool
nextProtos []string
ocspStapling bool
- ocspResponse []byte
ticketSupported bool
secureRenegotiation []byte
alpnProtocol string
@@ -1045,18 +1068,18 @@ type serverExtensions struct {
srtpMasterKeyIdentifier string
sctList []byte
customExtension string
- npnLast bool
+ npnAfterAlpn bool
hasKeyShare bool
keyShare keyShareEntry
}
-func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) {
+func (m *serverExtensions) marshal(extensions *byteBuilder) {
if m.duplicateExtension {
// Add a duplicate bogus extension at the beginning and end.
extensions.addU16(0xffff)
extensions.addU16(0) // length = 0 for empty extension
}
- if m.nextProtoNeg && !m.npnLast {
+ if m.nextProtoNeg && !m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extension := extensions.addU16LengthPrefixed()
@@ -1068,19 +1091,9 @@ func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) {
npn.addBytes([]byte(v))
}
}
- if version >= VersionTLS13 {
- if m.ocspResponse != nil {
- extensions.addU16(extensionStatusRequest)
- body := extensions.addU16LengthPrefixed()
- body.addU8(statusTypeOCSP)
- response := body.addU24LengthPrefixed()
- response.addBytes(m.ocspResponse)
- }
- } else {
- if m.ocspStapling {
- extensions.addU16(extensionStatusRequest)
- extensions.addU16(0)
- }
+ if m.ocspStapling {
+ extensions.addU16(extensionStatusRequest)
+ extensions.addU16(0)
}
if m.ticketSupported {
extensions.addU16(extensionSessionTicket)
@@ -1133,7 +1146,7 @@ func (m *serverExtensions) marshal(extensions *byteBuilder, version uint16) {
customExt := extensions.addU16LengthPrefixed()
customExt.addBytes([]byte(m.customExtension))
}
- if m.nextProtoNeg && m.npnLast {
+ if m.nextProtoNeg && m.npnAfterAlpn {
extensions.addU16(extensionNextProtoNeg)
extension := extensions.addU16LengthPrefixed()
@@ -1183,25 +1196,10 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool {
d = d[l:]
}
case extensionStatusRequest:
- if version >= VersionTLS13 {
- if length < 4 {
- return false
- }
- d := data[:length]
- if d[0] != statusTypeOCSP {
- return false
- }
- respLen := int(d[1])<<16 | int(d[2])<<8 | int(d[3])
- if respLen+4 != len(d) || respLen == 0 {
- return false
- }
- m.ocspResponse = d[4:]
- } else {
- if length > 0 {
- return false
- }
- m.ocspStapling = true
+ if length > 0 {
+ return false
}
+ m.ocspStapling = true
case extensionSessionTicket:
if length > 0 {
return false
@@ -1377,11 +1375,19 @@ func (m *helloRetryRequestMsg) unmarshal(data []byte) bool {
return true
}
+type certificateEntry struct {
+ data []byte
+ ocspResponse []byte
+ sctList []byte
+ duplicateExtensions bool
+ extraExtension []byte
+}
+
type certificateMsg struct {
raw []byte
hasRequestContext bool
requestContext []byte
- certificates [][]byte
+ certificates []certificateEntry
}
func (m *certificateMsg) marshal() (x []byte) {
@@ -1399,7 +1405,33 @@ func (m *certificateMsg) marshal() (x []byte) {
certificateList := certificate.addU24LengthPrefixed()
for _, cert := range m.certificates {
certEntry := certificateList.addU24LengthPrefixed()
- certEntry.addBytes(cert)
+ certEntry.addBytes(cert.data)
+ if m.hasRequestContext {
+ extensions := certificateList.addU16LengthPrefixed()
+ count := 1
+ if cert.duplicateExtensions {
+ count = 2
+ }
+
+ for i := 0; i < count; i++ {
+ if cert.ocspResponse != nil {
+ extensions.addU16(extensionStatusRequest)
+ body := extensions.addU16LengthPrefixed()
+ body.addU8(statusTypeOCSP)
+ response := body.addU24LengthPrefixed()
+ response.addBytes(cert.ocspResponse)
+ }
+
+ if cert.sctList != nil {
+ extensions.addU16(extensionSignedCertificateTimestamp)
+ extension := extensions.addU16LengthPrefixed()
+ extension.addBytes(cert.sctList)
+ }
+ }
+ if cert.extraExtension != nil {
+ extensions.addBytes(cert.extraExtension)
+ }
+ }
}
m.raw = certMsg.finish()
@@ -1436,27 +1468,62 @@ func (m *certificateMsg) unmarshal(data []byte) bool {
return false
}
- numCerts := 0
- d := data
- for certsLen > 0 {
- if len(d) < 4 {
+ m.certificates = nil
+ for len(data) != 0 {
+ if len(data) < 3 {
return false
}
- certLen := int(d[0])<<16 | int(d[1])<<8 | int(d[2])
- if len(d) < 3+certLen {
+ certLen := int(data[0])<<16 | int(data[1])<<8 | int(data[2])
+ if len(data) < 3+certLen {
return false
}
- d = d[3+certLen:]
- certsLen -= 3 + certLen
- numCerts++
- }
-
- m.certificates = make([][]byte, numCerts)
- d = data
- for i := 0; i < numCerts; i++ {
- certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
- m.certificates[i] = d[3 : 3+certLen]
- d = d[3+certLen:]
+ cert := certificateEntry{
+ data: data[3 : 3+certLen],
+ }
+ data = data[3+certLen:]
+ if m.hasRequestContext {
+ if len(data) < 2 {
+ return false
+ }
+ extensionsLen := int(data[0])<<8 | int(data[1])
+ if len(data) < 2+extensionsLen {
+ return false
+ }
+ extensions := data[2 : 2+extensionsLen]
+ data = data[2+extensionsLen:]
+ for len(extensions) != 0 {
+ if len(extensions) < 4 {
+ return false
+ }
+ extension := uint16(extensions[0])<<8 | uint16(extensions[1])
+ length := int(extensions[2])<<8 | int(extensions[3])
+ if len(extensions) < 4+length {
+ return false
+ }
+ contents := extensions[4 : 4+length]
+ extensions = extensions[4+length:]
+
+ switch extension {
+ case extensionStatusRequest:
+ if length < 4 {
+ return false
+ }
+ if contents[0] != statusTypeOCSP {
+ return false
+ }
+ respLen := int(contents[1])<<16 | int(contents[2])<<8 | int(contents[3])
+ if respLen+4 != len(contents) || respLen == 0 {
+ return false
+ }
+ cert.ocspResponse = contents[4:]
+ case extensionSignedCertificateTimestamp:
+ cert.sctList = contents
+ default:
+ return false
+ }
+ }
+ }
+ m.certificates = append(m.certificates, cert)
}
return true
@@ -1904,8 +1971,7 @@ type newSessionTicketMsg struct {
raw []byte
version uint16
ticketLifetime uint32
- keModes []byte
- authModes []byte
+ ticketAgeAdd uint32
ticket []byte
customExtension string
hasGREASEExtension bool
@@ -1922,8 +1988,7 @@ func (m *newSessionTicketMsg) marshal() []byte {
body := ticketMsg.addU24LengthPrefixed()
body.addU32(m.ticketLifetime)
if m.version >= VersionTLS13 {
- body.addU8LengthPrefixed().addBytes(m.keModes)
- body.addU8LengthPrefixed().addBytes(m.authModes)
+ body.addU32(m.ticketAgeAdd)
}
ticket := body.addU16LengthPrefixed()
@@ -1951,25 +2016,11 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
data = data[8:]
if m.version >= VersionTLS13 {
- if len(data) < 1 {
- return false
- }
- keModesLength := int(data[0])
- if len(data)-1 < keModesLength {
- return false
- }
- m.keModes = data[1 : 1+keModesLength]
- data = data[1+keModesLength:]
-
- if len(data) < 1 {
- return false
- }
- authModesLength := int(data[0])
- if len(data)-1 < authModesLength {
+ if len(data) < 4 {
return false
}
- m.authModes = data[1 : 1+authModesLength]
- data = data[1+authModesLength:]
+ m.ticketAgeAdd = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ data = data[4:]
}
if len(data) < 2 {
@@ -2268,7 +2319,7 @@ func eqPSKIdentityLists(x, y []pskIdentity) bool {
return false
}
for i, v := range x {
- if !bytes.Equal(y[i].keModes, v.keModes) || !bytes.Equal(y[i].authModes, v.authModes) || !bytes.Equal(y[i].ticket, v.ticket) {
+ if !bytes.Equal(y[i].ticket, v.ticket) || y[i].obfuscatedTicketAge != v.obfuscatedTicketAge {
return false
}
}
diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go
index 91471347..67950baa 100644
--- a/src/ssl/test/runner/handshake_server.go
+++ b/src/ssl/test/runner/handshake_server.go
@@ -16,6 +16,7 @@ import (
"fmt"
"io"
"math/big"
+ "time"
)
// serverHandshakeState contains details of a server handshake in progress.
@@ -158,7 +159,7 @@ func (hs *serverHandshakeState) readClientHello() error {
// Per RFC 6347, the version field in HelloVerifyRequest SHOULD
// be always DTLS 1.0
helloVerifyRequest := &helloVerifyRequestMsg{
- vers: VersionTLS10,
+ vers: versionToWire(VersionTLS10, c.isDTLS),
cookie: make([]byte, 32),
}
if _, err := io.ReadFull(c.config.rand(), helloVerifyRequest.cookie); err != nil {
@@ -384,6 +385,36 @@ func (hs *serverHandshakeState) doTLS13Handshake() error {
return err
}
+ // Select the cipher suite.
+ var preferenceList, supportedList []uint16
+ if config.PreferServerCipherSuites {
+ preferenceList = config.cipherSuites()
+ supportedList = hs.clientHello.cipherSuites
+ } else {
+ preferenceList = hs.clientHello.cipherSuites
+ supportedList = config.cipherSuites()
+ }
+
+ for _, id := range preferenceList {
+ if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
+ break
+ }
+ }
+
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+
+ hs.hello.cipherSuite = hs.suite.id
+ if c.config.Bugs.SendCipherSuite != 0 {
+ hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.finishedHash.discardHandshakeBuffer()
+ hs.writeClientHash(hs.clientHello.marshal())
+
supportedCurve := false
var selectedCurve CurveID
preferredCurves := config.curvePreferences()
@@ -404,78 +435,55 @@ Curves:
}
pskIdentities := hs.clientHello.pskIdentities
+ pskKEModes := hs.clientHello.pskKEModes
+
if len(pskIdentities) == 0 && len(hs.clientHello.sessionTicket) > 0 && c.config.Bugs.AcceptAnySession {
psk := pskIdentity{
- keModes: []byte{pskDHEKEMode},
- authModes: []byte{pskAuthMode},
- ticket: hs.clientHello.sessionTicket,
+ ticket: hs.clientHello.sessionTicket,
}
pskIdentities = []pskIdentity{psk}
+ pskKEModes = []byte{pskDHEKEMode}
}
- for i, pskIdentity := range pskIdentities {
- foundKE := false
- foundAuth := false
-
- for _, keMode := range pskIdentity.keModes {
- if keMode == pskDHEKEMode {
- foundKE = true
- }
- }
-
- for _, authMode := range pskIdentity.authModes {
- if authMode == pskAuthMode {
- foundAuth = true
- }
- }
-
- if !foundKE || !foundAuth {
- continue
- }
- sessionState, ok := c.decryptTicket(pskIdentity.ticket)
- if !ok {
- continue
- }
- if config.Bugs.AcceptAnySession {
- // Replace the cipher suite with one known to work, to
- // test cross-version resumption attempts.
- sessionState.cipherSuite = TLS_AES_128_GCM_SHA256
- } else {
- if sessionState.vers != c.vers && c.config.Bugs.AcceptAnySession {
- continue
- }
- if sessionState.ticketExpiration.Before(c.config.time()) {
+ var pskIndex int
+ foundKEMode := bytes.IndexByte(pskKEModes, pskDHEKEMode) >= 0
+ if foundKEMode {
+ for i, pskIdentity := range pskIdentities {
+ // TODO(svaldez): Check the obfuscatedTicketAge before accepting 0-RTT.
+ sessionState, ok := c.decryptTicket(pskIdentity.ticket)
+ if !ok {
continue
}
- cipherSuiteOk := false
- // Check that the client is still offering the ciphersuite in the session.
- for _, id := range hs.clientHello.cipherSuites {
- if id == sessionState.cipherSuite {
- cipherSuiteOk = true
- break
+ if !config.Bugs.AcceptAnySession {
+ if sessionState.vers != c.vers {
+ continue
+ }
+ if sessionState.ticketExpiration.Before(c.config.time()) {
+ continue
+ }
+ sessionCipher := cipherSuiteFromID(sessionState.cipherSuite)
+ if sessionCipher == nil || sessionCipher.hash() != hs.suite.hash() {
+ continue
}
}
- if !cipherSuiteOk {
- continue
- }
- }
- // Check that we also support the ciphersuite from the session.
- suite := c.tryCipherSuite(sessionState.cipherSuite, c.config.cipherSuites(), c.vers, true, true)
- if suite == nil {
- continue
- }
+ clientTicketAge := time.Duration(uint32(pskIdentity.obfuscatedTicketAge-sessionState.ticketAgeAdd)) * time.Millisecond
+ if config.Bugs.ExpectTicketAge != 0 && clientTicketAge != config.Bugs.ExpectTicketAge {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: invalid ticket age")
+ }
- hs.sessionState = sessionState
- hs.suite = suite
- hs.hello.hasPSKIdentity = true
- hs.hello.pskIdentity = uint16(i)
- if config.Bugs.SelectPSKIdentityOnResume != 0 {
- hs.hello.pskIdentity = config.Bugs.SelectPSKIdentityOnResume
+ hs.sessionState = sessionState
+ hs.hello.hasPSKIdentity = true
+ hs.hello.pskIdentity = uint16(i)
+ pskIndex = i
+ if config.Bugs.SelectPSKIdentityOnResume != 0 {
+ hs.hello.pskIdentity = config.Bugs.SelectPSKIdentityOnResume
+ }
+ c.didResume = true
+ break
}
- c.didResume = true
- break
}
if config.Bugs.AlwaysSelectPSKIdentity {
@@ -483,58 +491,25 @@ Curves:
hs.hello.pskIdentity = 0
}
- // If not resuming, select the cipher suite.
- if hs.suite == nil {
- var preferenceList, supportedList []uint16
- if config.PreferServerCipherSuites {
- preferenceList = config.cipherSuites()
- supportedList = hs.clientHello.cipherSuites
- } else {
- preferenceList = hs.clientHello.cipherSuites
- supportedList = config.cipherSuites()
- }
-
- for _, id := range preferenceList {
- if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil {
- break
- }
+ // Verify the PSK binder. Note there may not be a PSK binder if
+ // AcceptAnyBinder is set. See https://crbug.com/boringssl/115.
+ if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+ binderToVerify := hs.clientHello.pskBinders[pskIndex]
+ if err := verifyPSKBinder(hs.clientHello, hs.sessionState, binderToVerify, []byte{}); err != nil {
+ return err
}
}
- if hs.suite == nil {
- c.sendAlert(alertHandshakeFailure)
- return errors.New("tls: no cipher suite supported by both client and server")
- }
-
- hs.hello.cipherSuite = hs.suite.id
- if c.config.Bugs.SendCipherSuite != 0 {
- hs.hello.cipherSuite = c.config.Bugs.SendCipherSuite
- }
-
- hs.finishedHash = newFinishedHash(c.vers, hs.suite)
- hs.finishedHash.discardHandshakeBuffer()
- hs.writeClientHash(hs.clientHello.marshal())
-
- hs.hello.useCertAuth = hs.sessionState == nil
-
// Resolve PSK and compute the early secret.
var psk []byte
if hs.sessionState != nil {
- psk = deriveResumptionPSK(hs.suite, hs.sessionState.masterSecret)
- hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.sessionState.masterSecret))
+ psk = hs.sessionState.masterSecret
} else {
psk = hs.finishedHash.zeroSecret()
- hs.finishedHash.setResumptionContext(hs.finishedHash.zeroSecret())
}
earlySecret := hs.finishedHash.extractKey(hs.finishedHash.zeroSecret(), psk)
- if config.Bugs.OmitServerHelloSignatureAlgorithms {
- hs.hello.useCertAuth = false
- } else if config.Bugs.IncludeServerHelloSignatureAlgorithms {
- hs.hello.useCertAuth = true
- }
-
hs.hello.hasKeyShare = true
if hs.sessionState != nil && config.Bugs.NegotiatePSKResumption {
hs.hello.hasKeyShare = false
@@ -598,6 +573,7 @@ ResendHelloRetryRequest:
}
if sendHelloRetryRequest {
+ oldClientHelloBytes := hs.clientHello.marshal()
hs.writeServerHash(helloRetryRequest.marshal())
c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
c.flushHandshake()
@@ -621,17 +597,16 @@ ResendHelloRetryRequest:
oldClientHelloCopy := *hs.clientHello
oldClientHelloCopy.raw = nil
oldClientHelloCopy.hasEarlyData = false
- oldClientHelloCopy.earlyDataContext = nil
newClientHelloCopy := *newClientHello
newClientHelloCopy.raw = nil
if helloRetryRequest.hasSelectedGroup {
newKeyShares := newClientHelloCopy.keyShares
- if len(newKeyShares) == 0 || newKeyShares[len(newKeyShares)-1].group != helloRetryRequest.selectedGroup {
- return errors.New("tls: KeyShare from HelloRetryRequest not present in new ClientHello")
+ if len(newKeyShares) != 1 || newKeyShares[0].group != helloRetryRequest.selectedGroup {
+ return errors.New("tls: KeyShare from HelloRetryRequest not in new ClientHello")
}
- selectedKeyShare = &newKeyShares[len(newKeyShares)-1]
- newClientHelloCopy.keyShares = newKeyShares[:len(newKeyShares)-1]
+ selectedKeyShare = &newKeyShares[0]
+ newClientHelloCopy.keyShares = oldClientHelloCopy.keyShares
}
if len(helloRetryRequest.cookie) > 0 {
@@ -641,6 +616,16 @@ ResendHelloRetryRequest:
newClientHelloCopy.tls13Cookie = nil
}
+ // PSK binders and obfuscated ticket age are both updated in the
+ // second ClientHello.
+ if len(oldClientHelloCopy.pskIdentities) != len(newClientHelloCopy.pskIdentities) {
+ return errors.New("tls: PSK identity count from old and new ClientHello do not match")
+ }
+ for i, identity := range oldClientHelloCopy.pskIdentities {
+ newClientHelloCopy.pskIdentities[i].obfuscatedTicketAge = identity.obfuscatedTicketAge
+ }
+ newClientHelloCopy.pskBinders = oldClientHelloCopy.pskBinders
+
if !oldClientHelloCopy.equal(&newClientHelloCopy) {
return errors.New("tls: new ClientHello does not match")
}
@@ -649,6 +634,16 @@ ResendHelloRetryRequest:
firstHelloRetryRequest = false
goto ResendHelloRetryRequest
}
+
+ // Verify the PSK binder. Note there may not be a PSK binder if
+ // AcceptAnyBinder is set. See https://crbug.com/115.
+ if hs.sessionState != nil && !config.Bugs.AcceptAnySession {
+ binderToVerify := newClientHello.pskBinders[pskIndex]
+ err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...))
+ if err != nil {
+ return err
+ }
+ }
}
// Resolve ECDHE and compute the handshake secret.
@@ -728,25 +723,9 @@ ResendHelloRetryRequest:
// Switch to handshake traffic keys.
serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel)
- c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, handshakePhase, serverWrite)
+ c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite)
clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel)
- c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, handshakePhase, clientWrite)
-
- if hs.hello.useCertAuth {
- if hs.clientHello.ocspStapling {
- encryptedExtensions.extensions.ocspResponse = hs.cert.OCSPStaple
- }
- if hs.clientHello.sctListSupported {
- encryptedExtensions.extensions.sctList = hs.cert.SignedCertificateTimestampList
- }
- } else {
- if config.Bugs.SendOCSPResponseOnResume != nil {
- encryptedExtensions.extensions.ocspResponse = config.Bugs.SendOCSPResponseOnResume
- }
- if config.Bugs.SendSCTListOnResume != nil {
- encryptedExtensions.extensions.sctList = config.Bugs.SendSCTListOnResume
- }
- }
+ c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite)
// Send EncryptedExtensions.
hs.writeServerHash(encryptedExtensions.marshal())
@@ -757,7 +736,7 @@ ResendHelloRetryRequest:
c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal())
}
- if hs.hello.useCertAuth {
+ if hs.sessionState == nil {
if config.ClientAuth >= RequestClientCert {
// Request a client certificate
certReq := &certificateRequestMsg{
@@ -785,7 +764,29 @@ ResendHelloRetryRequest:
hasRequestContext: true,
}
if !config.Bugs.EmptyCertificateList {
- certMsg.certificates = hs.cert.Certificate
+ for i, certData := range hs.cert.Certificate {
+ cert := certificateEntry{
+ data: certData,
+ }
+ if i == 0 {
+ if hs.clientHello.ocspStapling {
+ cert.ocspResponse = hs.cert.OCSPStaple
+ }
+ if hs.clientHello.sctListSupported {
+ cert.sctList = hs.cert.SignedCertificateTimestampList
+ }
+ cert.duplicateExtensions = config.Bugs.SendDuplicateCertExtensions
+ cert.extraExtension = config.Bugs.SendExtensionOnCertificate
+ } else {
+ if config.Bugs.SendOCSPOnIntermediates != nil {
+ cert.ocspResponse = config.Bugs.SendOCSPOnIntermediates
+ }
+ if config.Bugs.SendSCTOnIntermediates != nil {
+ cert.sctList = config.Bugs.SendSCTOnIntermediates
+ }
+ }
+ certMsg.certificates = append(certMsg.certificates, cert)
+ }
}
certMsgBytes := certMsg.marshal()
hs.writeServerHash(certMsgBytes)
@@ -844,10 +845,11 @@ ResendHelloRetryRequest:
masterSecret := hs.finishedHash.extractKey(handshakeSecret, hs.finishedHash.zeroSecret())
clientTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, clientApplicationTrafficLabel)
serverTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, serverApplicationTrafficLabel)
+ c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
// Switch to application data keys on write. In particular, any alerts
// from the client certificate are sent over these keys.
- c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, applicationPhase, serverWrite)
+ c.out.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite)
// If we requested a client certificate, then the client must send a
// certificate message, even if it's empty.
@@ -873,7 +875,17 @@ ResendHelloRetryRequest:
}
}
- pub, err := hs.processCertsFromClient(certMsg.certificates)
+ var certs [][]byte
+ for _, cert := range certMsg.certificates {
+ certs = append(certs, cert.data)
+ // OCSP responses and SCT lists are not negotiated in
+ // client certificates.
+ if cert.ocspResponse != nil || cert.sctList != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: unexpected extensions in the client certificate")
+ }
+ }
+ pub, err := hs.processCertsFromClient(certs)
if err != nil {
return err
}
@@ -900,6 +912,27 @@ ResendHelloRetryRequest:
}
}
+ if encryptedExtensions.extensions.channelIDRequested {
+ msg, err := c.readHandshake()
+ if err != nil {
+ return err
+ }
+ channelIDMsg, ok := msg.(*channelIDMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(channelIDMsg, msg)
+ }
+ channelIDHash := crypto.SHA256.New()
+ channelIDHash.Write(hs.finishedHash.certificateVerifyInput(channelIDContextTLS13))
+ channelID, err := verifyChannelIDMessage(channelIDMsg, channelIDHash.Sum(nil))
+ if err != nil {
+ return err
+ }
+ c.channelID = channelID
+
+ hs.writeClientHash(channelIDMsg.marshal())
+ }
+
// Read the client Finished message.
msg, err := c.readHandshake()
if err != nil {
@@ -920,15 +953,14 @@ ResendHelloRetryRequest:
hs.writeClientHash(clientFinished.marshal())
// Switch to application data keys on read.
- c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, applicationPhase, clientWrite)
+ c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite)
c.cipherSuite = hs.suite
- c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel)
c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel)
// TODO(davidben): Allow configuring the number of tickets sent for
// testing.
- if !c.config.SessionTicketsDisabled {
+ if !c.config.SessionTicketsDisabled && foundKEMode {
ticketCount := 2
for i := 0; i < ticketCount; i++ {
c.SendNewSessionTicket()
@@ -1113,7 +1145,7 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server
if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
serverExtensions.nextProtoNeg = true
serverExtensions.nextProtos = config.NextProtos
- serverExtensions.npnLast = config.Bugs.SwapNPNAndALPN
+ serverExtensions.npnAfterAlpn = config.Bugs.SwapNPNAndALPN
}
}
}
@@ -1126,10 +1158,8 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server
serverExtensions.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !disableEMS
}
- if c.vers < VersionTLS13 || config.Bugs.NegotiateChannelIDAtAllVersions {
- if hs.clientHello.channelIDSupported && config.RequestChannelID {
- serverExtensions.channelIDRequested = true
- }
+ if hs.clientHello.channelIDSupported && config.RequestChannelID {
+ serverExtensions.channelIDRequested = true
}
if hs.clientHello.srtpProtectionProfiles != nil {
@@ -1321,7 +1351,11 @@ func (hs *serverHandshakeState) doFullHandshake() error {
if !isPSK {
certMsg := new(certificateMsg)
if !config.Bugs.EmptyCertificateList {
- certMsg.certificates = hs.cert.Certificate
+ for _, certData := range hs.cert.Certificate {
+ certMsg.certificates = append(certMsg.certificates, certificateEntry{
+ data: certData,
+ })
+ }
}
if !config.Bugs.UnauthenticatedECDH {
certMsgBytes := certMsg.marshal()
@@ -1409,7 +1443,9 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
hs.writeClientHash(certMsg.marshal())
- certificates = certMsg.certificates
+ for _, cert := range certMsg.certificates {
+ certificates = append(certificates, cert.data)
+ }
} else if c.vers != VersionSSL30 {
// In TLS, the Certificate message is required. In SSL
// 3.0, the peer skips it when sending no certificates.
@@ -1568,20 +1604,13 @@ func (hs *serverHandshakeState) readFinished(out []byte, isResume bool) error {
c.sendAlert(alertUnexpectedMessage)
return unexpectedMessageError(channelIDMsg, msg)
}
- x := new(big.Int).SetBytes(channelIDMsg.channelID[0:32])
- y := new(big.Int).SetBytes(channelIDMsg.channelID[32:64])
- r := new(big.Int).SetBytes(channelIDMsg.channelID[64:96])
- s := new(big.Int).SetBytes(channelIDMsg.channelID[96:128])
- if !elliptic.P256().IsOnCurve(x, y) {
- return errors.New("tls: invalid channel ID public key")
- }
- channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
var resumeHash []byte
if isResume {
resumeHash = hs.sessionState.handshakeHash
}
- if !ecdsa.Verify(channelID, hs.finishedHash.hashForChannelID(resumeHash), r, s) {
- return errors.New("tls: invalid channel ID signature")
+ channelID, err := verifyChannelIDMessage(channelIDMsg, hs.finishedHash.hashForChannelID(resumeHash))
+ if err != nil {
+ return err
}
c.channelID = channelID
@@ -1618,7 +1647,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
cipherSuite: hs.suite.id,
masterSecret: hs.masterSecret,
certificates: hs.certsFromClient,
- handshakeHash: hs.finishedHash.server.Sum(nil),
+ handshakeHash: hs.finishedHash.Sum(),
}
if !hs.hello.extensions.ticketSupported || hs.c.config.Bugs.SkipNewSessionTicket {
@@ -1765,6 +1794,21 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
return nil, nil
}
+func verifyChannelIDMessage(channelIDMsg *channelIDMsg, channelIDHash []byte) (*ecdsa.PublicKey, error) {
+ x := new(big.Int).SetBytes(channelIDMsg.channelID[0:32])
+ y := new(big.Int).SetBytes(channelIDMsg.channelID[32:64])
+ r := new(big.Int).SetBytes(channelIDMsg.channelID[64:96])
+ s := new(big.Int).SetBytes(channelIDMsg.channelID[96:128])
+ if !elliptic.P256().IsOnCurve(x, y) {
+ return nil, errors.New("tls: invalid channel ID public key")
+ }
+ channelID := &ecdsa.PublicKey{elliptic.P256(), x, y}
+ if !ecdsa.Verify(channelID, channelIDHash, r, s) {
+ return nil, errors.New("tls: invalid channel ID signature")
+ }
+ return channelID, nil
+}
+
func (hs *serverHandshakeState) writeServerHash(msg []byte) {
// writeServerHash is called before writeRecord.
hs.writeHash(msg, hs.c.sendHandshakeSeq)
@@ -1849,3 +1893,24 @@ func isTLS12Cipher(id uint16) bool {
func isGREASEValue(val uint16) bool {
return val&0x0f0f == 0x0a0a && val&0xff == val>>8
}
+
+func verifyPSKBinder(clientHello *clientHelloMsg, sessionState *sessionState, binderToVerify, transcript []byte) error {
+ binderLen := 2
+ for _, binder := range clientHello.pskBinders {
+ binderLen += 1 + len(binder)
+ }
+
+ truncatedHello := clientHello.marshal()
+ truncatedHello = truncatedHello[:len(truncatedHello)-binderLen]
+ pskCipherSuite := cipherSuiteFromID(sessionState.cipherSuite)
+ if pskCipherSuite == nil {
+ return errors.New("tls: Unknown cipher suite for PSK in session")
+ }
+
+ binder := computePSKBinder(sessionState.masterSecret, resumptionPSKBinderLabel, pskCipherSuite, transcript, truncatedHello)
+ if !bytes.Equal(binder, binderToVerify) {
+ return errors.New("tls: PSK binder does not verify")
+ }
+
+ return nil
+}
diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go
index ffa68e92..c311e995 100644
--- a/src/ssl/test/runner/prf.go
+++ b/src/ssl/test/runner/prf.go
@@ -230,10 +230,6 @@ type finishedHash struct {
// full buffer is required.
buffer []byte
- // TLS 1.3 has a resumption context which is carried over on PSK
- // resumption.
- resumptionContextHash []byte
-
version uint16
prf func(result, secret, label, seed []byte)
}
@@ -357,7 +353,7 @@ func (h finishedHash) hashForChannelID(resumeHash []byte) []byte {
hash.Write(channelIDResumeLabel)
hash.Write(resumeHash)
}
- hash.Write(h.server.Sum(nil))
+ hash.Write(h.Sum())
return hash.Sum(nil)
}
@@ -374,13 +370,6 @@ func (h *finishedHash) zeroSecret() []byte {
return make([]byte, h.hash.Size())
}
-// setResumptionContext sets the TLS 1.3 resumption context.
-func (h *finishedHash) setResumptionContext(resumptionContext []byte) {
- hash := h.hash.New()
- hash.Write(resumptionContext)
- h.resumptionContextHash = hash.Sum(nil)
-}
-
// extractKey combines two secrets together with HKDF-Expand in the TLS 1.3 key
// derivation schedule.
func (h *finishedHash) extractKey(salt, ikm []byte) []byte {
@@ -412,12 +401,13 @@ func hkdfExpandLabel(hash crypto.Hash, secret, label, hashValue []byte, length i
// resumption context hash, as used in TLS 1.3.
func (h *finishedHash) appendContextHashes(b []byte) []byte {
b = h.client.Sum(b)
- b = append(b, h.resumptionContextHash...)
return b
}
// The following are labels for traffic secret derivation in TLS 1.3.
var (
+ externalPSKBinderLabel = []byte("external psk binder key")
+ resumptionPSKBinderLabel = []byte("resumption psk binder key")
earlyTrafficLabel = []byte("client early traffic secret")
clientHandshakeTrafficLabel = []byte("client handshake traffic secret")
serverHandshakeTrafficLabel = []byte("server handshake traffic secret")
@@ -431,10 +421,6 @@ var (
// deriveSecret implements TLS 1.3's Derive-Secret function, as defined in
// section 7.1 of draft ietf-tls-tls13-16.
func (h *finishedHash) deriveSecret(secret, label []byte) []byte {
- if h.resumptionContextHash == nil {
- panic("Resumption context not set.")
- }
-
return hkdfExpandLabel(h.hash, secret, label, h.appendContextHashes(nil), h.hash.Size())
}
@@ -442,6 +428,7 @@ func (h *finishedHash) deriveSecret(secret, label []byte) []byte {
var (
clientCertificateVerifyContextTLS13 = []byte("TLS 1.3, client CertificateVerify")
serverCertificateVerifyContextTLS13 = []byte("TLS 1.3, server CertificateVerify")
+ channelIDContextTLS13 = []byte("TLS 1.3, Channel ID")
)
// certificateVerifyMessage returns the input to be signed for CertificateVerify
@@ -458,14 +445,6 @@ func (h *finishedHash) certificateVerifyInput(context []byte) []byte {
return b
}
-// The following are phase values for traffic key derivation in TLS 1.3.
-var (
- earlyHandshakePhase = []byte("early handshake key expansion")
- earlyApplicationPhase = []byte("early application data key expansion")
- handshakePhase = []byte("handshake key expansion")
- applicationPhase = []byte("application data key expansion")
-)
-
type trafficDirection int
const (
@@ -473,17 +452,16 @@ const (
serverWrite
)
+var (
+ keyTLS13 = []byte("key")
+ ivTLS13 = []byte("iv")
+)
+
// deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic
// secret.
-func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) interface{} {
- label := make([]byte, 0, len(phase)+2+16)
- label = append(label, phase...)
- label = append(label, []byte(", key")...)
- key := hkdfExpandLabel(suite.hash(), secret, label, nil, suite.keyLen)
-
- label = label[:len(label)-3] // Remove "key" from the end.
- label = append(label, []byte("iv")...)
- iv := hkdfExpandLabel(suite.hash(), secret, label, nil, suite.ivLen(version))
+func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret []byte, side trafficDirection) interface{} {
+ key := hkdfExpandLabel(suite.hash(), secret, keyTLS13, nil, suite.keyLen)
+ iv := hkdfExpandLabel(suite.hash(), secret, ivTLS13, nil, suite.ivLen(version))
return suite.aead(version, key, iv)
}
@@ -492,10 +470,11 @@ func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte {
return hkdfExpandLabel(hash, secret, applicationTrafficLabel, nil, hash.Size())
}
-func deriveResumptionPSK(suite *cipherSuite, resumptionSecret []byte) []byte {
- return hkdfExpandLabel(suite.hash(), resumptionSecret, []byte("resumption psk"), nil, suite.hash().Size())
-}
-
-func deriveResumptionContext(suite *cipherSuite, resumptionSecret []byte) []byte {
- return hkdfExpandLabel(suite.hash(), resumptionSecret, []byte("resumption context"), nil, suite.hash().Size())
+func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte {
+ finishedHash := newFinishedHash(VersionTLS13, cipherSuite)
+ earlySecret := finishedHash.extractKey(finishedHash.zeroSecret(), psk)
+ binderKey := finishedHash.deriveSecret(earlySecret, label)
+ finishedHash.Write(transcript)
+ finishedHash.Write(truncatedHello)
+ return finishedHash.clientSum(binderKey)
}
diff --git a/src/ssl/test/runner/rsa_chain_cert.pem b/src/ssl/test/runner/rsa_chain_cert.pem
new file mode 100644
index 00000000..8eb6e60e
--- /dev/null
+++ b/src/ssl/test/runner/rsa_chain_cert.pem
@@ -0,0 +1,35 @@
+-----BEGIN CERTIFICATE-----
+MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD
+QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs
+aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8
+CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/
+kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3
+tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c
+IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1
+z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V
+iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw
+rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7
+AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w
+giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW
+ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK
+MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC
+1ngWZ7Ih
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS
+b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE
+AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D
+GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ
+3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l
+HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF
+Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7
+6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM
+cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ
+BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1
+QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye
+NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b
+WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv
+XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4=
+-----END CERTIFICATE-----
diff --git a/src/ssl/test/runner/rsa_chain_key.pem b/src/ssl/test/runner/rsa_chain_key.pem
new file mode 100644
index 00000000..d94d7044
--- /dev/null
+++ b/src/ssl/test/runner/rsa_chain_key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC
+afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M
+/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P
+Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l
+P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50
+Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ
+i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0
+YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk
+wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe
+iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ
+HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9
+042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn
+1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f
+CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE
+NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f
+AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z
+YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt
+Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA
+UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP
+2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS
+fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy
+xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN
+FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ
+2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk
+buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi
+SxpiPQ8d/hmSGwn4ksrWUsJD
+-----END PRIVATE KEY-----
diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go
index 367fef1b..683f07cb 100644
--- a/src/ssl/test/runner/runner.go
+++ b/src/ssl/test/runner/runner.go
@@ -62,6 +62,7 @@ var (
looseErrors = flag.Bool("loose-errors", false, "If true, allow shims to report an untranslated error code.")
shimConfigFile = flag.String("shim-config", "", "A config file to use to configure the tests for this shim.")
includeDisabled = flag.Bool("include-disabled", false, "If true, also runs disabled tests.")
+ repeatUntilFailure = flag.Bool("repeat-until-failure", false, "If true, the first selected test will be run repeatedly until failure.")
)
// ShimConfigurations is used with the “json” package and represents a shim
@@ -87,6 +88,7 @@ type testCert int
const (
testCertRSA testCert = iota
testCertRSA1024
+ testCertRSAChain
testCertECDSAP256
testCertECDSAP384
testCertECDSAP521
@@ -95,6 +97,7 @@ const (
const (
rsaCertificateFile = "cert.pem"
rsa1024CertificateFile = "rsa_1024_cert.pem"
+ rsaChainCertificateFile = "rsa_chain_cert.pem"
ecdsaP256CertificateFile = "ecdsa_p256_cert.pem"
ecdsaP384CertificateFile = "ecdsa_p384_cert.pem"
ecdsaP521CertificateFile = "ecdsa_p521_cert.pem"
@@ -103,6 +106,7 @@ const (
const (
rsaKeyFile = "key.pem"
rsa1024KeyFile = "rsa_1024_key.pem"
+ rsaChainKeyFile = "rsa_chain_key.pem"
ecdsaP256KeyFile = "ecdsa_p256_key.pem"
ecdsaP384KeyFile = "ecdsa_p384_key.pem"
ecdsaP521KeyFile = "ecdsa_p521_key.pem"
@@ -112,6 +116,7 @@ const (
var (
rsaCertificate Certificate
rsa1024Certificate Certificate
+ rsaChainCertificate Certificate
ecdsaP256Certificate Certificate
ecdsaP384Certificate Certificate
ecdsaP521Certificate Certificate
@@ -135,6 +140,12 @@ var testCerts = []struct {
cert: &rsa1024Certificate,
},
{
+ id: testCertRSAChain,
+ certFile: rsaChainCertificateFile,
+ keyFile: rsaChainKeyFile,
+ cert: &rsaChainCertificate,
+ },
+ {
id: testCertECDSAP256,
certFile: ecdsaP256CertificateFile,
keyFile: ecdsaP256KeyFile,
@@ -158,7 +169,10 @@ var channelIDKey *ecdsa.PrivateKey
var channelIDBytes []byte
var testOCSPResponse = []byte{1, 2, 3, 4}
-var testSCTList = []byte{5, 6, 7, 8}
+var testSCTList = []byte{0, 6, 0, 4, 5, 6, 7, 8}
+
+var testOCSPExtension = append([]byte{byte(extensionStatusRequest) >> 8, byte(extensionStatusRequest), 0, 8, statusTypeOCSP, 0, 0, 4}, testOCSPResponse...)
+var testSCTExtension = append([]byte{byte(extensionSignedCertificateTimestamp) >> 8, byte(extensionSignedCertificateTimestamp), 0, byte(len(testSCTList))}, testSCTList...)
func initCertificates() {
for i := range testCerts {
@@ -364,6 +378,9 @@ type testCase struct {
// expectMessageDropped, if true, means the test message is expected to
// be dropped by the client rather than echoed back.
expectMessageDropped bool
+ // expectPeerCertificate, if not nil, is the certificate chain the peer
+ // is expected to send.
+ expectPeerCertificate *Certificate
}
var testCases []testCase
@@ -581,6 +598,17 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, nu
return fmt.Errorf("expected peer to use curve %04x, but got %04x", expected, connState.CurveID)
}
+ if test.expectPeerCertificate != nil {
+ if len(connState.PeerCertificates) != len(test.expectPeerCertificate.Certificate) {
+ return fmt.Errorf("expected peer to send %d certificates, but got %d", len(connState.PeerCertificates), len(test.expectPeerCertificate.Certificate))
+ }
+ for i, cert := range connState.PeerCertificates {
+ if !bytes.Equal(cert.Raw, test.expectPeerCertificate.Certificate[i]) {
+ return fmt.Errorf("peer certificate %d did not match", i+1)
+ }
+ }
+ }
+
if test.exportKeyingMaterial > 0 {
actual := make([]byte, test.exportKeyingMaterial)
if _, err := io.ReadFull(tlsConn, actual); err != nil {
@@ -1682,6 +1710,50 @@ func addBasicTests() {
expectedLocalError: "remote error: handshake failure",
},
{
+ name: "FailCertCallback-Client-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ testType: serverTest,
+ name: "FailCertCallback-Server-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ name: "FailCertCallback-Client-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequestClientCert,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
+ testType: serverTest,
+ name: "FailCertCallback-Server-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ flags: []string{"-fail-cert-callback"},
+ shouldFail: true,
+ expectedError: ":CERT_CB_ERROR:",
+ expectedLocalError: "remote error: internal error",
+ },
+ {
protocol: dtls,
name: "FragmentMessageTypeMismatch-DTLS",
config: Config{
@@ -2299,10 +2371,13 @@ func addBasicTests() {
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
+ // TLS 1.3 servers are expected to
+ // always enable GREASE. TLS 1.3 is new,
+ // so there is no existing ecosystem to
+ // worry about.
ExpectGREASE: true,
},
},
- flags: []string{"-enable-grease"},
},
}
testCases = append(testCases, basicTests...)
@@ -2485,7 +2560,8 @@ func addCipherSuiteTests() {
if !shouldClientFail {
// Ensure the maximum record size is accepted.
testCases = append(testCases, testCase{
- name: prefix + ver.name + "-" + suite.name + "-LargeRecord",
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-LargeRecord",
config: Config{
MinVersion: ver.version,
MaxVersion: ver.version,
@@ -2497,6 +2573,33 @@ func addCipherSuiteTests() {
flags: flags,
messageLen: maxPlaintext,
})
+
+ // Test bad records for all ciphers. Bad records are fatal in TLS
+ // and ignored in DTLS.
+ var shouldFail bool
+ var expectedError string
+ if protocol == tls {
+ shouldFail = true
+ expectedError = ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:"
+ }
+
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ name: prefix + ver.name + "-" + suite.name + "-BadRecord",
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ CipherSuites: []uint16{suite.id},
+ Certificates: []Certificate{cert},
+ PreSharedKey: []byte(psk),
+ PreSharedKeyIdentity: pskIdentity,
+ },
+ flags: flags,
+ damageFirstWrite: true,
+ messageLen: maxPlaintext,
+ shouldFail: shouldFail,
+ expectedError: expectedError,
+ })
}
}
}
@@ -3940,33 +4043,54 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) {
},
})
- // Client sends a Channel ID.
- tests = append(tests, testCase{
- name: "ChannelID-Client",
- config: Config{
- MaxVersion: VersionTLS12,
- RequestChannelID: true,
- },
- flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
- resumeSession: true,
- expectChannelID: true,
- })
+ // Test Channel ID
+ for _, ver := range tlsVersions {
+ if ver.version < VersionTLS10 {
+ continue
+ }
+ // Client sends a Channel ID.
+ tests = append(tests, testCase{
+ name: "ChannelID-Client-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ RequestChannelID: true,
+ },
+ flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
+ resumeSession: true,
+ expectChannelID: true,
+ })
- // Server accepts a Channel ID.
- tests = append(tests, testCase{
- testType: serverTest,
- name: "ChannelID-Server",
- config: Config{
- MaxVersion: VersionTLS12,
- ChannelID: channelIDKey,
- },
- flags: []string{
- "-expect-channel-id",
- base64.StdEncoding.EncodeToString(channelIDBytes),
- },
- resumeSession: true,
- expectChannelID: true,
- })
+ // Server accepts a Channel ID.
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "ChannelID-Server-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ ChannelID: channelIDKey,
+ },
+ flags: []string{
+ "-expect-channel-id",
+ base64.StdEncoding.EncodeToString(channelIDBytes),
+ },
+ resumeSession: true,
+ expectChannelID: true,
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
+ name: "InvalidChannelIDSignature-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ ChannelID: channelIDKey,
+ Bugs: ProtocolBugs{
+ InvalidChannelIDSignature: true,
+ },
+ },
+ flags: []string{"-enable-channel-id"},
+ shouldFail: true,
+ expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
+ })
+ }
// Channel ID and NPN at the same time, to ensure their relative
// ordering is correct.
@@ -4333,6 +4457,19 @@ func addVersionNegotiationTests() {
expectedVersion: VersionTLS12,
})
+ // Test that the maximum version is selected regardless of the
+ // client-sent order.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "IgnoreClientVersionOrder",
+ config: Config{
+ Bugs: ProtocolBugs{
+ SendSupportedVersions: []uint16{VersionTLS12, tls13DraftVersion},
+ },
+ },
+ expectedVersion: VersionTLS13,
+ })
+
// Test for version tolerance.
testCases = append(testCases, testCase{
testType: serverTest,
@@ -4715,6 +4852,8 @@ func addExtensionTests() {
config: Config{
MaxVersion: ver.version,
NextProtos: []string{"foo", "bar", "baz"},
+ // Prior to TLS 1.3, exercise the asynchronous session callback.
+ SessionTicketsDisabled: ver.version < VersionTLS13,
},
flags: []string{
"-expect-advertised-alpn", "\x03foo\x03bar\x03baz",
@@ -4859,7 +4998,10 @@ func addExtensionTests() {
config: Config{
MaxVersion: ver.version,
Bugs: ProtocolBugs{
- CorruptTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in[len(in)-1] ^= 1
+ return in, nil
+ },
},
},
resumeSession: true,
@@ -4897,7 +5039,10 @@ func addExtensionTests() {
config: Config{
MaxVersion: ver.version,
Bugs: ProtocolBugs{
- CorruptTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in[len(in)-1] ^= 1
+ return in, nil
+ },
},
},
resumeSession: true,
@@ -5024,6 +5169,10 @@ func addExtensionTests() {
resumeSession: true,
})
+ var differentSCTList []byte
+ differentSCTList = append(differentSCTList, testSCTList...)
+ differentSCTList[len(differentSCTList)-1] ^= 1
+
// The SCT extension did not specify that it must only be sent on resumption as it
// should have, so test that we tolerate but ignore it.
testCases = append(testCases, testCase{
@@ -5031,7 +5180,7 @@ func addExtensionTests() {
config: Config{
MaxVersion: ver.version,
Bugs: ProtocolBugs{
- SendSCTListOnResume: []byte("bogus"),
+ SendSCTListOnResume: differentSCTList,
},
},
flags: []string{
@@ -5055,6 +5204,61 @@ func addExtensionTests() {
expectedSCTList: testSCTList,
resumeSession: true,
})
+
+ emptySCTListCert := *testCerts[0].cert
+ emptySCTListCert.SignedCertificateTimestampList = []byte{0, 0}
+
+ // Test empty SCT list.
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListEmpty-Client-" + ver.name,
+ testType: clientTest,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{emptySCTListCert},
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ emptySCTCert := *testCerts[0].cert
+ emptySCTCert.SignedCertificateTimestampList = []byte{0, 6, 0, 2, 1, 2, 0, 0}
+
+ // Test empty SCT in non-empty list.
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListEmptySCT-Client-" + ver.name,
+ testType: clientTest,
+ config: Config{
+ MaxVersion: ver.version,
+ Certificates: []Certificate{emptySCTCert},
+ },
+ flags: []string{
+ "-enable-signed-cert-timestamps",
+ },
+ shouldFail: true,
+ expectedError: ":ERROR_PARSING_EXTENSION:",
+ })
+
+ // Test that certificate-related extensions are not sent unsolicited.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "UnsolicitedCertificateExtensions-" + ver.name,
+ config: Config{
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ NoOCSPStapling: true,
+ NoSignedCertificateTimestamps: true,
+ },
+ },
+ flags: []string{
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
}
testCases = append(testCases, testCase{
@@ -5171,19 +5375,6 @@ func addExtensionTests() {
expectedError: ":ERROR_PARSING_EXTENSION:",
})
testCases = append(testCases, testCase{
- name: "ChannelID-Forbidden-TLS13",
- config: Config{
- MaxVersion: VersionTLS13,
- RequestChannelID: true,
- Bugs: ProtocolBugs{
- NegotiateChannelIDAtAllVersions: true,
- },
- },
- flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)},
- shouldFail: true,
- expectedError: ":ERROR_PARSING_EXTENSION:",
- })
- testCases = append(testCases, testCase{
name: "Ticket-Forbidden-TLS13",
config: Config{
MaxVersion: VersionTLS12,
@@ -5205,74 +5396,180 @@ func addExtensionTests() {
// implicit in every test.)
testCases = append(testCases, testCase{
testType: serverTest,
- name: "ChannelID-Declined-TLS13",
+ name: "NPN-Declined-TLS13",
config: Config{
MaxVersion: VersionTLS13,
- ChannelID: channelIDKey,
+ NextProtos: []string{"bar"},
},
- flags: []string{"-enable-channel-id"},
+ flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
})
+
+ // OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is
+ // tolerated.
testCases = append(testCases, testCase{
- testType: serverTest,
- name: "NPN-Declined-TLS13",
+ name: "SendOCSPResponseOnResume-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendOCSPResponseOnResume: []byte("bogus"),
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-expect-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ },
+ resumeSession: true,
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendUnsolicitedOCSPOnCertificate-TLS13",
config: Config{
MaxVersion: VersionTLS13,
- NextProtos: []string{"bar"},
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: testOCSPExtension,
+ },
},
- flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"},
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendUnsolicitedSCTOnCertificate-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendExtensionOnCertificate: testSCTExtension,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
})
+ // Test that extensions on client certificates are never accepted.
testCases = append(testCases, testCase{
+ name: "SendExtensionOnClientCertificate-TLS13",
testType: serverTest,
- name: "InvalidChannelIDSignature",
config: Config{
- MaxVersion: VersionTLS12,
- ChannelID: channelIDKey,
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaCertificate},
Bugs: ProtocolBugs{
- InvalidChannelIDSignature: true,
+ SendExtensionOnCertificate: testOCSPExtension,
},
},
- flags: []string{"-enable-channel-id"},
- shouldFail: true,
- expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:",
- expectedLocalError: "remote error: error decrypting message",
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-require-any-client-certificate",
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
})
- // OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is
- // tolerated.
testCases = append(testCases, testCase{
- name: "SendOCSPResponseOnResume-TLS12",
+ name: "SendUnknownExtensionOnCertificate-TLS13",
config: Config{
- MaxVersion: VersionTLS12,
+ MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendOCSPResponseOnResume: []byte("bogus"),
+ SendExtensionOnCertificate: []byte{0x00, 0x7f, 0, 0},
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ var differentSCTList []byte
+ differentSCTList = append(differentSCTList, testSCTList...)
+ differentSCTList[len(differentSCTList)-1] ^= 1
+
+ // Test that extensions on intermediates are allowed but ignored.
+ testCases = append(testCases, testCase{
+ name: "IgnoreExtensionsOnIntermediates-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Certificates: []Certificate{rsaChainCertificate},
+ Bugs: ProtocolBugs{
+ // Send different values on the intermediate. This tests
+ // the intermediate's extensions do not override the
+ // leaf's.
+ SendOCSPOnIntermediates: []byte{1, 3, 3, 7},
+ SendSCTOnIntermediates: differentSCTList,
},
},
flags: []string{
"-enable-ocsp-stapling",
"-expect-ocsp-response",
base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-enable-signed-cert-timestamps",
+ "-expect-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
},
resumeSession: true,
})
- // Beginning TLS 1.3, enforce this does not happen.
+ // Test that extensions are not sent on intermediates when configured
+ // only for a leaf.
testCases = append(testCases, testCase{
- name: "SendOCSPResponseOnResume-TLS13",
+ testType: serverTest,
+ name: "SendNoExtensionsOnIntermediate-TLS13",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendOCSPResponseOnResume: []byte("bogus"),
+ ExpectNoExtensionsOnIntermediate: true,
},
},
flags: []string{
- "-enable-ocsp-stapling",
- "-expect-ocsp-response",
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-ocsp-response",
base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
+
+ // Test that extensions are not sent on client certificates.
+ testCases = append(testCases, testCase{
+ name: "SendNoClientCertificateExtensions-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ ClientAuth: RequireAnyClientCert,
+ },
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaKeyFile),
+ "-ocsp-response",
+ base64.StdEncoding.EncodeToString(testOCSPResponse),
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString(testSCTList),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SendDuplicateExtensionsOnCerts-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendDuplicateCertExtensions: true,
+ },
+ },
+ flags: []string{
+ "-enable-ocsp-stapling",
+ "-enable-signed-cert-timestamps",
},
resumeSession: true,
shouldFail: true,
- expectedError: ":ERROR_PARSING_EXTENSION:",
+ expectedError: ":DUPLICATE_EXTENSION:",
+ })
+
+ testCases = append(testCases, testCase{
+ name: "SignedCertificateTimestampListInvalid-Server",
+ testType: serverTest,
+ flags: []string{
+ "-signed-cert-timestamps",
+ base64.StdEncoding.EncodeToString([]byte{0, 0}),
+ },
+ shouldFail: true,
+ expectedError: ":INVALID_SCT_LIST:",
})
}
@@ -5381,6 +5678,223 @@ func addResumptionVersionTests() {
}
}
+ // Make sure shim ticket mutations are functional.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "ShimTicketRewritable",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ in, err := SetShimTicketVersion(in, VersionTLS12)
+ if err != nil {
+ return nil, err
+ }
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ })
+
+ // Resumptions are declined if the version does not match.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineCrossVersion",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketVersion(in, VersionTLS13)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineCrossVersion-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketVersion(in, VersionTLS12)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // Resumptions are declined if the cipher is invalid or disabled.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher-2",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384)
+ },
+ },
+ },
+ flags: []string{
+ "-cipher", "AES128",
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // Sessions are not resumed if they do not use the preferred cipher.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-CipherNotPreferred",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ ExpectNewTicket: true,
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ shouldFail: false,
+ expectResumeRejected: true,
+ })
+
+ // TLS 1.3 allows sessions to be resumed at a different cipher if their
+ // PRF hashes match, but BoringSSL will always decline such resumptions.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-CipherNotPreferred-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256, TLS_AES_128_GCM_SHA256},
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ // If the client (runner) offers ChaCha20-Poly1305 first, the
+ // server (shim) always prefers it. Switch it to AES-GCM.
+ return SetShimTicketCipherSuite(in, TLS_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ shouldFail: false,
+ expectResumeRejected: true,
+ })
+
+ // Sessions may not be resumed if they contain another version's cipher.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-DeclineBadCipher-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ FilterTicket: func(in []byte) ([]byte, error) {
+ return SetShimTicketCipherSuite(in, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+ },
+ },
+ },
+ flags: []string{
+ "-ticket-key",
+ base64.StdEncoding.EncodeToString(TestShimTicketKey),
+ },
+ expectResumeRejected: true,
+ })
+
+ // If the client does not offer the cipher from the session, decline to
+ // resume. Clients are forbidden from doing this, but BoringSSL selects
+ // the cipher first, so we only decline.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-UnofferedCipher",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ },
+ expectResumeRejected: true,
+ })
+
+ // In TLS 1.3, clients may advertise a cipher list which does not
+ // include the selected cipher. Test that we tolerate this. Servers may
+ // resume at another cipher if the PRF matches, but BoringSSL will
+ // always decline.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-UnofferedCipher-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ Bugs: ProtocolBugs{
+ SendCipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ },
+ },
+ expectResumeRejected: true,
+ })
+
+ // Sessions may not be resumed at a different cipher.
testCases = append(testCases, testCase{
name: "Resume-Client-CipherMismatch",
resumeSession: true,
@@ -5399,6 +5913,8 @@ func addResumptionVersionTests() {
expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
})
+ // Session resumption in TLS 1.3 may change the cipher suite if the PRF
+ // matches.
testCases = append(testCases, testCase{
name: "Resume-Client-CipherMismatch-TLS13",
resumeSession: true,
@@ -5408,13 +5924,87 @@ func addResumptionVersionTests() {
},
resumeConfig: &Config{
MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
+ },
+ })
+
+ // Session resumption in TLS 1.3 is forbidden if the PRF does not match.
+ testCases = append(testCases, testCase{
+ name: "Resume-Client-PRFMismatch-TLS13",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
Bugs: ProtocolBugs{
SendCipherSuite: TLS_AES_256_GCM_SHA384,
},
},
shouldFail: true,
- expectedError: ":OLD_SESSION_CIPHER_NOT_RETURNED:",
+ expectedError: ":OLD_SESSION_PRF_HASH_MISMATCH:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-BinderWrongLength",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendShortPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decrypting message",
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-NoPSKBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendNoPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decoding message",
+ expectedError: ":DECODE_ERROR:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-InvalidPSKBinder",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendInvalidPSKBinder: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: error decrypting message",
+ expectedError: ":DIGEST_CHECK_FAILED:",
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "Resume-Server-PSKBinderFirstExtension",
+ resumeSession: true,
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ PSKBinderFirst: true,
+ },
+ },
+ shouldFail: true,
+ expectedLocalError: "remote error: illegal parameter",
+ expectedError: ":PRE_SHARED_KEY_MUST_BE_LAST:",
})
}
@@ -5579,6 +6169,8 @@ func addRenegotiationTests() {
CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
Bugs: ProtocolBugs{
NegotiateVersionOnRenego: VersionTLS11,
+ // Avoid failing early at the record layer.
+ SendRecordVersion: VersionTLS12,
},
},
renegotiate: 1,
@@ -6874,6 +7466,7 @@ func addExportKeyingMaterialTests() {
useExportContext: true,
})
}
+
testCases = append(testCases, testCase{
name: "ExportKeyingMaterial-SSL3",
config: Config{
@@ -6886,6 +7479,47 @@ func addExportKeyingMaterialTests() {
shouldFail: true,
expectedError: "failed to export keying material",
})
+
+ // Exporters work during a False Start.
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-FalseStart",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"foo"},
+ Bugs: ProtocolBugs{
+ ExpectFalseStart: true,
+ },
+ },
+ flags: []string{
+ "-false-start",
+ "-advertise-alpn", "\x03foo",
+ },
+ shimWritesFirst: true,
+ exportKeyingMaterial: 1024,
+ exportLabel: "label",
+ exportContext: "context",
+ useExportContext: true,
+ })
+
+ // Exporters do not work in the middle of a renegotiation. Test this by
+ // triggering the exporter after every SSL_read call and configuring the
+ // shim to run asynchronously.
+ testCases = append(testCases, testCase{
+ name: "ExportKeyingMaterial-Renegotiate",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ },
+ renegotiate: 1,
+ flags: []string{
+ "-async",
+ "-use-exporter-between-reads",
+ "-renegotiate-freely",
+ "-expect-total-renegotiations", "1",
+ },
+ shouldFail: true,
+ expectedError: "failed to export keying material",
+ })
}
func addTLSUniqueTests() {
@@ -7636,81 +8270,73 @@ func addSessionTicketTests() {
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a},
- SendPSKAuthModes: []byte{0x1a, pskAuthMode, 0x2a},
},
},
resumeSession: true,
expectedResumeVersion: VersionTLS13,
})
- // Test that the server declines sessions with no matching key exchange mode.
+ // Test that the server does not send session tickets with no matching key exchange mode.
testCases = append(testCases, testCase{
testType: serverTest,
- name: "TLS13-SendBadKEModeSessionTicket-Server",
+ name: "TLS13-ExpectNoSessionTicketOnBadKEMode-Server",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendPSKKeyExchangeModes: []byte{0x1a},
+ SendPSKKeyExchangeModes: []byte{0x1a},
+ ExpectNoNewSessionTicket: true,
},
},
- resumeSession: true,
- expectResumeRejected: true,
})
- // Test that the server declines sessions with no matching auth mode.
+ // Test that the server does not accept a session with no matching key exchange mode.
testCases = append(testCases, testCase{
testType: serverTest,
- name: "TLS13-SendBadAuthModeSessionTicket-Server",
+ name: "TLS13-SendBadKEModeSessionTicket-Server",
config: Config{
MaxVersion: VersionTLS13,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendPSKAuthModes: []byte{0x1a},
+ SendPSKKeyExchangeModes: []byte{0x1a},
},
},
resumeSession: true,
expectResumeRejected: true,
})
- // Test that the client ignores unknown PSK modes.
+ // Test that the client ticket age is sent correctly.
testCases = append(testCases, testCase{
testType: clientTest,
- name: "TLS13-SendUnknownModeSessionTicket-Client",
+ name: "TLS13-TestValidTicketAge-Client",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a},
- SendPSKAuthModes: []byte{0x1a, pskAuthMode, 0x2a},
+ ExpectTicketAge: 10 * time.Second,
},
},
- resumeSession: true,
- expectedResumeVersion: VersionTLS13,
- })
-
- // Test that the client ignores tickets with no matching key exchange mode.
- testCases = append(testCases, testCase{
- testType: clientTest,
- name: "TLS13-SendBadKEModeSessionTicket-Client",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- SendPSKKeyExchangeModes: []byte{0x1a},
- },
+ resumeSession: true,
+ flags: []string{
+ "-resumption-delay", "10",
},
- flags: []string{"-expect-no-session"},
})
- // Test that the client ignores tickets with no matching auth mode.
+ // Test that the client ticket age is enforced.
testCases = append(testCases, testCase{
testType: clientTest,
- name: "TLS13-SendBadAuthModeSessionTicket-Client",
+ name: "TLS13-TestBadTicketAge-Client",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
- SendPSKAuthModes: []byte{0x1a},
+ ExpectTicketAge: 1000 * time.Second,
},
},
- flags: []string{"-expect-no-session"},
+ resumeSession: true,
+ shouldFail: true,
+ expectedLocalError: "tls: invalid ticket age",
})
+
}
func addChangeCipherSpecTests() {
@@ -8369,33 +8995,6 @@ func addTLS13HandshakeTests() {
testCases = append(testCases, testCase{
testType: clientTest,
- name: "OmitServerHelloSignatureAlgorithms",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- OmitServerHelloSignatureAlgorithms: true,
- },
- },
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
-
- testCases = append(testCases, testCase{
- testType: clientTest,
- name: "IncludeServerHelloSignatureAlgorithms",
- config: Config{
- MaxVersion: VersionTLS13,
- Bugs: ProtocolBugs{
- IncludeServerHelloSignatureAlgorithms: true,
- },
- },
- resumeSession: true,
- shouldFail: true,
- expectedError: ":UNEXPECTED_EXTENSION:",
- })
-
- testCases = append(testCases, testCase{
- testType: clientTest,
name: "MissingKeyShare-Client",
config: Config{
MaxVersion: VersionTLS13,
@@ -8759,6 +9358,18 @@ func addTLS13HandshakeTests() {
expectedError: ":PSK_IDENTITY_NOT_FOUND:",
})
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-ExtraPSKIdentity",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ ExtraPSKIdentity: true,
+ },
+ },
+ resumeSession: true,
+ })
+
// Test that unknown NewSessionTicket extensions are tolerated.
testCases = append(testCases, testCase{
name: "TLS13-CustomTicketExtension",
@@ -8771,6 +9382,58 @@ func addTLS13HandshakeTests() {
})
}
+func addTLS13CipherPreferenceTests() {
+ // Test that client preference is honored if the shim has AES hardware
+ // and ChaCha20-Poly1305 is preferred otherwise.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-CipherPreference-Server-ChaCha20-AES",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ },
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-CipherPreference-Server-AES-ChaCha20",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ CipherSuites: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+
+ // Test that the client orders ChaCha20-Poly1305 and AES-GCM based on
+ // whether it has AES hardware.
+ testCases = append(testCases, testCase{
+ name: "TLS13-CipherPreference-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ // Use the client cipher order. (This is the default but
+ // is listed to be explicit.)
+ PreferServerCipherSuites: false,
+ },
+ flags: []string{
+ "-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
+ "-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
+ },
+ })
+}
+
func addPeekTests() {
// Test SSL_peek works, including on empty records.
testCases = append(testCases, testCase{
@@ -8841,16 +9504,177 @@ func addPeekTests() {
})
}
+func addRecordVersionTests() {
+ for _, ver := range tlsVersions {
+ // Test that the record version is enforced.
+ testCases = append(testCases, testCase{
+ name: "CheckRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendRecordVersion: 0x03ff,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ })
+
+ // Test that the ClientHello may use any record version, for
+ // compatibility reasons.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "LooseInitialRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendInitialRecordVersion: 0x03ff,
+ },
+ },
+ })
+
+ // Test that garbage ClientHello record versions are rejected.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "GarbageInitialRecordVersion-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Bugs: ProtocolBugs{
+ SendInitialRecordVersion: 0xffff,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":WRONG_VERSION_NUMBER:",
+ })
+ }
+}
+
+func addCertificateTests() {
+ // Test that a certificate chain with intermediate may be sent and
+ // received as both client and server.
+ for _, ver := range tlsVersions {
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "SendReceiveIntermediate-Client-" + ver.name,
+ config: Config{
+ Certificates: []Certificate{rsaChainCertificate},
+ ClientAuth: RequireAnyClientCert,
+ },
+ expectPeerCertificate: &rsaChainCertificate,
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "SendReceiveIntermediate-Server-" + ver.name,
+ config: Config{
+ Certificates: []Certificate{rsaChainCertificate},
+ },
+ expectPeerCertificate: &rsaChainCertificate,
+ flags: []string{
+ "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ "-key-file", path.Join(*resourceDir, rsaChainKeyFile),
+ "-require-any-client-certificate",
+ "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile),
+ },
+ })
+ }
+}
+
+func addRetainOnlySHA256ClientCertTests() {
+ for _, ver := range tlsVersions {
+ // Test that enabling
+ // SSL_CTX_set_retain_only_sha256_of_client_certs without
+ // actually requesting a client certificate is a no-op.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-NoCert-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ },
+ flags: []string{
+ "-retain-only-sha256-client-cert-initial",
+ "-retain-only-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ })
+
+ // Test that when retaining only a SHA-256 certificate is
+ // enabled, the hash appears as expected.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-Cert-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-initial",
+ "-retain-only-sha256-client-cert-resume",
+ "-expect-sha256-client-cert-initial",
+ "-expect-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ })
+
+ // Test that when the config changes from on to off, a
+ // resumption is rejected because the server now wants the full
+ // certificate chain.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-OnOff-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-initial",
+ "-expect-sha256-client-cert-initial",
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+
+ // Test that when the config changes from off to on, a
+ // resumption is rejected because the server now wants just the
+ // hash.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "RetainOnlySHA256-OffOn-" + ver.name,
+ config: Config{
+ MinVersion: ver.version,
+ MaxVersion: ver.version,
+ Certificates: []Certificate{rsaCertificate},
+ },
+ flags: []string{
+ "-verify-peer",
+ "-retain-only-sha256-client-cert-resume",
+ "-expect-sha256-client-cert-resume",
+ },
+ resumeSession: true,
+ expectResumeRejected: true,
+ })
+ }
+}
+
func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) {
defer wg.Done()
for test := range c {
var err error
- if *mallocTest < 0 {
- statusChan <- statusMsg{test: test, started: true}
- err = runTest(test, shimPath, -1)
- } else {
+ if *mallocTest >= 0 {
for mallocNumToFail := int64(*mallocTest); ; mallocNumToFail++ {
statusChan <- statusMsg{test: test, started: true}
if err = runTest(test, shimPath, mallocNumToFail); err != errMoreMallocs {
@@ -8860,6 +9684,14 @@ func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sy
break
}
}
+ } else if *repeatUntilFailure {
+ for err == nil {
+ statusChan <- statusMsg{test: test, started: true}
+ err = runTest(test, shimPath, -1)
+ }
+ } else {
+ statusChan <- statusMsg{test: test, started: true}
+ err = runTest(test, shimPath, -1)
}
statusChan <- statusMsg{test: test, err: err}
}
@@ -8958,7 +9790,11 @@ func main() {
addWrongMessageTypeTests()
addTrailingMessageDataTests()
addTLS13HandshakeTests()
+ addTLS13CipherPreferenceTests()
addPeekTests()
+ addRecordVersionTests()
+ addCertificateTests()
+ addRetainOnlySHA256ClientCertTests()
var wg sync.WaitGroup
@@ -9016,6 +9852,11 @@ func main() {
if matched {
foundTest = true
testChan <- &testCases[i]
+
+ // Only run one test if repeating until failure.
+ if *repeatUntilFailure {
+ break
+ }
}
}
diff --git a/src/ssl/test/runner/shim_ticket.go b/src/ssl/test/runner/shim_ticket.go
new file mode 100644
index 00000000..9e57d482
--- /dev/null
+++ b/src/ssl/test/runner/shim_ticket.go
@@ -0,0 +1,249 @@
+// Copyright (c) 2016, Google Inc.
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+package runner
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha256"
+ "encoding/asn1"
+ "errors"
+)
+
+// TestShimTicketKey is the testing key assumed for the shim.
+var TestShimTicketKey = make([]byte, 48)
+
+func DecryptShimTicket(in []byte) ([]byte, error) {
+ name := TestShimTicketKey[:16]
+ macKey := TestShimTicketKey[16:32]
+ encKey := TestShimTicketKey[32:48]
+
+ h := hmac.New(sha256.New, macKey)
+
+ block, err := aes.NewCipher(encKey)
+ if err != nil {
+ panic(err)
+ }
+
+ if len(in) < len(name)+block.BlockSize()+1+h.Size() {
+ return nil, errors.New("tls: shim ticket too short")
+ }
+
+ // Check the key name.
+ if !bytes.Equal(name, in[:len(name)]) {
+ return nil, errors.New("tls: shim ticket name mismatch")
+ }
+
+ // Check the MAC at the end of the ticket.
+ mac := in[len(in)-h.Size():]
+ in = in[:len(in)-h.Size()]
+ h.Write(in)
+ if !hmac.Equal(mac, h.Sum(nil)) {
+ return nil, errors.New("tls: shim ticket MAC mismatch")
+ }
+
+ // The MAC covers the key name, but the encryption does not.
+ in = in[len(name):]
+
+ // Decrypt in-place.
+ iv := in[:block.BlockSize()]
+ in = in[block.BlockSize():]
+ if l := len(in); l == 0 || l%block.BlockSize() != 0 {
+ return nil, errors.New("tls: ticket ciphertext not a multiple of the block size")
+ }
+ out := make([]byte, len(in))
+ cbc := cipher.NewCBCDecrypter(block, iv)
+ cbc.CryptBlocks(out, in)
+
+ // Remove the padding.
+ pad := int(out[len(out)-1])
+ if pad == 0 || pad > block.BlockSize() || pad > len(in) {
+ return nil, errors.New("tls: bad shim ticket CBC pad")
+ }
+
+ for i := 0; i < pad; i++ {
+ if out[len(out)-1-i] != byte(pad) {
+ return nil, errors.New("tls: bad shim ticket CBC pad")
+ }
+ }
+
+ return out[:len(out)-pad], nil
+}
+
+func EncryptShimTicket(in []byte) []byte {
+ name := TestShimTicketKey[:16]
+ macKey := TestShimTicketKey[16:32]
+ encKey := TestShimTicketKey[32:48]
+
+ h := hmac.New(sha256.New, macKey)
+
+ block, err := aes.NewCipher(encKey)
+ if err != nil {
+ panic(err)
+ }
+
+ // Use the zero IV for rewritten tickets.
+ iv := make([]byte, block.BlockSize())
+ cbc := cipher.NewCBCEncrypter(block, iv)
+ pad := block.BlockSize() - (len(in) % block.BlockSize())
+
+ out := make([]byte, 0, len(name)+len(iv)+len(in)+pad+h.Size())
+ out = append(out, name...)
+ out = append(out, iv...)
+ out = append(out, in...)
+ for i := 0; i < pad; i++ {
+ out = append(out, byte(pad))
+ }
+
+ ciphertext := out[len(name)+len(iv):]
+ cbc.CryptBlocks(ciphertext, ciphertext)
+
+ h.Write(out)
+ return h.Sum(out)
+}
+
+const asn1Constructed = 0x20
+
+func parseDERElement(in []byte) (tag byte, body, rest []byte, ok bool) {
+ rest = in
+ if len(rest) < 1 {
+ return
+ }
+
+ tag = rest[0]
+ rest = rest[1:]
+
+ if tag&0x1f == 0x1f {
+ // Long-form tags not supported.
+ return
+ }
+
+ if len(rest) < 1 {
+ return
+ }
+
+ length := int(rest[0])
+ rest = rest[1:]
+ if length > 0x7f {
+ lengthLength := length & 0x7f
+ length = 0
+ if lengthLength == 0 {
+ // No indefinite-length encoding.
+ return
+ }
+
+ // Decode long-form lengths.
+ for lengthLength > 0 {
+ if len(rest) < 1 || (length<<8)>>8 != length {
+ return
+ }
+ if length == 0 && rest[0] == 0 {
+ // Length not minimally-encoded.
+ return
+ }
+ length <<= 8
+ length |= int(rest[0])
+ rest = rest[1:]
+ lengthLength--
+ }
+
+ if length < 0x80 {
+ // Length not minimally-encoded.
+ return
+ }
+ }
+
+ if len(rest) < length {
+ return
+ }
+
+ body = rest[:length]
+ rest = rest[length:]
+ ok = true
+ return
+}
+
+func SetShimTicketVersion(in []byte, vers uint16) ([]byte, error) {
+ plaintext, err := DecryptShimTicket(in)
+ if err != nil {
+ return nil, err
+ }
+
+ tag, session, _, ok := parseDERElement(plaintext)
+ if !ok || tag != asn1.TagSequence|asn1Constructed {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the session version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Next field is the protocol version.
+ tag, version, _, ok := parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // This code assumes both old and new versions are encoded in two
+ // bytes. This isn't quite right as INTEGERs are minimally-encoded, but
+ // we do not need to support other caess for now.
+ if len(version) != 2 || vers < 0x80 || vers >= 0x8000 {
+ return nil, errors.New("tls: unsupported version in shim session")
+ }
+
+ version[0] = byte(vers >> 8)
+ version[1] = byte(vers)
+
+ return EncryptShimTicket(plaintext), nil
+}
+
+func SetShimTicketCipherSuite(in []byte, id uint16) ([]byte, error) {
+ plaintext, err := DecryptShimTicket(in)
+ if err != nil {
+ return nil, err
+ }
+
+ tag, session, _, ok := parseDERElement(plaintext)
+ if !ok || tag != asn1.TagSequence|asn1Constructed {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the session version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Skip the protocol version.
+ tag, _, session, ok = parseDERElement(session)
+ if !ok || tag != asn1.TagInteger {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ // Next field is the cipher suite.
+ tag, cipherSuite, _, ok := parseDERElement(session)
+ if !ok || tag != asn1.TagOctetString || len(cipherSuite) != 2 {
+ return nil, errors.New("tls: could not decode shim session")
+ }
+
+ cipherSuite[0] = byte(id >> 8)
+ cipherSuite[1] = byte(id)
+
+ return EncryptShimTicket(plaintext), nil
+}
diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc
index 425664d4..940e676e 100644
--- a/src/ssl/test/test_config.cc
+++ b/src/ssl/test/test_config.cc
@@ -75,6 +75,7 @@ const Flag<bool> kBoolFlags[] = {
{ "-install-ddos-callback", &TestConfig::install_ddos_callback },
{ "-fail-ddos-callback", &TestConfig::fail_ddos_callback },
{ "-fail-second-ddos-callback", &TestConfig::fail_second_ddos_callback },
+ { "-fail-cert-callback", &TestConfig::fail_cert_callback },
{ "-handshake-never-done", &TestConfig::handshake_never_done },
{ "-use-export-context", &TestConfig::use_export_context },
{ "-tls-unique", &TestConfig::tls_unique },
@@ -106,6 +107,15 @@ const Flag<bool> kBoolFlags[] = {
{ "-send-alert", &TestConfig::send_alert },
{ "-peek-then-read", &TestConfig::peek_then_read },
{ "-enable-grease", &TestConfig::enable_grease },
+ { "-use-exporter-between-reads", &TestConfig::use_exporter_between_reads },
+ { "-retain-only-sha256-client-cert-initial",
+ &TestConfig::retain_only_sha256_client_cert_initial },
+ { "-retain-only-sha256-client-cert-resume",
+ &TestConfig::retain_only_sha256_client_cert_resume },
+ { "-expect-sha256-client-cert-initial",
+ &TestConfig::expect_sha256_client_cert_initial },
+ { "-expect-sha256-client-cert-resume",
+ &TestConfig::expect_sha256_client_cert_resume },
};
const Flag<std::string> kStringFlags[] = {
@@ -130,6 +140,7 @@ const Flag<std::string> kStringFlags[] = {
{ "-cipher-tls11", &TestConfig::cipher_tls11 },
{ "-export-label", &TestConfig::export_label },
{ "-export-context", &TestConfig::export_context },
+ { "-expect-peer-cert-file", &TestConfig::expect_peer_cert_file },
};
const Flag<std::string> kBase64Flags[] = {
@@ -140,6 +151,7 @@ const Flag<std::string> kBase64Flags[] = {
&TestConfig::expected_signed_cert_timestamps },
{ "-ocsp-response", &TestConfig::ocsp_response },
{ "-signed-cert-timestamps", &TestConfig::signed_cert_timestamps },
+ { "-ticket-key", &TestConfig::ticket_key },
};
const Flag<int> kIntFlags[] = {
@@ -156,6 +168,9 @@ const Flag<int> kIntFlags[] = {
{ "-expect-dhe-group-size", &TestConfig::expect_dhe_group_size },
{ "-initial-timeout-duration-ms", &TestConfig::initial_timeout_duration_ms },
{ "-max-cert-list", &TestConfig::max_cert_list },
+ { "-expect-cipher-aes", &TestConfig::expect_cipher_aes },
+ { "-expect-cipher-no-aes", &TestConfig::expect_cipher_no_aes },
+ { "-resumption-delay", &TestConfig::resumption_delay },
};
const Flag<std::vector<int>> kIntVectorFlags[] = {
diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h
index 9f742975..ed1a47bd 100644
--- a/src/ssl/test/test_config.h
+++ b/src/ssl/test/test_config.h
@@ -73,6 +73,7 @@ struct TestConfig {
bool install_ddos_callback = false;
bool fail_ddos_callback = false;
bool fail_second_ddos_callback = false;
+ bool fail_cert_callback = false;
std::string cipher;
std::string cipher_tls10;
std::string cipher_tls11;
@@ -115,6 +116,16 @@ struct TestConfig {
bool peek_then_read = false;
bool enable_grease = false;
int max_cert_list = 0;
+ std::string ticket_key;
+ bool use_exporter_between_reads = false;
+ int expect_cipher_aes = 0;
+ int expect_cipher_no_aes = 0;
+ std::string expect_peer_cert_file;
+ int resumption_delay = 0;
+ bool retain_only_sha256_client_cert_initial = false;
+ bool retain_only_sha256_client_cert_resume = false;
+ bool expect_sha256_client_cert_initial = false;
+ bool expect_sha256_client_cert_resume = false;
};
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c
index e32464d4..17f7161e 100644
--- a/src/ssl/tls13_both.c
+++ b/src/ssl/tls13_both.c
@@ -25,6 +25,7 @@
#include <openssl/x509.h>
#include <openssl/x509v3.h>
+#include "../crypto/internal.h"
#include "internal.h"
@@ -79,6 +80,11 @@ int tls13_handshake(SSL *ssl) {
hs->wait = ssl_hs_ok;
return -1;
+ case ssl_hs_channel_id_lookup:
+ ssl->rwstate = SSL_CHANNEL_ID_LOOKUP;
+ hs->wait = ssl_hs_ok;
+ return -1;
+
case ssl_hs_private_key_operation:
ssl->rwstate = SSL_PRIVATE_KEY_OPERATION;
hs->wait = ssl_hs_ok;
@@ -105,8 +111,9 @@ int tls13_handshake(SSL *ssl) {
}
}
-static int tls13_get_cert_verify_signature_input(SSL *ssl, uint8_t **out,
- size_t *out_len, int server) {
+int tls13_get_cert_verify_signature_input(
+ SSL *ssl, uint8_t **out, size_t *out_len,
+ enum ssl_cert_verify_context_t cert_verify_context) {
CBB cbb;
if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
goto err;
@@ -118,23 +125,33 @@ static int tls13_get_cert_verify_signature_input(SSL *ssl, uint8_t **out,
}
}
- if (server) {
+ const uint8_t *context;
+ size_t context_len;
+ if (cert_verify_context == ssl_cert_verify_server) {
/* Include the NUL byte. */
static const char kContext[] = "TLS 1.3, server CertificateVerify";
- if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) {
- goto err;
- }
- } else {
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else if (cert_verify_context == ssl_cert_verify_client) {
static const char kContext[] = "TLS 1.3, client CertificateVerify";
- if (!CBB_add_bytes(&cbb, (const uint8_t *)kContext, sizeof(kContext))) {
- goto err;
- }
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else if (cert_verify_context == ssl_cert_verify_channel_id) {
+ static const char kContext[] = "TLS 1.3, Channel ID";
+ context = (const uint8_t *)kContext;
+ context_len = sizeof(kContext);
+ } else {
+ goto err;
}
- uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
- size_t context_hashes_len;
- if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) ||
- !CBB_add_bytes(&cbb, context_hashes, context_hashes_len) ||
+ if (!CBB_add_bytes(&cbb, context, context_len)) {
+ goto err;
+ }
+
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+ !CBB_add_bytes(&cbb, context_hash, context_hash_len) ||
!CBB_finish(&cbb, out, out_len)) {
goto err;
}
@@ -148,7 +165,7 @@ err:
}
int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
- CBS cbs, context;
+ CBS cbs, context, certificate_list;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
if (!CBS_get_u8_length_prefixed(&cbs, &context) ||
CBS_len(&context) != 0) {
@@ -158,17 +175,117 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
}
const int retain_sha256 =
- ssl->server && ssl->ctx->retain_only_sha256_of_client_certs;
+ ssl->server && ssl->retain_only_sha256_of_client_certs;
int ret = 0;
- uint8_t alert;
- STACK_OF(X509) *chain = ssl_parse_cert_chain(
- ssl, &alert, retain_sha256 ? ssl->s3->new_session->peer_sha256 : NULL,
- &cbs);
+
+ STACK_OF(X509) *chain = sk_X509_new_null();
if (chain == NULL) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!CBS_get_u24_length_prefixed(&cbs, &certificate_list)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto err;
}
+ while (CBS_len(&certificate_list) > 0) {
+ CBS certificate, extensions;
+ if (!CBS_get_u24_length_prefixed(&certificate_list, &certificate) ||
+ !CBS_get_u16_length_prefixed(&certificate_list, &extensions)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_LENGTH_MISMATCH);
+ goto err;
+ }
+
+ /* Retain the hash of the leaf certificate if requested. */
+ if (sk_X509_num(chain) == 0 && retain_sha256) {
+ SHA256(CBS_data(&certificate), CBS_len(&certificate),
+ ssl->s3->new_session->peer_sha256);
+ }
+
+ X509 *x = ssl_parse_x509(&certificate);
+ if (x == NULL || CBS_len(&certificate) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ X509_free(x);
+ goto err;
+ }
+ if (!sk_X509_push(chain, x)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+ X509_free(x);
+ goto err;
+ }
+
+ /* Parse out the extensions. */
+ int have_status_request = 0, have_sct = 0;
+ CBS status_request, sct;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_status_request, &have_status_request, &status_request},
+ {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct},
+ };
+
+ uint8_t alert;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ goto err;
+ }
+
+ /* All Certificate extensions are parsed, but only the leaf extensions are
+ * stored. */
+ if (have_status_request) {
+ if (ssl->server || !ssl->ocsp_stapling_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ goto err;
+ }
+
+ uint8_t status_type;
+ CBS ocsp_response;
+ if (!CBS_get_u8(&status_request, &status_type) ||
+ status_type != TLSEXT_STATUSTYPE_ocsp ||
+ !CBS_get_u24_length_prefixed(&status_request, &ocsp_response) ||
+ CBS_len(&ocsp_response) == 0 ||
+ CBS_len(&status_request) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (sk_X509_num(chain) == 1 &&
+ !CBS_stow(&ocsp_response, &ssl->s3->new_session->ocsp_response,
+ &ssl->s3->new_session->ocsp_response_length)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (have_sct) {
+ if (ssl->server || !ssl->signed_cert_timestamps_enabled) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ goto err;
+ }
+
+ if (!ssl_is_sct_list_valid(&sct)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ goto err;
+ }
+
+ if (sk_X509_num(chain) == 1 &&
+ !CBS_stow(&sct,
+ &ssl->s3->new_session->tlsext_signed_cert_timestamp_list,
+ &ssl->s3->new_session
+ ->tlsext_signed_cert_timestamp_list_length)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+ }
+
if (CBS_len(&cbs) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
@@ -198,13 +315,13 @@ int tls13_process_certificate(SSL *ssl, int allow_anonymous) {
goto err;
}
- X509_free(ssl->s3->new_session->peer);
+ X509_free(ssl->s3->new_session->x509_peer);
X509 *leaf = sk_X509_value(chain, 0);
X509_up_ref(leaf);
- ssl->s3->new_session->peer = leaf;
+ ssl->s3->new_session->x509_peer = leaf;
- sk_X509_pop_free(ssl->s3->new_session->cert_chain, X509_free);
- ssl->s3->new_session->cert_chain = chain;
+ sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free);
+ ssl->s3->new_session->x509_chain = chain;
chain = NULL;
ret = 1;
@@ -216,7 +333,7 @@ err:
int tls13_process_certificate_verify(SSL *ssl) {
int ret = 0;
- X509 *peer = ssl->s3->new_session->peer;
+ X509 *peer = ssl->s3->new_session->x509_peer;
EVP_PKEY *pkey = NULL;
uint8_t *msg = NULL;
size_t msg_len;
@@ -245,8 +362,9 @@ int tls13_process_certificate_verify(SSL *ssl) {
}
ssl->s3->tmp.peer_signature_algorithm = signature_algorithm;
- if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
- !ssl->server)) {
+ if (!tls13_get_cert_verify_signature_input(
+ ssl, &msg, &msg_len,
+ ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
}
@@ -307,17 +425,79 @@ int tls13_process_finished(SSL *ssl) {
}
int tls13_prepare_certificate(SSL *ssl) {
- CBB cbb, body;
+ CBB cbb, body, certificate_list;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) ||
/* The request context is always empty in the handshake. */
!CBB_add_u8(&body, 0) ||
- !ssl_add_cert_chain(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
- CBB_cleanup(&cbb);
- return 0;
+ !CBB_add_u24_length_prefixed(&body, &certificate_list)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (!ssl_has_certificate(ssl)) {
+ if (!ssl_complete_message(ssl, &cbb)) {
+ goto err;
+ }
+
+ return 1;
+ }
+
+ CERT *cert = ssl->cert;
+ CBB leaf, extensions;
+ if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) ||
+ !ssl_add_cert_to_cbb(&leaf, cert->x509_leaf) ||
+ !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ if (ssl->s3->hs->scts_requested &&
+ ssl->ctx->signed_cert_timestamp_list_length != 0) {
+ CBB contents;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
+ !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+ !CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list,
+ ssl->ctx->signed_cert_timestamp_list_length) ||
+ !CBB_flush(&extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (ssl->s3->hs->ocsp_stapling_requested &&
+ ssl->ctx->ocsp_response_length != 0) {
+ CBB contents, ocsp_response;
+ if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) ||
+ !CBB_add_u16_length_prefixed(&extensions, &contents) ||
+ !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) ||
+ !CBB_add_u24_length_prefixed(&contents, &ocsp_response) ||
+ !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response,
+ ssl->ctx->ocsp_response_length) ||
+ !CBB_flush(&extensions)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ for (size_t i = 0; i < sk_X509_num(cert->x509_chain); i++) {
+ CBB child;
+ if (!CBB_add_u24_length_prefixed(&certificate_list, &child) ||
+ !ssl_add_cert_to_cbb(&child, sk_X509_value(cert->x509_chain, i)) ||
+ !CBB_add_u16(&certificate_list, 0 /* no extensions */)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+
+ if (!ssl_complete_message(ssl, &cbb)) {
+ goto err;
}
return 1;
+
+err:
+ CBB_cleanup(&cbb);
+ return 0;
}
enum ssl_private_key_result_t tls13_prepare_certificate_verify(
@@ -352,8 +532,9 @@ enum ssl_private_key_result_t tls13_prepare_certificate_verify(
enum ssl_private_key_result_t sign_result;
if (is_first_run) {
- if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
- ssl->server)) {
+ if (!tls13_get_cert_verify_signature_input(
+ ssl, &msg, &msg_len,
+ ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
}
@@ -369,7 +550,7 @@ enum ssl_private_key_result_t tls13_prepare_certificate_verify(
}
if (!CBB_did_write(&child, sig_len) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -394,7 +575,7 @@ int tls13_prepare_finished(SSL *ssl) {
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_FINISHED) ||
!CBB_add_bytes(&body, verify_data, verify_data_len) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
CBB_cleanup(&cbb);
return 0;
}
diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c
index 87ccdc4b..4a30ce3d 100644
--- a/src/ssl/tls13_client.c
+++ b/src/ssl/tls13_client.c
@@ -24,6 +24,7 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
+#include "../crypto/internal.h"
#include "internal.h"
@@ -41,6 +42,7 @@ enum client_hs_state_t {
state_send_client_certificate,
state_send_client_certificate_verify,
state_complete_client_certificate_verify,
+ state_send_channel_id,
state_send_client_finished,
state_flush,
state_done,
@@ -66,95 +68,71 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL *ssl,
return ssl_hs_error;
}
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ int have_cookie, have_key_share;
+ CBS cookie, key_share;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
+ };
+
+ uint8_t alert;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ if (have_cookie) {
+ CBS cookie_value;
+ if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+ CBS_len(&cookie_value) == 0 ||
+ CBS_len(&cookie) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
- switch (type) {
- case TLSEXT_TYPE_cookie: {
- if (hs->cookie != NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
- /* Cookies may be requested whether or not advertised, so no need to
- * check. */
-
- CBS cookie;
- if (!CBS_get_u16_length_prefixed(&extension, &cookie) ||
- CBS_len(&cookie) == 0 ||
- CBS_len(&extension) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- if (!CBS_stow(&cookie, &hs->cookie, &hs->cookie_len)) {
- return ssl_hs_error;
- }
- break;
- }
+ if (!CBS_stow(&cookie_value, &hs->cookie, &hs->cookie_len)) {
+ return ssl_hs_error;
+ }
+ }
+
+ if (have_key_share) {
+ uint16_t group_id;
+ if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
- case TLSEXT_TYPE_key_share: {
- if (hs->retry_group != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
- /* key_share is always advertised, so no need to check. */
-
- uint16_t group_id;
- if (!CBS_get_u16(&extension, &group_id) ||
- CBS_len(&extension) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- /* The group must be supported. */
- const uint16_t *groups;
- size_t groups_len;
- tls1_get_grouplist(ssl, &groups, &groups_len);
- int found = 0;
- for (size_t i = 0; i < groups_len; i++) {
- if (groups[i] == group_id) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
- return ssl_hs_error;
- }
-
- /* Check that the HelloRetryRequest does not request the key share that
- * was provided in the initial ClientHello. */
- if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
- return ssl_hs_error;
- }
-
- SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
- hs->retry_group = group_id;
+ /* The group must be supported. */
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+ int found = 0;
+ for (size_t i = 0; i < groups_len; i++) {
+ if (groups[i] == group_id) {
+ found = 1;
break;
}
+ }
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
+ if (!found) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
+ }
+
+ /* Check that the HelloRetryRequest does not request the key share that
+ * was provided in the initial ClientHello. */
+ if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
}
+
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ hs->retry_group = group_id;
}
hs->received_hello_retry_request = 1;
@@ -164,11 +142,7 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL *ssl,
static enum ssl_hs_wait_t do_send_second_client_hello(SSL *ssl,
SSL_HANDSHAKE *hs) {
- CBB cbb, body;
- if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CLIENT_HELLO) ||
- !ssl_add_client_hello_body(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
- CBB_cleanup(&cbb);
+ if (!ssl_write_client_hello(ssl)) {
return ssl_hs_error;
}
@@ -217,73 +191,37 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- /* Check if the cipher is disabled. */
- if ((cipher->algorithm_mkey & ssl->cert->mask_k) ||
- (cipher->algorithm_auth & ssl->cert->mask_a) ||
- SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
- SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl) ||
- !sk_SSL_CIPHER_find(ssl_get_ciphers_by_id(ssl), NULL, cipher)) {
+ /* Check if the cipher is a TLS 1.3 cipher. */
+ if (SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) ||
+ SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
/* Parse out the extensions. */
- int have_key_share = 0, have_pre_shared_key = 0, have_sigalgs = 0;
- CBS key_share, pre_shared_key, sigalgs;
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
+ int have_key_share = 0, have_pre_shared_key = 0;
+ CBS key_share, pre_shared_key;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+ };
- switch (type) {
- case TLSEXT_TYPE_key_share:
- if (have_key_share) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
- key_share = extension;
- have_key_share = 1;
- break;
- case TLSEXT_TYPE_pre_shared_key:
- if (have_pre_shared_key) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
- pre_shared_key = extension;
- have_pre_shared_key = 1;
- break;
- case TLSEXT_TYPE_signature_algorithms:
- if (have_sigalgs) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
- sigalgs = extension;
- have_sigalgs = 1;
- break;
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
+ uint8_t alert;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
}
- /* We only support PSK_AUTH and PSK_DHE_KE. */
- if (!have_key_share || have_sigalgs == have_pre_shared_key) {
+ /* We only support PSK_DHE_KE. */
+ if (!have_key_share) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- uint8_t alert = SSL_AD_DECODE_ERROR;
+ alert = SSL_AD_DECODE_ERROR;
if (have_pre_shared_key) {
if (ssl->session == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
@@ -303,8 +241,8 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (ssl->session->cipher != cipher) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+ if (ssl->session->cipher->algorithm_prf != cipher->algorithm_prf) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_PRF_HASH_MISMATCH);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
@@ -339,20 +277,17 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
/* Derive resumption material. */
- uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
if (ssl->s3->session_reused) {
- if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
- ssl->s3->new_session) ||
- !tls13_resumption_psk(ssl, psk_secret, hash_len,
- ssl->s3->new_session)) {
+ if (hash_len != (size_t) ssl->s3->new_session->master_key_length) {
return ssl_hs_error;
}
+ memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len);
}
/* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
* into the running secret. */
- if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+ if (!tls13_init_key_schedule(ssl) ||
!tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
return ssl_hs_error;
}
@@ -372,16 +307,10 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
}
OPENSSL_free(dhe_secret);
- if (have_sigalgs &&
- CBS_len(&sigalgs) != 0) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
/* If there was no HelloRetryRequest, the version negotiation logic has
* already hashed the message. */
if (hs->received_hello_retry_request &&
- !ssl->method->hash_current_message(ssl)) {
+ !ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
@@ -411,7 +340,7 @@ static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL *ssl,
return ssl_hs_error;
}
- if (!ssl->method->hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
@@ -467,7 +396,7 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl,
sk_X509_NAME_pop_free(ssl->s3->hs->ca_names, X509_NAME_free);
ssl->s3->hs->ca_names = ca_sk;
- if (!ssl->method->hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
@@ -479,7 +408,7 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL *ssl,
SSL_HANDSHAKE *hs) {
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
!tls13_process_certificate(ssl, 0 /* certificate required */) ||
- !ssl->method->hash_current_message(ssl)) {
+ !ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
@@ -491,8 +420,8 @@ static enum ssl_hs_wait_t do_process_server_certificate_verify(
SSL *ssl, SSL_HANDSHAKE *hs) {
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
!tls13_process_certificate_verify(ssl) ||
- !ssl->method->hash_current_message(ssl)) {
- return 0;
+ !ssl_hash_current_message(ssl)) {
+ return ssl_hs_error;
}
hs->state = state_process_server_finished;
@@ -504,10 +433,10 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl,
static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0};
if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) ||
!tls13_process_finished(ssl) ||
- !ssl->method->hash_current_message(ssl) ||
+ !ssl_hash_current_message(ssl) ||
/* Update the secret to the master secret and derive traffic keys. */
!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) ||
- !tls13_derive_traffic_secret_0(ssl)) {
+ !tls13_derive_application_secrets(ssl)) {
return ssl_hs_error;
}
@@ -519,7 +448,7 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl,
static enum ssl_hs_wait_t do_certificate_callback(SSL *ssl, SSL_HANDSHAKE *hs) {
/* The peer didn't request a certificate. */
if (!ssl->s3->hs->cert_request) {
- hs->state = state_send_client_finished;
+ hs->state = state_send_channel_id;
return ssl_hs_ok;
}
@@ -566,13 +495,13 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL *ssl,
int is_first_run) {
/* Don't send CertificateVerify if there is no certificate. */
if (!ssl_has_certificate(ssl)) {
- hs->state = state_send_client_finished;
+ hs->state = state_send_channel_id;
return ssl_hs_ok;
}
switch (tls13_prepare_certificate_verify(ssl, is_first_run)) {
case ssl_private_key_success:
- hs->state = state_send_client_finished;
+ hs->state = state_send_channel_id;
return ssl_hs_write_message;
case ssl_private_key_retry:
@@ -587,6 +516,32 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL *ssl,
return ssl_hs_error;
}
+static enum ssl_hs_wait_t do_send_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) {
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ hs->state = state_send_client_finished;
+ return ssl_hs_ok;
+ }
+
+ if (!ssl_do_channel_id_callback(ssl)) {
+ return ssl_hs_error;
+ }
+
+ if (ssl->tlsext_channel_id_private == NULL) {
+ return ssl_hs_channel_id_lookup;
+ }
+
+ CBB cbb, body;
+ if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
+ !tls1_write_channel_id(ssl, &body) ||
+ !ssl_complete_message(ssl, &cbb)) {
+ CBB_cleanup(&cbb);
+ return ssl_hs_error;
+ }
+
+ hs->state = state_send_client_finished;
+ return ssl_hs_write_message;
+}
+
static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) {
if (!tls13_prepare_finished(ssl)) {
return ssl_hs_error;
@@ -597,11 +552,11 @@ static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) {
}
static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) {
- if (!tls13_set_traffic_key(ssl, type_data, evp_aead_open,
- hs->server_traffic_secret_0, hs->hash_len) ||
- !tls13_set_traffic_key(ssl, type_data, evp_aead_seal,
- hs->client_traffic_secret_0, hs->hash_len) ||
- !tls13_finalize_keys(ssl)) {
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_derive_resumption_secret(ssl)) {
return ssl_hs_error;
}
@@ -651,10 +606,13 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL *ssl) {
break;
case state_send_client_certificate_verify:
ret = do_send_client_certificate_verify(ssl, hs, 1 /* first run */);
- break;
+ break;
case state_complete_client_certificate_verify:
ret = do_send_client_certificate_verify(ssl, hs, 0 /* complete */);
- break;
+ break;
+ case state_send_channel_id:
+ ret = do_send_channel_id(ssl, hs);
+ break;
case state_send_client_finished:
ret = do_send_client_finished(ssl, hs);
break;
@@ -682,13 +640,12 @@ int tls13_process_new_session_ticket(SSL *ssl) {
return 0;
}
- CBS cbs, ke_modes, auth_modes, ticket, extensions;
+ ssl_session_refresh_time(ssl, session);
+
+ CBS cbs, ticket, extensions;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
if (!CBS_get_u32(&cbs, &session->tlsext_tick_lifetime_hint) ||
- !CBS_get_u8_length_prefixed(&cbs, &ke_modes) ||
- CBS_len(&ke_modes) == 0 ||
- !CBS_get_u8_length_prefixed(&cbs, &auth_modes) ||
- CBS_len(&auth_modes) == 0 ||
+ !CBS_get_u32(&cbs, &session->ticket_age_add) ||
!CBS_get_u16_length_prefixed(&cbs, &ticket) ||
!CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) ||
!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
@@ -699,13 +656,10 @@ int tls13_process_new_session_ticket(SSL *ssl) {
return 0;
}
+ session->ticket_age_add_valid = 1;
session->not_resumable = 0;
- /* Ignore the ticket unless the server preferences are compatible with us. */
- if (memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL &&
- memchr(CBS_data(&auth_modes), SSL_PSK_AUTH, CBS_len(&auth_modes)) !=
- NULL &&
- ssl->ctx->new_session_cb != NULL &&
+ if (ssl->ctx->new_session_cb != NULL &&
ssl->ctx->new_session_cb(ssl, session)) {
/* |new_session_cb|'s return value signals that it took ownership. */
return 1;
diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c
index 1fcde514..d87d8a6f 100644
--- a/src/ssl/tls13_enc.c
+++ b/src/ssl/tls13_enc.c
@@ -20,27 +20,19 @@
#include <openssl/aead.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
-#include <openssl/hmac.h>
#include <openssl/hkdf.h>
+#include <openssl/hmac.h>
#include <openssl/mem.h>
#include "internal.h"
-int tls13_init_key_schedule(SSL *ssl, const uint8_t *resumption_ctx,
- size_t resumption_ctx_len) {
+int tls13_init_key_schedule(SSL *ssl) {
SSL_HANDSHAKE *hs = ssl->s3->hs;
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
hs->hash_len = EVP_MD_size(digest);
- /* Save the hash of the resumption context. */
- unsigned resumption_hash_len;
- if (!EVP_Digest(resumption_ctx, resumption_ctx_len, hs->resumption_hash,
- &resumption_hash_len, digest, NULL)) {
- return 0;
- }
-
/* Initialize the secret to the zero key. */
memset(hs->secret, 0, hs->hash_len);
@@ -89,22 +81,17 @@ static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest,
return ret;
}
-int tls13_get_context_hashes(SSL *ssl, uint8_t *out, size_t *out_len) {
- SSL_HANDSHAKE *hs = ssl->s3->hs;
-
+int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx);
unsigned handshake_len = 0;
int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) &&
EVP_DigestFinal_ex(&ctx, out, &handshake_len);
EVP_MD_CTX_cleanup(&ctx);
- if (!ok) {
- return 0;
+ if (ok) {
+ *out_len = handshake_len;
}
-
- memcpy(out + handshake_len, hs->resumption_hash, hs->hash_len);
- *out_len = handshake_len + hs->hash_len;
- return 1;
+ return ok;
}
/* derive_secret derives a secret of length |len| and writes the result in |out|
@@ -115,18 +102,17 @@ static int derive_secret(SSL *ssl, uint8_t *out, size_t len,
SSL_HANDSHAKE *hs = ssl->s3->hs;
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
- uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
- size_t context_hashes_len;
- if (!tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len)) {
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len)) {
return 0;
}
return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label,
- label_len, context_hashes, context_hashes_len, len);
+ label_len, context_hash, context_hash_len, len);
}
-int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
- enum evp_aead_direction_t direction,
+int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
const uint8_t *traffic_secret,
size_t traffic_secret_len) {
if (traffic_secret_len > 0xff) {
@@ -134,33 +120,11 @@ int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
return 0;
}
- const char *key_label, *iv_label;
- switch (type) {
- case type_early_handshake:
- key_label = "early handshake key expansion, key";
- iv_label = "early handshake key expansion, iv";
- break;
- case type_early_data:
- key_label = "early application data key expansion, key";
- iv_label = "early application data key expansion, iv";
- break;
- case type_handshake:
- key_label = "handshake key expansion, key";
- iv_label = "handshake key expansion, iv";
- break;
- case type_data:
- key_label = "application data key expansion, key";
- iv_label = "application data key expansion, iv";
- break;
- default:
- return 0;
- }
-
/* Look up cipher suite properties. */
const EVP_AEAD *aead;
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
- size_t mac_secret_len, fixed_iv_len;
- if (!ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len,
+ size_t discard;
+ if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
SSL_get_session(ssl)->cipher,
ssl3_protocol_version(ssl))) {
return 0;
@@ -170,8 +134,7 @@ int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
size_t key_len = EVP_AEAD_key_length(aead);
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
if (!hkdf_expand_label(key, digest, traffic_secret, traffic_secret_len,
- (const uint8_t *)key_label, strlen(key_label), NULL, 0,
- key_len)) {
+ (const uint8_t *)"key", 3, NULL, 0, key_len)) {
return 0;
}
@@ -179,8 +142,7 @@ int tls13_set_traffic_key(SSL *ssl, enum tls_record_type_t type,
size_t iv_len = EVP_AEAD_nonce_length(aead);
uint8_t iv[EVP_AEAD_MAX_NONCE_LENGTH];
if (!hkdf_expand_label(iv, digest, traffic_secret, traffic_secret_len,
- (const uint8_t *)iv_label, strlen(iv_label), NULL, 0,
- iv_len)) {
+ (const uint8_t *)"iv", 2, NULL, 0, iv_len)) {
return 0;
}
@@ -241,26 +203,29 @@ int tls13_set_handshake_traffic(SSL *ssl) {
}
if (ssl->server) {
- if (!tls13_set_traffic_key(ssl, type_handshake, evp_aead_open,
- client_traffic_secret, hs->hash_len) ||
- !tls13_set_traffic_key(ssl, type_handshake, evp_aead_seal,
- server_traffic_secret, hs->hash_len)) {
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, client_traffic_secret,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, server_traffic_secret,
+ hs->hash_len)) {
return 0;
}
} else {
- if (!tls13_set_traffic_key(ssl, type_handshake, evp_aead_open,
- server_traffic_secret, hs->hash_len) ||
- !tls13_set_traffic_key(ssl, type_handshake, evp_aead_seal,
- client_traffic_secret, hs->hash_len)) {
+ if (!tls13_set_traffic_key(ssl, evp_aead_open, server_traffic_secret,
+ hs->hash_len) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, client_traffic_secret,
+ hs->hash_len)) {
return 0;
}
}
return 1;
}
-int tls13_derive_traffic_secret_0(SSL *ssl) {
+static const char kTLS13LabelExporter[] = "exporter master secret";
+
+int tls13_derive_application_secrets(SSL *ssl) {
SSL_HANDSHAKE *hs = ssl->s3->hs;
+ ssl->s3->exporter_secret_len = hs->hash_len;
return derive_secret(ssl, hs->client_traffic_secret_0, hs->hash_len,
(const uint8_t *)kTLS13LabelClientApplicationTraffic,
strlen(kTLS13LabelClientApplicationTraffic)) &&
@@ -270,7 +235,10 @@ int tls13_derive_traffic_secret_0(SSL *ssl) {
(const uint8_t *)kTLS13LabelServerApplicationTraffic,
strlen(kTLS13LabelServerApplicationTraffic)) &&
ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0",
- hs->server_traffic_secret_0, hs->hash_len);
+ hs->server_traffic_secret_0, hs->hash_len) &&
+ derive_secret(ssl, ssl->s3->exporter_secret, hs->hash_len,
+ (const uint8_t *)kTLS13LabelExporter,
+ strlen(kTLS13LabelExporter));
}
static const char kTLS13LabelApplicationTraffic[] =
@@ -296,27 +264,36 @@ int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
return 0;
}
- return tls13_set_traffic_key(ssl, type_data, direction, secret, secret_len);
+ return tls13_set_traffic_key(ssl, direction, secret, secret_len);
}
-static const char kTLS13LabelExporter[] = "exporter master secret";
static const char kTLS13LabelResumption[] = "resumption master secret";
-int tls13_finalize_keys(SSL *ssl) {
- SSL_HANDSHAKE *hs = ssl->s3->hs;
+int tls13_derive_resumption_secret(SSL *ssl) {
+ ssl->s3->new_session->master_key_length = ssl->s3->hs->hash_len;
+ return derive_secret(ssl, ssl->s3->new_session->master_key,
+ ssl->s3->new_session->master_key_length,
+ (const uint8_t *)kTLS13LabelResumption,
+ strlen(kTLS13LabelResumption));
+}
- ssl->s3->exporter_secret_len = hs->hash_len;
- ssl->s3->new_session->master_key_length = hs->hash_len;
- if (!derive_secret(
- ssl, ssl->s3->exporter_secret, ssl->s3->exporter_secret_len,
- (const uint8_t *)kTLS13LabelExporter, strlen(kTLS13LabelExporter)) ||
- !derive_secret(ssl, ssl->s3->new_session->master_key,
- ssl->s3->new_session->master_key_length,
- (const uint8_t *)kTLS13LabelResumption,
- strlen(kTLS13LabelResumption))) {
+static const char kTLS13LabelFinished[] = "finished";
+
+/* tls13_verify_data sets |out| to be the HMAC of |context| using a derived
+ * Finished key for both Finished messages and the PSK binder. */
+static int tls13_verify_data(const EVP_MD *digest, uint8_t *out,
+ size_t *out_len, const uint8_t *secret,
+ size_t hash_len, uint8_t *context,
+ size_t context_len) {
+ uint8_t key[EVP_MAX_MD_SIZE];
+ unsigned len;
+ if (!hkdf_expand_label(key, digest, secret, hash_len,
+ (const uint8_t *)kTLS13LabelFinished,
+ strlen(kTLS13LabelFinished), NULL, 0, hash_len) ||
+ HMAC(digest, key, hash_len, context, context_len, out, &len) == NULL) {
return 0;
}
-
+ *out_len = len;
return 1;
}
@@ -324,54 +301,23 @@ int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server) {
SSL_HANDSHAKE *hs = ssl->s3->hs;
const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
- uint8_t key[EVP_MAX_MD_SIZE];
- size_t key_len = EVP_MD_size(digest);
-
const uint8_t *traffic_secret;
- const char *label = "finished";
if (is_server == ssl->server) {
traffic_secret = ssl->s3->write_traffic_secret;
} else {
traffic_secret = ssl->s3->read_traffic_secret;
}
- uint8_t context_hashes[2 * EVP_MAX_MD_SIZE];
- size_t context_hashes_len;
- unsigned len;
- if (!hkdf_expand_label(key, digest, traffic_secret, hs->hash_len,
- (const uint8_t *)label, strlen(label), NULL, 0,
- hs->hash_len) ||
- !tls13_get_context_hashes(ssl, context_hashes, &context_hashes_len) ||
- HMAC(digest, key, key_len, context_hashes, context_hashes_len, out,
- &len) == NULL) {
+ uint8_t context_hash[EVP_MAX_MD_SIZE];
+ size_t context_hash_len;
+ if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+ !tls13_verify_data(digest, out, out_len, traffic_secret, hs->hash_len,
+ context_hash, context_hash_len)) {
return 0;
}
- *out_len = len;
return 1;
}
-static const char kTLS13LabelResumptionPSK[] = "resumption psk";
-static const char kTLS13LabelResumptionContext[] = "resumption context";
-
-int tls13_resumption_psk(SSL *ssl, uint8_t *out, size_t out_len,
- const SSL_SESSION *session) {
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
- return hkdf_expand_label(out, digest, session->master_key,
- session->master_key_length,
- (const uint8_t *)kTLS13LabelResumptionPSK,
- strlen(kTLS13LabelResumptionPSK), NULL, 0, out_len);
-}
-
-int tls13_resumption_context(SSL *ssl, uint8_t *out, size_t out_len,
- const SSL_SESSION *session) {
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
- return hkdf_expand_label(out, digest, session->master_key,
- session->master_key_length,
- (const uint8_t *)kTLS13LabelResumptionContext,
- strlen(kTLS13LabelResumptionContext), NULL, 0,
- out_len);
-}
-
int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
const char *label, size_t label_len,
const uint8_t *context, size_t context_len,
@@ -388,3 +334,119 @@ int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len,
ssl->s3->exporter_secret_len, (const uint8_t *)label,
label_len, hash, hash_len, out_len);
}
+
+static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
+
+static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest,
+ uint8_t *psk, size_t psk_len, uint8_t *context,
+ size_t context_len, size_t hash_len) {
+ uint8_t binder_context[EVP_MAX_MD_SIZE];
+ unsigned binder_context_len;
+ if (!EVP_Digest(NULL, 0, binder_context, &binder_context_len, digest, NULL)) {
+ return 0;
+ }
+
+ uint8_t early_secret[EVP_MAX_MD_SIZE] = {0};
+ size_t early_secret_len;
+ if (!HKDF_extract(early_secret, &early_secret_len, digest, psk, hash_len,
+ NULL, 0)) {
+ return 0;
+ }
+
+ uint8_t binder_key[EVP_MAX_MD_SIZE] = {0};
+ size_t len;
+ if (!hkdf_expand_label(binder_key, digest, early_secret, hash_len,
+ (const uint8_t *)kTLS13LabelPSKBinder,
+ strlen(kTLS13LabelPSKBinder), binder_context,
+ binder_context_len, hash_len) ||
+ !tls13_verify_data(digest, out, &len, binder_key, hash_len, context,
+ context_len)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) {
+ const EVP_MD *digest =
+ ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+ size_t hash_len = EVP_MD_size(digest);
+
+ if (len < hash_len + 3) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
+ if (!EVP_DigestInit_ex(&ctx, digest, NULL) ||
+ !EVP_DigestUpdate(&ctx, ssl->s3->handshake_buffer->data,
+ ssl->s3->handshake_buffer->length) ||
+ !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) ||
+ !EVP_DigestFinal_ex(&ctx, context, &context_len)) {
+ EVP_MD_CTX_cleanup(&ctx);
+ return 0;
+ }
+
+ EVP_MD_CTX_cleanup(&ctx);
+
+ uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+ if (!tls13_psk_binder(ssl, verify_data, digest, ssl->session->master_key,
+ ssl->session->master_key_length, context,
+ context_len, hash_len)) {
+ return 0;
+ }
+
+ memcpy(msg + len - hash_len, verify_data, hash_len);
+ return 1;
+}
+
+int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session,
+ CBS *binders) {
+ const EVP_MD *digest =
+ ssl_get_handshake_digest(session->cipher->algorithm_prf);
+ size_t hash_len = EVP_MD_size(digest);
+
+ /* Get the full ClientHello, including message header. It must be large enough
+ * to exclude the binders. */
+ CBS message;
+ ssl->method->get_current_message(ssl, &message);
+ if (CBS_len(&message) < CBS_len(binders) + 2) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Hash a ClientHello prefix up to the binders. For now, this assumes we only
+ * ever verify PSK binders on initial ClientHellos. */
+ uint8_t context[EVP_MAX_MD_SIZE];
+ unsigned context_len;
+ if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
+ context, &context_len, digest, NULL)) {
+ return 0;
+ }
+
+ uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
+ CBS binder;
+ if (!tls13_psk_binder(ssl, verify_data, digest, session->master_key,
+ session->master_key_length, context, context_len,
+ hash_len) ||
+ /* We only consider the first PSK, so compare against the first binder. */
+ !CBS_get_u8_length_prefixed(binders, &binder)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ int binder_ok = CBS_len(&binder) == hash_len &&
+ CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
+#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
+ binder_ok = 1;
+#endif
+ if (!binder_ok) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED);
+ return 0;
+ }
+
+ return 1;
+}
diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c
index 25700694..83ef6795 100644
--- a/src/ssl/tls13_server.c
+++ b/src/ssl/tls13_server.c
@@ -17,6 +17,7 @@
#include <assert.h>
#include <string.h>
+#include <openssl/aead.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
@@ -43,9 +44,10 @@ enum server_hs_state_t {
state_flush,
state_process_client_certificate,
state_process_client_certificate_verify,
+ state_process_channel_id,
state_process_client_finished,
state_send_new_session_ticket,
- state_flush_new_session_ticket,
+ state_flush_new_session_tickets,
state_done,
};
@@ -61,7 +63,7 @@ static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry,
TLSEXT_TYPE_key_share)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION);
- return ssl_hs_error;
+ return 0;
}
int found_key_share;
@@ -103,53 +105,9 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
/* Load the client random. */
if (client_hello.random_len != SSL3_RANDOM_SIZE) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return -1;
- }
- memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
-
- uint8_t alert = SSL_AD_DECODE_ERROR;
- SSL_SESSION *session = NULL;
- CBS pre_shared_key;
- if (ssl_early_callback_get_extension(&client_hello, &pre_shared_key,
- TLSEXT_TYPE_pre_shared_key) &&
- !ssl_ext_pre_shared_key_parse_clienthello(ssl, &session, &alert,
- &pre_shared_key)) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- return 0;
- }
-
- if (session != NULL &&
- /* Only resume if the session's version matches. */
- (session->ssl_version != ssl->version ||
- !ssl_client_cipher_list_contains_cipher(
- &client_hello, (uint16_t)SSL_CIPHER_get_id(session->cipher)))) {
- SSL_SESSION_free(session);
- session = NULL;
- }
-
- if (session == NULL) {
- if (!ssl_get_new_session(ssl, 1 /* server */)) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_hs_error;
- }
- } else {
- /* Only authentication information carries over in TLS 1.3. */
- ssl->s3->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
- if (ssl->s3->new_session == NULL) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_hs_error;
- }
- ssl->s3->session_reused = 1;
- SSL_SESSION_free(session);
- }
-
- if (ssl->ctx->dos_protection_cb != NULL &&
- ssl->ctx->dos_protection_cb(&client_hello) == 0) {
- /* Connection rejected for DOS reasons. */
- OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return ssl_hs_error;
}
+ memcpy(ssl->s3->client_random, client_hello.random, client_hello.random_len);
/* TLS 1.3 requires the peer only advertise the null compression. */
if (client_hello.compression_methods_len != 1 ||
@@ -169,20 +127,64 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_ok;
}
+static const SSL_CIPHER *choose_tls13_cipher(
+ const SSL *ssl, const struct ssl_early_callback_ctx *client_hello) {
+ if (client_hello->cipher_suites_len % 2 != 0) {
+ return NULL;
+ }
+
+ CBS cipher_suites;
+ CBS_init(&cipher_suites, client_hello->cipher_suites,
+ client_hello->cipher_suites_len);
+
+ const int aes_is_fine = EVP_has_aes_hardware();
+ const uint16_t version = ssl3_protocol_version(ssl);
+
+ const SSL_CIPHER *best = NULL;
+ while (CBS_len(&cipher_suites) > 0) {
+ uint16_t cipher_suite;
+ if (!CBS_get_u16(&cipher_suites, &cipher_suite)) {
+ return NULL;
+ }
+
+ /* Limit to TLS 1.3 ciphers we know about. */
+ const SSL_CIPHER *candidate = SSL_get_cipher_by_value(cipher_suite);
+ if (candidate == NULL ||
+ SSL_CIPHER_get_min_version(candidate) > version ||
+ SSL_CIPHER_get_max_version(candidate) < version) {
+ continue;
+ }
+
+ /* TLS 1.3 removes legacy ciphers, so honor the client order, but prefer
+ * ChaCha20 if we do not have AES hardware. */
+ if (aes_is_fine) {
+ return candidate;
+ }
+
+ if (candidate->algorithm_enc == SSL_CHACHA20POLY1305) {
+ return candidate;
+ }
+
+ if (best == NULL) {
+ best = candidate;
+ }
+ }
+
+ return best;
+}
+
static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
- if (!ssl->s3->session_reused) {
- /* Call |cert_cb| to update server certificates if required. */
- if (ssl->cert->cert_cb != NULL) {
- int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
- if (rv == 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return ssl_hs_error;
- }
- if (rv < 0) {
- hs->state = state_select_parameters;
- return ssl_hs_x509_lookup;
- }
+ /* Call |cert_cb| to update server certificates if required. */
+ if (ssl->cert->cert_cb != NULL) {
+ int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg);
+ if (rv == 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ if (rv < 0) {
+ hs->state = state_select_parameters;
+ return ssl_hs_x509_lookup;
}
}
@@ -194,45 +196,116 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) {
return ssl_hs_error;
}
- if (!ssl->s3->session_reused) {
- const SSL_CIPHER *cipher =
- ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl));
- if (cipher == NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ /* Negotiate the cipher suite. */
+ ssl->s3->tmp.new_cipher = choose_tls13_cipher(ssl, &client_hello);
+ if (ssl->s3->tmp.new_cipher == NULL) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ return ssl_hs_error;
+ }
+
+ /* Decode the ticket if we agree on a PSK key exchange mode. */
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ SSL_SESSION *session = NULL;
+ CBS pre_shared_key, binders;
+ if (hs->accept_psk_mode &&
+ ssl_early_callback_get_extension(&client_hello, &pre_shared_key,
+ TLSEXT_TYPE_pre_shared_key)) {
+ /* Verify that the pre_shared_key extension is the last extension in
+ * ClientHello. */
+ if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) !=
+ client_hello.extensions + client_hello.extensions_len) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_PRE_SHARED_KEY_MUST_BE_LAST);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
return ssl_hs_error;
}
- ssl->s3->new_session->cipher = cipher;
+ if (!ssl_ext_pre_shared_key_parse_clienthello(ssl, &session, &binders,
+ &alert, &pre_shared_key)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
}
- ssl->s3->tmp.new_cipher = ssl->s3->new_session->cipher;
- ssl->method->received_flight(ssl);
+ if (session != NULL &&
+ !ssl_session_is_resumable(ssl, session)) {
+ SSL_SESSION_free(session);
+ session = NULL;
+ }
+
+ /* Set up the new session, either using the original one as a template or
+ * creating a fresh one. */
+ if (session == NULL) {
+ if (!ssl_get_new_session(ssl, 1 /* server */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher;
+ /* On new sessions, stash the SNI value in the session. */
+ if (ssl->s3->hs->hostname != NULL) {
+ ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname);
+ if (ssl->s3->new_session->tlsext_hostname == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ }
+ } else {
+ /* Check the PSK binder. */
+ if (!tls13_verify_psk_binder(ssl, session, &binders)) {
+ SSL_SESSION_free(session);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* Only authentication information carries over in TLS 1.3. */
+ ssl->s3->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
+ if (ssl->s3->new_session == NULL) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+ ssl->s3->session_reused = 1;
+ SSL_SESSION_free(session);
+ }
+
+ if (ssl->ctx->dos_protection_cb != NULL &&
+ ssl->ctx->dos_protection_cb(&client_hello) == 0) {
+ /* Connection rejected for DOS reasons. */
+ OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was
+ * deferred. Complete it now. */
+ if (!ssl_negotiate_alpn(ssl, &alert, &client_hello)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
/* The PRF hash is now known. */
size_t hash_len =
EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
/* Derive resumption material. */
- uint8_t resumption_ctx[EVP_MAX_MD_SIZE] = {0};
uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0};
if (ssl->s3->session_reused) {
- if (!tls13_resumption_context(ssl, resumption_ctx, hash_len,
- ssl->s3->new_session) ||
- !tls13_resumption_psk(ssl, psk_secret, hash_len,
- ssl->s3->new_session)) {
+ if (hash_len != (size_t) ssl->s3->new_session->master_key_length) {
return ssl_hs_error;
}
+ memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len);
}
/* Set up the key schedule, hash in the ClientHello, and incorporate the PSK
* into the running secret. */
- if (!tls13_init_key_schedule(ssl, resumption_ctx, hash_len) ||
+ if (!tls13_init_key_schedule(ssl) ||
!tls13_advance_key_schedule(ssl, psk_secret, hash_len)) {
return ssl_hs_error;
}
+ ssl->method->received_flight(ssl);
+
/* Resolve ECDHE and incorporate it into the secret. */
int need_retry;
if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) {
@@ -259,7 +332,7 @@ static enum ssl_hs_wait_t do_send_hello_retry_request(SSL *ssl,
!CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) ||
!CBB_add_u16(&extensions, 2 /* length */) ||
!CBB_add_u16(&extensions, group_id) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
CBB_cleanup(&cbb);
return ssl_hs_error;
}
@@ -298,7 +371,7 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL *ssl,
return ssl_hs_error;
}
- if (!ssl->method->hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
@@ -316,18 +389,8 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) {
!CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) ||
!CBB_add_u16_length_prefixed(&body, &extensions) ||
!ssl_ext_pre_shared_key_add_serverhello(ssl, &extensions) ||
- !ssl_ext_key_share_add_serverhello(ssl, &extensions)) {
- goto err;
- }
-
- if (!ssl->s3->session_reused) {
- if (!CBB_add_u16(&extensions, TLSEXT_TYPE_signature_algorithms) ||
- !CBB_add_u16(&extensions, 0)) {
- goto err;
- }
- }
-
- if (!ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_ext_key_share_add_serverhello(ssl, &extensions) ||
+ !ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -349,7 +412,7 @@ static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl,
if (!ssl->method->init_message(ssl, &cbb, &body,
SSL3_MT_ENCRYPTED_EXTENSIONS) ||
!ssl_add_serverhello_tlsext(ssl, &body) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
CBB_cleanup(&cbb);
return ssl_hs_error;
}
@@ -394,7 +457,7 @@ static enum ssl_hs_wait_t do_send_certificate_request(SSL *ssl,
if (!ssl_add_client_CA_list(ssl, &body) ||
!CBB_add_u16(&body, 0 /* empty certificate_extensions. */) ||
- !ssl->method->finish_message(ssl, &cbb)) {
+ !ssl_complete_message(ssl, &cbb)) {
goto err;
}
@@ -458,9 +521,9 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL *ssl, SSL_HANDSHAKE *hs) {
static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) {
/* Update the secret to the master secret and derive traffic keys. */
if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) ||
- !tls13_derive_traffic_secret_0(ssl) ||
- !tls13_set_traffic_key(ssl, type_data, evp_aead_seal,
- hs->server_traffic_secret_0, hs->hash_len)) {
+ !tls13_derive_application_secrets(ssl) ||
+ !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0,
+ hs->hash_len)) {
return ssl_hs_error;
}
@@ -476,7 +539,7 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl,
ssl->s3->new_session->verify_result = X509_V_OK;
/* Skip this state. */
- hs->state = state_process_client_finished;
+ hs->state = state_process_channel_id;
return ssl_hs_ok;
}
@@ -485,14 +548,14 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl,
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
!tls13_process_certificate(ssl, allow_anonymous) ||
- !ssl->method->hash_current_message(ssl)) {
+ !ssl_hash_current_message(ssl)) {
return ssl_hs_error;
}
/* For historical reasons, the server's copy of the chain does not include the
* leaf while the client's does. */
- if (sk_X509_num(ssl->s3->new_session->cert_chain) > 0) {
- X509_free(sk_X509_shift(ssl->s3->new_session->cert_chain));
+ if (sk_X509_num(ssl->s3->new_session->x509_chain) > 0) {
+ X509_free(sk_X509_shift(ssl->s3->new_session->x509_chain));
}
hs->state = state_process_client_certificate_verify;
@@ -501,16 +564,32 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl,
static enum ssl_hs_wait_t do_process_client_certificate_verify(
SSL *ssl, SSL_HANDSHAKE *hs) {
- if (ssl->s3->new_session->peer == NULL) {
+ if (ssl->s3->new_session->x509_peer == NULL) {
/* Skip this state. */
- hs->state = state_process_client_finished;
+ hs->state = state_process_channel_id;
return ssl_hs_ok;
}
if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
!tls13_process_certificate_verify(ssl) ||
- !ssl->method->hash_current_message(ssl)) {
- return 0;
+ !ssl_hash_current_message(ssl)) {
+ return ssl_hs_error;
+ }
+
+ hs->state = state_process_channel_id;
+ return ssl_hs_read_message;
+}
+
+static enum ssl_hs_wait_t do_process_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) {
+ if (!ssl->s3->tlsext_channel_id_valid) {
+ hs->state = state_process_client_finished;
+ return ssl_hs_ok;
+ }
+
+ if (!tls13_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
+ !tls1_verify_channel_id(ssl) ||
+ !ssl_hash_current_message(ssl)) {
+ return ssl_hs_error;
}
hs->state = state_process_client_finished;
@@ -521,35 +600,49 @@ static enum ssl_hs_wait_t do_process_client_finished(SSL *ssl,
SSL_HANDSHAKE *hs) {
if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) ||
!tls13_process_finished(ssl) ||
- !ssl->method->hash_current_message(ssl) ||
+ !ssl_hash_current_message(ssl) ||
/* evp_aead_seal keys have already been switched. */
- !tls13_set_traffic_key(ssl, type_data, evp_aead_open,
- hs->client_traffic_secret_0, hs->hash_len) ||
- !tls13_finalize_keys(ssl)) {
+ !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
+ hs->hash_len) ||
+ !tls13_derive_resumption_secret(ssl)) {
return ssl_hs_error;
}
ssl->method->received_flight(ssl);
+
+ /* Refresh the session timestamp so that it is measured from ticket
+ * issuance. */
+ ssl_session_refresh_time(ssl, ssl->s3->new_session);
hs->state = state_send_new_session_ticket;
return ssl_hs_ok;
}
+/* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
+ * client makes several connections before getting a renewal. */
+static const int kNumTickets = 2;
+
static enum ssl_hs_wait_t do_send_new_session_ticket(SSL *ssl,
SSL_HANDSHAKE *hs) {
+ /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a
+ * session ticket. */
+ if (!hs->accept_psk_mode) {
+ hs->state = state_done;
+ return ssl_hs_ok;
+ }
+
SSL_SESSION *session = ssl->s3->new_session;
- session->tlsext_tick_lifetime_hint = session->timeout;
+ if (!RAND_bytes((uint8_t *)&session->ticket_age_add, 4)) {
+ goto err;
+ }
/* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo
* extension. */
- CBB cbb, body, ke_modes, auth_modes, ticket, extensions;
+ CBB cbb, body, ticket, extensions;
if (!ssl->method->init_message(ssl, &cbb, &body,
SSL3_MT_NEW_SESSION_TICKET) ||
- !CBB_add_u32(&body, session->tlsext_tick_lifetime_hint) ||
- !CBB_add_u8_length_prefixed(&body, &ke_modes) ||
- !CBB_add_u8(&ke_modes, SSL_PSK_DHE_KE) ||
- !CBB_add_u8_length_prefixed(&body, &auth_modes) ||
- !CBB_add_u8(&auth_modes, SSL_PSK_AUTH) ||
+ !CBB_add_u32(&body, session->timeout) ||
+ !CBB_add_u32(&body, session->ticket_age_add) ||
!CBB_add_u16_length_prefixed(&body, &ticket) ||
!ssl_encrypt_ticket(ssl, &ticket, session) ||
!CBB_add_u16_length_prefixed(&body, &extensions)) {
@@ -557,21 +650,23 @@ static enum ssl_hs_wait_t do_send_new_session_ticket(SSL *ssl,
}
/* Add a fake extension. See draft-davidben-tls-grease-01. */
- if (ssl->ctx->grease_enabled) {
- if (!CBB_add_u16(&extensions,
- ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
- !CBB_add_u16(&extensions, 0 /* empty */)) {
- goto err;
- }
+ if (!CBB_add_u16(&extensions,
+ ssl_get_grease_value(ssl, ssl_grease_ticket_extension)) ||
+ !CBB_add_u16(&extensions, 0 /* empty */)) {
+ goto err;
}
- if (!ssl->method->finish_message(ssl, &cbb)) {
+ if (!ssl_complete_message(ssl, &cbb)) {
goto err;
}
hs->session_tickets_sent++;
+ if (hs->session_tickets_sent >= kNumTickets) {
+ hs->state = state_flush_new_session_tickets;
+ } else {
+ hs->state = state_send_new_session_ticket;
+ }
- hs->state = state_flush_new_session_ticket;
return ssl_hs_write_message;
err:
@@ -579,17 +674,9 @@ err:
return ssl_hs_error;
}
-/* TLS 1.3 recommends single-use tickets, so issue multiple tickets in case the
- * client makes several connections before getting a renewal. */
-static const int kNumTickets = 2;
-
-static enum ssl_hs_wait_t do_flush_new_session_ticket(SSL *ssl,
- SSL_HANDSHAKE *hs) {
- if (hs->session_tickets_sent >= kNumTickets) {
- hs->state = state_done;
- } else {
- hs->state = state_send_new_session_ticket;
- }
+static enum ssl_hs_wait_t do_flush_new_session_tickets(SSL *ssl,
+ SSL_HANDSHAKE *hs) {
+ hs->state = state_done;
return ssl_hs_flush;
}
@@ -645,14 +732,17 @@ enum ssl_hs_wait_t tls13_server_handshake(SSL *ssl) {
case state_process_client_certificate_verify:
ret = do_process_client_certificate_verify(ssl, hs);
break;
+ case state_process_channel_id:
+ ret = do_process_channel_id(ssl, hs);
+ break;
case state_process_client_finished:
ret = do_process_client_finished(ssl, hs);
break;
case state_send_new_session_ticket:
ret = do_send_new_session_ticket(ssl, hs);
break;
- case state_flush_new_session_ticket:
- ret = do_flush_new_session_ticket(ssl, hs);
+ case state_flush_new_session_tickets:
+ ret = do_flush_new_session_tickets(ssl, hs);
break;
case state_done:
ret = ssl_hs_ok;
diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c
index 8bcdf8f6..ce42904b 100644
--- a/src/ssl/tls_method.c
+++ b/src/ssl/tls_method.c
@@ -130,7 +130,7 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
ssl3_new,
ssl3_free,
ssl3_get_message,
- ssl3_hash_current_message,
+ ssl3_get_current_message,
ssl3_release_current_message,
ssl3_read_app_data,
ssl3_read_change_cipher_spec,
@@ -140,6 +140,7 @@ static const SSL_PROTOCOL_METHOD kTLSProtocolMethod = {
ssl3_supports_cipher,
ssl3_init_message,
ssl3_finish_message,
+ ssl3_queue_message,
ssl3_write_message,
ssl3_send_change_cipher_spec,
ssl3_expect_flight,
diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c
index 7041ce34..59319225 100644
--- a/src/ssl/tls_record.c
+++ b/src/ssl/tls_record.c
@@ -174,7 +174,7 @@ size_t ssl_seal_align_prefix_len(const SSL *ssl) {
}
}
-size_t ssl_max_seal_overhead(const SSL *ssl) {
+size_t SSL_max_seal_overhead(const SSL *ssl) {
size_t ret = SSL_AEAD_CTX_max_overhead(ssl->s3->aead_write_ctx);
if (SSL_is_dtls(ssl)) {
ret += DTLS1_RT_HEADER_LENGTH;
@@ -210,9 +210,20 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out,
return ssl_open_record_partial;
}
- /* Check that the major version in the record matches. As of TLS 1.3, the
- * minor version is no longer checked. */
- if ((version >> 8) != SSL3_VERSION_MAJOR) {
+ int version_ok;
+ if (ssl->s3->aead_read_ctx == NULL) {
+ /* Only check the first byte. Enforcing beyond that can prevent decoding
+ * version negotiation failure alerts. */
+ version_ok = (version >> 8) == SSL3_VERSION_MAJOR;
+ } else if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) {
+ /* Earlier versions of TLS switch the record version. */
+ version_ok = version == ssl->version;
+ } else {
+ /* Starting TLS 1.3, the version field is frozen at {3, 1}. */
+ version_ok = version == TLS1_VERSION;
+ }
+
+ if (!version_ok) {
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
*out_alert = SSL_AD_PROTOCOL_VERSION;
return ssl_open_record_error;
diff --git a/src/tool/digest.cc b/src/tool/digest.cc
index 2e3e6085..7b6c88b5 100644
--- a/src/tool/digest.cc
+++ b/src/tool/digest.cc
@@ -21,6 +21,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -64,8 +65,9 @@ struct Source {
};
Source() : is_stdin_(false) {}
- Source(Type) : is_stdin_(true) {}
- Source(const std::string &name) : is_stdin_(false), filename_(name) {}
+ explicit Source(Type) : is_stdin_(true) {}
+ explicit Source(const std::string &name)
+ : is_stdin_(false), filename_(name) {}
bool is_stdin() const { return is_stdin_; }
const std::string &filename() const { return filename_; }
@@ -132,12 +134,8 @@ static bool SumFile(std::string *out_hex, const EVP_MD *md,
static const size_t kBufSize = 8192;
std::unique_ptr<uint8_t[]> buf(new uint8_t[kBufSize]);
- EVP_MD_CTX ctx;
- EVP_MD_CTX_init(&ctx);
- std::unique_ptr<EVP_MD_CTX, func_delete<EVP_MD_CTX, int, EVP_MD_CTX_cleanup>>
- scoped_ctx(&ctx);
-
- if (!EVP_DigestInit_ex(&ctx, md, NULL)) {
+ bssl::ScopedEVP_MD_CTX ctx;
+ if (!EVP_DigestInit_ex(ctx.get(), md, NULL)) {
fprintf(stderr, "Failed to initialize EVP_MD_CTX.\n");
return false;
}
@@ -158,7 +156,7 @@ static bool SumFile(std::string *out_hex, const EVP_MD *md,
return false;
}
- if (!EVP_DigestUpdate(&ctx, buf.get(), n)) {
+ if (!EVP_DigestUpdate(ctx.get(), buf.get(), n)) {
fprintf(stderr, "Failed to update hash.\n");
return false;
}
@@ -166,7 +164,7 @@ static bool SumFile(std::string *out_hex, const EVP_MD *md,
uint8_t digest[EVP_MAX_MD_SIZE];
unsigned digest_len;
- if (!EVP_DigestFinal_ex(&ctx, digest, &digest_len)) {
+ if (!EVP_DigestFinal_ex(ctx.get(), digest, &digest_len)) {
fprintf(stderr, "Failed to finish hash.\n");
return false;
}
diff --git a/src/tool/pkcs12.cc b/src/tool/pkcs12.cc
index 15e32d3d..7fd6f131 100644
--- a/src/tool/pkcs12.cc
+++ b/src/tool/pkcs12.cc
@@ -120,23 +120,22 @@ bool DoPKCS12(const std::vector<std::string> &args) {
CBS_init(&pkcs12, contents.get(), size);
EVP_PKEY *key;
- STACK_OF(X509) *certs = sk_X509_new_null();
+ bssl::UniquePtr<STACK_OF(X509)> certs(sk_X509_new_null());
- if (!PKCS12_get_key_and_certs(&key, certs, &pkcs12, password)) {
+ if (!PKCS12_get_key_and_certs(&key, certs.get(), &pkcs12, password)) {
fprintf(stderr, "Failed to parse PKCS#12 data:\n");
ERR_print_errors_fp(stderr);
return false;
}
+ bssl::UniquePtr<EVP_PKEY> key_owned(key);
if (key != NULL) {
PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
- EVP_PKEY_free(key);
}
- for (size_t i = 0; i < sk_X509_num(certs); i++) {
- PEM_write_X509(stdout, sk_X509_value(certs, i));
+ for (size_t i = 0; i < sk_X509_num(certs.get()); i++) {
+ PEM_write_X509(stdout, sk_X509_value(certs.get(), i));
}
- sk_X509_pop_free(certs, X509_free);
return true;
}
diff --git a/src/tool/rand.cc b/src/tool/rand.cc
index 3701748c..b442e0d0 100644
--- a/src/tool/rand.cc
+++ b/src/tool/rand.cc
@@ -16,6 +16,7 @@
#include <vector>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>
diff --git a/src/tool/server.cc b/src/tool/server.cc
index 012f671c..d0213e9e 100644
--- a/src/tool/server.cc
+++ b/src/tool/server.cc
@@ -103,25 +103,25 @@ bool Server(const std::vector<std::string> &args) {
return false;
}
- SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
- SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+ bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
+ SSL_CTX_set_options(ctx.get(), SSL_OP_NO_SSLv3);
// Server authentication is required.
std::string key_file = "server.pem";
if (args_map.count("-key") != 0) {
key_file = args_map["-key"];
}
- if (!SSL_CTX_use_PrivateKey_file(ctx, key_file.c_str(), SSL_FILETYPE_PEM)) {
+ if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key_file.c_str(), SSL_FILETYPE_PEM)) {
fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str());
return false;
}
- if (!SSL_CTX_use_certificate_chain_file(ctx, key_file.c_str())) {
+ if (!SSL_CTX_use_certificate_chain_file(ctx.get(), key_file.c_str())) {
fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str());
return false;
}
if (args_map.count("-cipher") != 0 &&
- !SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str())) {
+ !SSL_CTX_set_cipher_list(ctx.get(), args_map["-cipher"].c_str())) {
fprintf(stderr, "Failed setting cipher list\n");
return false;
}
@@ -133,7 +133,7 @@ bool Server(const std::vector<std::string> &args) {
args_map["-max-version"].c_str());
return false;
}
- if (!SSL_CTX_set_max_proto_version(ctx, version)) {
+ if (!SSL_CTX_set_max_proto_version(ctx.get(), version)) {
return false;
}
}
@@ -145,13 +145,13 @@ bool Server(const std::vector<std::string> &args) {
args_map["-min-version"].c_str());
return false;
}
- if (!SSL_CTX_set_min_proto_version(ctx, version)) {
+ if (!SSL_CTX_set_min_proto_version(ctx.get(), version)) {
return false;
}
}
if (args_map.count("-ocsp-response") != 0 &&
- !LoadOCSPResponse(ctx, args_map["-ocsp-response"].c_str())) {
+ !LoadOCSPResponse(ctx.get(), args_map["-ocsp-response"].c_str())) {
fprintf(stderr, "Failed to load OCSP response: %s\n", args_map["-ocsp-response"].c_str());
return false;
}
@@ -162,23 +162,19 @@ bool Server(const std::vector<std::string> &args) {
}
BIO *bio = BIO_new_socket(sock, BIO_CLOSE);
- SSL *ssl = SSL_new(ctx);
- SSL_set_bio(ssl, bio, bio);
+ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get()));
+ SSL_set_bio(ssl.get(), bio, bio);
- int ret = SSL_accept(ssl);
+ int ret = SSL_accept(ssl.get());
if (ret != 1) {
- int ssl_err = SSL_get_error(ssl, ret);
+ int ssl_err = SSL_get_error(ssl.get(), ret);
fprintf(stderr, "Error while connecting: %d\n", ssl_err);
ERR_print_errors_cb(PrintErrorCallback, stderr);
return false;
}
fprintf(stderr, "Connected.\n");
- PrintConnectionInfo(ssl);
+ PrintConnectionInfo(ssl.get());
- bool ok = TransferData(ssl, sock);
-
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- return ok;
+ return TransferData(ssl.get(), sock);
}
diff --git a/src/tool/speed.cc b/src/tool/speed.cc
index d5f94e1a..f16a9ebc 100644
--- a/src/tool/speed.cc
+++ b/src/tool/speed.cc
@@ -203,7 +203,7 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
size_t chunk_len, size_t ad_len) {
static const unsigned kAlignment = 16;
- EVP_AEAD_CTX ctx;
+ bssl::ScopedEVP_AEAD_CTX ctx;
const size_t key_len = EVP_AEAD_key_length(aead);
const size_t nonce_len = EVP_AEAD_nonce_length(aead);
const size_t overhead_len = EVP_AEAD_max_overhead(aead);
@@ -222,7 +222,7 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
uint8_t *const out = align(out_storage.get(), kAlignment);
memset(out, 0, chunk_len + overhead_len);
- if (!EVP_AEAD_CTX_init_with_direction(&ctx, aead, key.get(), key_len,
+ if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.get(), key_len,
EVP_AEAD_DEFAULT_TAG_LENGTH,
evp_aead_seal)) {
fprintf(stderr, "Failed to create EVP_AEAD_CTX.\n");
@@ -234,10 +234,9 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
if (!TimeFunction(&results, [chunk_len, overhead_len, nonce_len, ad_len, in,
out, &ctx, &nonce, &ad]() -> bool {
size_t out_len;
-
- return EVP_AEAD_CTX_seal(
- &ctx, out, &out_len, chunk_len + overhead_len, nonce.get(),
- nonce_len, in, chunk_len, ad.get(), ad_len);
+ return EVP_AEAD_CTX_seal(ctx.get(), out, &out_len,
+ chunk_len + overhead_len, nonce.get(),
+ nonce_len, in, chunk_len, ad.get(), ad_len);
})) {
fprintf(stderr, "EVP_AEAD_CTX_seal failed.\n");
ERR_print_errors_fp(stderr);
@@ -245,9 +244,6 @@ static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
}
results.PrintWithBytes(name + " seal", chunk_len);
-
- EVP_AEAD_CTX_cleanup(&ctx);
-
return true;
}
@@ -302,7 +298,7 @@ static bool SpeedHash(const EVP_MD *md, const std::string &name,
SpeedHashChunk(md, name + " (8192 bytes)", 8192);
}
-static bool SpeedRandomChunk(const std::string name, size_t chunk_len) {
+static bool SpeedRandomChunk(const std::string &name, size_t chunk_len) {
uint8_t scratch[8192];
if (chunk_len > sizeof(scratch)) {
@@ -547,15 +543,16 @@ static bool SpeedNewHope(const std::string &selected) {
}
TimeResults results;
- NEWHOPE_POLY *sk = NEWHOPE_POLY_new();
+ bssl::UniquePtr<NEWHOPE_POLY> sk(NEWHOPE_POLY_new());
uint8_t acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
RAND_bytes(acceptmsg, sizeof(acceptmsg));
- if (!TimeFunction(&results, [sk, &acceptmsg]() -> bool {
+ if (!TimeFunction(&results, [&sk, &acceptmsg]() -> bool {
uint8_t key[SHA256_DIGEST_LENGTH];
uint8_t offermsg[NEWHOPE_OFFERMSG_LENGTH];
- NEWHOPE_offer(offermsg, sk);
- if (!NEWHOPE_finish(key, sk, acceptmsg, NEWHOPE_ACCEPTMSG_LENGTH)) {
+ NEWHOPE_offer(offermsg, sk.get());
+ if (!NEWHOPE_finish(key, sk.get(), acceptmsg,
+ NEWHOPE_ACCEPTMSG_LENGTH)) {
return false;
}
return true;
@@ -564,7 +561,6 @@ static bool SpeedNewHope(const std::string &selected) {
return false;
}
- NEWHOPE_POLY_free(sk);
results.Print("newhope key exchange");
return true;
}
@@ -599,45 +595,43 @@ bool Speed(const std::vector<std::string> &args) {
g_timeout_seconds = atoi(args_map["-timeout"].c_str());
}
- RSA *key = RSA_private_key_from_bytes(kDERRSAPrivate2048,
- kDERRSAPrivate2048Len);
- if (key == NULL) {
+ bssl::UniquePtr<RSA> key(
+ RSA_private_key_from_bytes(kDERRSAPrivate2048, kDERRSAPrivate2048Len));
+ if (key == nullptr) {
fprintf(stderr, "Failed to parse RSA key.\n");
ERR_print_errors_fp(stderr);
return false;
}
- if (!SpeedRSA("RSA 2048", key, selected)) {
+ if (!SpeedRSA("RSA 2048", key.get(), selected)) {
return false;
}
- RSA_free(key);
- key = RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
- kDERRSAPrivate3Prime2048Len);
- if (key == NULL) {
+ key.reset(RSA_private_key_from_bytes(kDERRSAPrivate3Prime2048,
+ kDERRSAPrivate3Prime2048Len));
+ if (key == nullptr) {
fprintf(stderr, "Failed to parse RSA key.\n");
ERR_print_errors_fp(stderr);
return false;
}
- if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key, selected)) {
+ if (!SpeedRSA("RSA 2048 (3 prime, e=3)", key.get(), selected)) {
return false;
}
- RSA_free(key);
- key = RSA_private_key_from_bytes(kDERRSAPrivate4096,
- kDERRSAPrivate4096Len);
- if (key == NULL) {
+ key.reset(
+ RSA_private_key_from_bytes(kDERRSAPrivate4096, kDERRSAPrivate4096Len));
+ if (key == nullptr) {
fprintf(stderr, "Failed to parse 4096-bit RSA key.\n");
ERR_print_errors_fp(stderr);
return 1;
}
- if (!SpeedRSA("RSA 4096", key, selected)) {
+ if (!SpeedRSA("RSA 4096", key.get(), selected)) {
return false;
}
- RSA_free(key);
+ key.reset();
// kTLSADLen is the number of bytes of additional data that TLS passes to
// AEADs.
diff --git a/src/tool/transport_common.cc b/src/tool/transport_common.cc
index d5326b5c..7eed8ba4 100644
--- a/src/tool/transport_common.cc
+++ b/src/tool/transport_common.cc
@@ -154,7 +154,7 @@ bool Accept(int *out_sock, const std::string &port) {
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
- addr.sin6_addr = in6addr_any;
+ addr.sin6_addr = IN6ADDR_ANY_INIT;
addr.sin6_port = htons(atoi(port.c_str()));
bool ok = false;
@@ -267,17 +267,21 @@ void PrintConnectionInfo(const SSL *ssl) {
SSL_get0_alpn_selected(ssl, &alpn, &alpn_len);
fprintf(stderr, " ALPN protocol: %.*s\n", alpn_len, alpn);
+ const char *host_name = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+ if (host_name != nullptr && SSL_is_server(ssl)) {
+ fprintf(stderr, " Client sent SNI: %s\n", host_name);
+ }
+
// Print the server cert subject and issuer names.
- X509 *peer = SSL_get_peer_certificate(ssl);
- if (peer != NULL) {
+ bssl::UniquePtr<X509> peer(SSL_get_peer_certificate(ssl));
+ if (peer != nullptr) {
fprintf(stderr, " Cert subject: ");
- X509_NAME_print_ex_fp(stderr, X509_get_subject_name(peer), 0,
+ X509_NAME_print_ex_fp(stderr, X509_get_subject_name(peer.get()), 0,
XN_FLAG_ONELINE);
fprintf(stderr, "\n Cert issuer: ");
- X509_NAME_print_ex_fp(stderr, X509_get_issuer_name(peer), 0,
+ X509_NAME_print_ex_fp(stderr, X509_get_issuer_name(peer.get()), 0,
XN_FLAG_ONELINE);
fprintf(stderr, "\n");
- X509_free(peer);
}
}
diff --git a/src/util/all_tests.json b/src/util/all_tests.json
index ac4b3c7a..d2e39ce1 100644
--- a/src/util/all_tests.json
+++ b/src/util/all_tests.json
@@ -35,6 +35,7 @@
["crypto/dsa/dsa_test"],
["crypto/ec/ec_test"],
["crypto/ec/example_mul"],
+ ["crypto/ec/p256-x86_64_test", "crypto/ec/p256-x86_64_tests.txt"],
["crypto/ecdh/ecdh_test", "crypto/ecdh/ecdh_tests.txt"],
["crypto/ecdsa/ecdsa_sign_test", "crypto/ecdsa/ecdsa_sign_tests.txt"],
["crypto/ecdsa/ecdsa_test"],
@@ -54,6 +55,7 @@
["crypto/pkcs8/pkcs12_test"],
["crypto/pkcs8/pkcs8_test"],
["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_tests.txt"],
+ ["crypto/pool/pool_test"],
["crypto/refcount_test"],
["crypto/rsa/rsa_test"],
["crypto/thread_test"],
diff --git a/src/util/bot/DEPS b/src/util/bot/DEPS
index c57864cb..0452d552 100644
--- a/src/util/bot/DEPS
+++ b/src/util/bot/DEPS
@@ -24,10 +24,15 @@ deps = {
deps_os = {
'android': {
'boringssl/util/bot/android_tools':
- Var('chromium_git') + '/android_tools.git' + '@' + 'af1c5a4cd6329ccdcf8c2bc93d9eea02f9d74869',
+ Var('chromium_git') + '/android_tools.git' + '@' + 'c02a002b48d6637714ef98f0e4bf6952b9c4cf10',
},
}
+recursedeps = [
+ # android_tools pulls in the NDK from a separate repository.
+ 'boringssl/util/bot/android_tools',
+]
+
hooks = [
{
'name': 'cmake_linux64',
diff --git a/src/util/bot/go/bootstrap.py b/src/util/bot/go/bootstrap.py
index 058cc6c8..5661be2d 100755
--- a/src/util/bot/go/bootstrap.py
+++ b/src/util/bot/go/bootstrap.py
@@ -45,7 +45,7 @@ WORKSPACE = os.path.join(ROOT, 'go')
EXE_SFX = '.exe' if sys.platform == 'win32' else ''
# Pinned version of Go toolset to download.
-TOOLSET_VERSION = 'go1.7'
+TOOLSET_VERSION = 'go1.7.3'
# Platform dependent portion of a download URL. See http://golang.org/dl/.
TOOLSET_VARIANTS = {
diff --git a/src/util/bot/update_clang.py b/src/util/bot/update_clang.py
index cd446e84..32fb01a5 100644
--- a/src/util/bot/update_clang.py
+++ b/src/util/bot/update_clang.py
@@ -22,7 +22,7 @@ import urllib
# CLANG_REVISION and CLANG_SUB_REVISION determine the build of clang
# to use. These should be synced with tools/clang/scripts/update.py in
# Chromium.
-CLANG_REVISION = "280106"
+CLANG_REVISION = "284979"
CLANG_SUB_REVISION = "1"
PACKAGE_VERSION = "%s-%s" % (CLANG_REVISION, CLANG_SUB_REVISION)
diff --git a/src/util/bot/vs_toolchain.py b/src/util/bot/vs_toolchain.py
index f90bb466..201b000f 100644
--- a/src/util/bot/vs_toolchain.py
+++ b/src/util/bot/vs_toolchain.py
@@ -19,7 +19,7 @@ import gyp
TOOLCHAIN_VERSION = '2015'
-TOOLCHAIN_HASH = '95ddda401ec5678f15eeed01d2bee08fcbc5ee97'
+TOOLCHAIN_HASH = 'd5dc33b15d1b2c086f2f6632e2fd15882f80dbd3'
def SetEnvironmentAndGetRuntimeDllDirs():
diff --git a/src/util/doc.config b/src/util/doc.config
index e7cfa82d..f3f3d523 100644
--- a/src/util/doc.config
+++ b/src/util/doc.config
@@ -14,6 +14,7 @@
"include/openssl/lhash.h",
"include/openssl/mem.h",
"include/openssl/obj.h",
+ "include/openssl/pool.h",
"include/openssl/rand.h",
"include/openssl/stack.h",
"include/openssl/time_support.h"
diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py
index 0b84bfd8..aae158d1 100644
--- a/src/util/generate_build_files.py
+++ b/src/util/generate_build_files.py
@@ -266,7 +266,7 @@ class Bazel(object):
out.write(' "%s",\n' % arg)
out.write(' ],\n')
- out.write(' copts = copts,\n')
+ out.write(' copts = copts + ["-DBORINGSSL_SHARED_LIBRARY"],\n')
if len(data_files) > 0:
out.write(' data = [\n')
diff --git a/src/util/run_android_tests.go b/src/util/run_android_tests.go
index fe5392a5..8e42596f 100644
--- a/src/util/run_android_tests.go
+++ b/src/util/run_android_tests.go
@@ -241,7 +241,6 @@ func main() {
binaries = append(binaries, "ssl/test/bssl_shim")
files = append(files,
"BUILDING.md",
- "util/all_tests.json",
"ssl/test/runner/cert.pem",
"ssl/test/runner/channel_id_key.pem",
"ssl/test/runner/ecdsa_p256_cert.pem",
@@ -253,6 +252,9 @@ func main() {
"ssl/test/runner/key.pem",
"ssl/test/runner/rsa_1024_cert.pem",
"ssl/test/runner/rsa_1024_key.pem",
+ "ssl/test/runner/rsa_chain_cert.pem",
+ "ssl/test/runner/rsa_chain_key.pem",
+ "util/all_tests.json",
)
fmt.Printf("Building runner...\n")