diff options
author | Steven Valdez <svaldez@google.com> | 2016-11-21 15:35:44 -0500 |
---|---|---|
committer | Steven Valdez <svaldez@google.com> | 2016-11-22 10:25:59 -0500 |
commit | 909b19f027eb0af12513f4d5589efdd67e34bd91 (patch) | |
tree | 45a240b1d683dbc5599bd3d397f80d794148d6c0 /src | |
parent | 95add82835138f09cf7bb4a51c04c6320c241674 (diff) | |
download | boringssl-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')
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(©) != 0) { + uint16_t type; + CBS data; + if (!CBS_get_u16(©, &type) || + !CBS_get_u16_length_prefixed(©, &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(©, &sct_list) || + CBS_len(©) != 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") |