diff options
author | Steven Valdez <svaldez@google.com> | 2016-10-07 10:34:51 -0400 |
---|---|---|
committer | Steven Valdez <svaldez@google.com> | 2016-10-10 10:12:47 -0400 |
commit | bb1ceac29bc7a18b94e3da78057dc41aa7071784 (patch) | |
tree | d2c33595946806d8cbc75201ada3e044382727ce /src | |
parent | 7c0d06c221ce9edf44bbf978b909b38a0aee2084 (diff) | |
download | boringssl-bb1ceac29bc7a18b94e3da78057dc41aa7071784.tar.gz |
external/boringssl: Sync to 3cbdc346.android-n-mr1-preview-2android-n-mr1-preview-1
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/e34bcc91c07c0bf65ecc53a814d51f5246007150..3cbdc34619daafb9f8527fb9dd27afc8ee7dcf19
This removes android_compat_keywrap.c, as these APIs are now provided
natively by BoringSSL.
Test: cts-tradefed run cts -m CtsLibcoreTestCases -m
CtsLibcoreOkHttpTestCases -a arm64-v8a
Change-Id: I29bce93c45eb5b80fa739667bf6e357e0af03b7f
Diffstat (limited to 'src')
76 files changed, 7903 insertions, 1555 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7438caf6..3d1ea78d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -121,8 +121,8 @@ if(NOT WIN32) endif() if(FUZZ) - if(!CMAKE_CXX_COMPILER_ID MATCHES "Clang") - message("You need to build with Clang for fuzzing to work") + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + message(FATAL_ERROR "You need to build with Clang for fuzzing to work") endif() add_definitions(-DBORINGSSL_UNSAFE_FUZZER_MODE) @@ -214,9 +214,9 @@ add_custom_target( run_tests COMMAND ${GO_EXECUTABLE} run util/all_tests.go -build-dir ${CMAKE_BINARY_DIR} - COMMAND cd ssl/test/runner - COMMAND ${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim> - ${RUNNER_ARGS} + COMMAND cd ssl/test/runner && + ${GO_EXECUTABLE} test -shim-path $<TARGET_FILE:bssl_shim> + ${RUNNER_ARGS} WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} DEPENDS all_tests bssl_shim ${MAYBE_USES_TERMINAL}) diff --git a/src/FUZZING.md b/src/FUZZING.md index 9f4edef1..1a214030 100644 --- a/src/FUZZING.md +++ b/src/FUZZING.md @@ -30,15 +30,16 @@ The arguments to `jobs` and `workers` should be the number of cores that you wis The recommended values of `max_len` for each test are: -| Test | `max_len` value | -|------------|-----------------| -| `cert` | 3072 | -| `client` | 20000 | -| `pkcs8` | 2048 | -| `privkey` | 2048 | -| `server` | 4096 | -| `spki` | 1024 | -| `read_pem` | 512 | +| Test | `max_len` value | +|---------------|-----------------| +| `cert` | 3072 | +| `client` | 20000 | +| `pkcs8` | 2048 | +| `privkey` | 2048 | +| `server` | 4096 | +| `spki` | 1024 | +| `read_pem` | 512 | +| `ssl_ctx_api` | 256 | These were determined by rounding up the length of the largest case in the corpus. @@ -60,4 +61,31 @@ When `-DFUZZ=1` is passed into CMake, BoringSSL builds with `BORINGSSL_UNSAFE_FU * 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: + +``` +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/ +``` + +Note the suppressions file is ignored so disabled tests record transcripts too. Then merge into the existing corpora: + +``` +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 +``` diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 5182a4a8..4cc5ae26 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -17,6 +17,8 @@ elseif(UNIX) elseif (${ARCH} STREQUAL "x86") set(PERLASM_FLAGS "-fPIC -DOPENSSL_IA32_SSE2") set(PERLASM_STYLE elf) + elseif (${ARCH} STREQUAL "ppc64le") + set(PERLASM_STYLE ppc64le) else() set(PERLASM_STYLE elf) endif() @@ -45,6 +47,7 @@ function(perlasm dest src) DEPENDS ${src} ${PROJECT_SOURCE_DIR}/crypto/perlasm/arm-xlate.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/ppc-xlate.pl ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl @@ -116,6 +119,7 @@ add_library( cpu-arm.c cpu-arm-linux.c cpu-intel.c + cpu-ppc64le.c crypto.c ex_data.c mem.c diff --git a/src/crypto/aes/CMakeLists.txt b/src/crypto/aes/CMakeLists.txt index 0566e398..33eebf53 100644 --- a/src/crypto/aes/CMakeLists.txt +++ b/src/crypto/aes/CMakeLists.txt @@ -39,12 +39,21 @@ if (${ARCH} STREQUAL "aarch64") ) endif() +if (${ARCH} STREQUAL "ppc64le") + set( + AES_ARCH_SOURCES + + aesp8-ppc.${ASM_EXT} + ) +endif() + add_library( aes OBJECT aes.c + key_wrap.c mode_wrappers.c ${AES_ARCH_SOURCES} @@ -60,6 +69,7 @@ perlasm(aesni-x86.${ASM_EXT} asm/aesni-x86.pl) perlasm(aes-armv4.${ASM_EXT} asm/aes-armv4.pl) perlasm(bsaes-armv7.${ASM_EXT} asm/bsaes-armv7.pl) perlasm(aesv8-armx.${ASM_EXT} asm/aesv8-armx.pl) +perlasm(aesp8-ppc.${ASM_EXT} asm/aesp8-ppc.pl) add_executable( aes_test diff --git a/src/crypto/aes/aes.c b/src/crypto/aes/aes.c index 88239198..1aed63e5 100644 --- a/src/crypto/aes/aes.c +++ b/src/crypto/aes/aes.c @@ -1066,12 +1066,12 @@ static int hwaes_capable(void) { return CRYPTO_is_ARMv8_AES_capable(); } -int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, +int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits, AES_KEY *key); -int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, +int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits, AES_KEY *key); -void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); #else @@ -1079,19 +1079,19 @@ static int hwaes_capable(void) { return 0; } -static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { +static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { +static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { +static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { +static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } @@ -1106,7 +1106,7 @@ static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) void asm_AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { if (hwaes_capable()) { - aes_v8_encrypt(in, out, key); + aes_hw_encrypt(in, out, key); } else { asm_AES_encrypt(in, out, key); } @@ -1115,7 +1115,7 @@ void AES_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { void asm_AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { if (hwaes_capable()) { - aes_v8_decrypt(in, out, key); + aes_hw_decrypt(in, out, key); } else { asm_AES_decrypt(in, out, key); } @@ -1124,7 +1124,7 @@ void AES_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { int asm_AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { if (hwaes_capable()) { - return aes_v8_set_encrypt_key(key, bits, aeskey); + return aes_hw_set_encrypt_key(key, bits, aeskey); } else { return asm_AES_set_encrypt_key(key, bits, aeskey); } @@ -1133,7 +1133,7 @@ int AES_set_encrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { int asm_AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey); int AES_set_decrypt_key(const uint8_t *key, unsigned bits, AES_KEY *aeskey) { if (hwaes_capable()) { - return aes_v8_set_decrypt_key(key, bits, aeskey); + return aes_hw_set_decrypt_key(key, bits, aeskey); } else { return asm_AES_set_decrypt_key(key, bits, aeskey); } diff --git a/src/crypto/aes/aes_test.cc b/src/crypto/aes/aes_test.cc index e488d81d..4fb3a31f 100644 --- a/src/crypto/aes/aes_test.cc +++ b/src/crypto/aes/aes_test.cc @@ -15,88 +15,168 @@ #include <stdio.h> #include <string.h> +#include <memory> +#include <vector> + #include <openssl/aes.h> #include <openssl/crypto.h> +#include "../test/file_test.h" + + +static bool TestRaw(FileTest *t) { + std::vector<uint8_t> key, plaintext, ciphertext; + if (!t->GetBytes(&key, "Key") || + !t->GetBytes(&plaintext, "Plaintext") || + !t->GetBytes(&ciphertext, "Ciphertext")) { + return false; + } + + if (plaintext.size() != AES_BLOCK_SIZE || + ciphertext.size() != AES_BLOCK_SIZE) { + t->PrintLine("Plaintext or Ciphertext not a block size."); + return false; + } -static bool TestAES(const uint8_t *key, size_t key_len, - const uint8_t plaintext[AES_BLOCK_SIZE], - const uint8_t ciphertext[AES_BLOCK_SIZE]) { AES_KEY aes_key; - if (AES_set_encrypt_key(key, key_len * 8, &aes_key) != 0) { - fprintf(stderr, "AES_set_encrypt_key failed\n"); + if (AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) { + t->PrintLine("AES_set_encrypt_key failed."); return false; } // Test encryption. uint8_t block[AES_BLOCK_SIZE]; - AES_encrypt(plaintext, block, &aes_key); - if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) { - fprintf(stderr, "AES_encrypt gave the wrong output\n"); + AES_encrypt(plaintext.data(), block, &aes_key); + if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(), + ciphertext.size())) { + t->PrintLine("AES_encrypt gave the wrong output."); return false; } // Test in-place encryption. - memcpy(block, plaintext, AES_BLOCK_SIZE); + memcpy(block, plaintext.data(), AES_BLOCK_SIZE); AES_encrypt(block, block, &aes_key); - if (memcmp(block, ciphertext, AES_BLOCK_SIZE) != 0) { - fprintf(stderr, "AES_encrypt gave the wrong output\n"); + if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, ciphertext.data(), + ciphertext.size())) { + t->PrintLine("In-place AES_encrypt gave the wrong output."); return false; } - if (AES_set_decrypt_key(key, key_len * 8, &aes_key) != 0) { - fprintf(stderr, "AES_set_decrypt_key failed\n"); + if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) { + t->PrintLine("AES_set_decrypt_key failed."); return false; } // Test decryption. - AES_decrypt(ciphertext, block, &aes_key); - if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) { - fprintf(stderr, "AES_decrypt gave the wrong output\n"); + AES_decrypt(ciphertext.data(), block, &aes_key); + if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(), + plaintext.size())) { + t->PrintLine("AES_decrypt gave the wrong output."); return false; } // Test in-place decryption. - memcpy(block, ciphertext, AES_BLOCK_SIZE); + memcpy(block, ciphertext.data(), AES_BLOCK_SIZE); AES_decrypt(block, block, &aes_key); - if (memcmp(block, plaintext, AES_BLOCK_SIZE) != 0) { - fprintf(stderr, "AES_decrypt gave the wrong output\n"); + if (!t->ExpectBytesEqual(block, AES_BLOCK_SIZE, plaintext.data(), + plaintext.size())) { + t->PrintLine("In-place AES_decrypt gave the wrong output."); return false; } + return true; } -int main() { +static bool TestKeyWrap(FileTest *t) { + // All test vectors use the default IV, so test both with implicit and + // explicit IV. + // + // TODO(davidben): Find test vectors that use a different IV. + static const uint8_t kDefaultIV[] = { + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + }; + + std::vector<uint8_t> key, plaintext, ciphertext; + if (!t->GetBytes(&key, "Key") || + !t->GetBytes(&plaintext, "Plaintext") || + !t->GetBytes(&ciphertext, "Ciphertext")) { + return false; + } + + if (plaintext.size() + 8 != ciphertext.size()) { + t->PrintLine("Invalid Plaintext and Ciphertext lengths."); + return false; + } + + AES_KEY aes_key; + if (AES_set_encrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) { + t->PrintLine("AES_set_encrypt_key failed."); + return false; + } + + std::unique_ptr<uint8_t[]> buf(new uint8_t[ciphertext.size()]); + if (AES_wrap_key(&aes_key, nullptr /* iv */, buf.get(), plaintext.data(), + plaintext.size()) != static_cast<int>(ciphertext.size()) || + !t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(), + ciphertext.size())) { + t->PrintLine("AES_wrap_key with implicit IV failed."); + return false; + } + + memset(buf.get(), 0, ciphertext.size()); + if (AES_wrap_key(&aes_key, kDefaultIV, buf.get(), plaintext.data(), + plaintext.size()) != static_cast<int>(ciphertext.size()) || + !t->ExpectBytesEqual(buf.get(), ciphertext.size(), ciphertext.data(), + ciphertext.size())) { + t->PrintLine("AES_wrap_key with explicit IV failed."); + return false; + } + + if (AES_set_decrypt_key(key.data(), 8 * key.size(), &aes_key) != 0) { + t->PrintLine("AES_set_decrypt_key failed."); + return false; + } + + buf.reset(new uint8_t[plaintext.size()]); + if (AES_unwrap_key(&aes_key, nullptr /* iv */, buf.get(), ciphertext.data(), + ciphertext.size()) != static_cast<int>(plaintext.size()) || + !t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(), + plaintext.size())) { + t->PrintLine("AES_unwrap_key with implicit IV failed."); + return false; + } + + memset(buf.get(), 0, plaintext.size()); + if (AES_unwrap_key(&aes_key, kDefaultIV, buf.get(), ciphertext.data(), + ciphertext.size()) != static_cast<int>(plaintext.size()) || + !t->ExpectBytesEqual(buf.get(), plaintext.size(), plaintext.data(), + plaintext.size())) { + t->PrintLine("AES_unwrap_key with explicit IV failed."); + return false; + } + + return true; +} + +static bool TestAES(FileTest *t, void *arg) { + if (t->GetParameter() == "Raw") { + return TestRaw(t); + } + if (t->GetParameter() == "KeyWrap") { + return TestKeyWrap(t); + } + + t->PrintLine("Unknown mode '%s'.", t->GetParameter().c_str()); + return false; +} + +int main(int argc, char **argv) { CRYPTO_library_init(); - // Test vectors from FIPS-197, Appendix C. - if (!TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f", - 128 / 8, - (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77" - "\x88\x99\xaa\xbb\xcc\xdd\xee\xff", - (const uint8_t *)"\x69\xc4\xe0\xd8\x6a\x7b\x04\x30" - "\xd8\xcd\xb7\x80\x70\xb4\xc5\x5a") || - !TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17", - 192 / 8, - (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77" - "\x88\x99\xaa\xbb\xcc\xdd\xee\xff", - (const uint8_t *)"\xdd\xa9\x7c\xa4\x86\x4c\xdf\xe0" - "\x6e\xaf\x70\xa0\xec\x0d\x71\x91") || - !TestAES((const uint8_t *)"\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", - 256 / 8, - (const uint8_t *)"\x00\x11\x22\x33\x44\x55\x66\x77" - "\x88\x99\xaa\xbb\xcc\xdd\xee\xff", - (const uint8_t *)"\x8e\xa2\xb7\xca\x51\x67\x45\xbf" - "\xea\xfc\x49\x90\x4b\x49\x60\x89")) { - return false; - } - - printf("PASS\n"); - return 0; + if (argc != 2) { + fprintf(stderr, "%s <test file.txt>\n", argv[0]); + return 1; + } + + return FileTestMain(TestAES, nullptr, argv[1]); } diff --git a/src/crypto/aes/aes_tests.txt b/src/crypto/aes/aes_tests.txt new file mode 100644 index 00000000..d4e4c61b --- /dev/null +++ b/src/crypto/aes/aes_tests.txt @@ -0,0 +1,50 @@ +# Test vectors from FIPS-197, Appendix C. + +Mode = Raw +Key = 000102030405060708090a0b0c0d0e0f +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = 69c4e0d86a7b0430d8cdb78070b4c55a + +Mode = Raw +Key = 000102030405060708090a0b0c0d0e0f1011121314151617 +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = dda97ca4864cdfe06eaf70a0ec0d7191 + +Mode = Raw +Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = 8ea2b7ca516745bfeafc49904b496089 + + +# Test vectors from +# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = 1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5 + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f1011121314151617 +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = 96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +Plaintext = 00112233445566778899aabbccddeeff +Ciphertext = 64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7 + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f1011121314151617 +Plaintext = 00112233445566778899aabbccddeeff0001020304050607 +Ciphertext = 031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2 + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +Plaintext = 00112233445566778899aabbccddeeff0001020304050607 +Ciphertext = a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1 + +Mode = KeyWrap +Key = 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f +Plaintext = 00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f +Ciphertext = 28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21 diff --git a/src/crypto/aes/asm/aesp8-ppc.pl b/src/crypto/aes/asm/aesp8-ppc.pl new file mode 100644 index 00000000..4bdcff74 --- /dev/null +++ b/src/crypto/aes/asm/aesp8-ppc.pl @@ -0,0 +1,3805 @@ +#! /usr/bin/env perl +# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +# +# ==================================================================== +# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# This module implements support for AES instructions as per PowerISA +# specification version 2.07, first implemented by POWER8 processor. +# The module is endian-agnostic in sense that it supports both big- +# and little-endian cases. Data alignment in parallelizable modes is +# handled with VSX loads and stores, which implies MSR.VSX flag being +# set. It should also be noted that ISA specification doesn't prohibit +# alignment exceptions for these instructions on page boundaries. +# Initially alignment was handled in pure AltiVec/VMX way [when data +# is aligned programmatically, which in turn guarantees exception- +# free execution], but it turned to hamper performance when vcipher +# instructions are interleaved. It's reckoned that eventual +# misalignment penalties at page boundaries are in average lower +# than additional overhead in pure AltiVec approach. +# +# May 2016 +# +# Add XTS subroutine, 9x on little- and 12x improvement on big-endian +# systems were measured. +# +###################################################################### +# Current large-block performance in cycles per byte processed with +# 128-bit key (less is better). +# +# CBC en-/decrypt CTR XTS +# POWER8[le] 3.96/0.72 0.74 1.1 +# POWER8[be] 3.75/0.65 0.66 1.0 + +$flavour = shift; + +if ($flavour =~ /64/) { + $SIZE_T =8; + $LRSAVE =2*$SIZE_T; + $STU ="stdu"; + $POP ="ld"; + $PUSH ="std"; + $UCMP ="cmpld"; + $SHL ="sldi"; +} elsif ($flavour =~ /32/) { + $SIZE_T =4; + $LRSAVE =$SIZE_T; + $STU ="stwu"; + $POP ="lwz"; + $PUSH ="stw"; + $UCMP ="cmplw"; + $SHL ="slwi"; +} else { die "nonsense $flavour"; } + +$LITTLE_ENDIAN = ($flavour=~/le$/) ? $SIZE_T : 0; + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or +die "can't locate ppc-xlate.pl"; + +open STDOUT,"| $^X $xlate $flavour ".shift || die "can't call $xlate: $!"; + +$FRAME=8*$SIZE_T; +$prefix="aes_hw"; + +$sp="r1"; +$vrsave="r12"; + +######################################################################### +{{{ # Key setup procedures # +my ($inp,$bits,$out,$ptr,$cnt,$rounds)=map("r$_",(3..8)); +my ($zero,$in0,$in1,$key,$rcon,$mask,$tmp)=map("v$_",(0..6)); +my ($stage,$outperm,$outmask,$outhead,$outtail)=map("v$_",(7..11)); + +$code.=<<___; +.machine "any" + +.text + +.align 7 +rcon: +.long 0x01000000, 0x01000000, 0x01000000, 0x01000000 ?rev +.long 0x1b000000, 0x1b000000, 0x1b000000, 0x1b000000 ?rev +.long 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c, 0x0d0e0f0c ?rev +.long 0,0,0,0 ?asis +Lconsts: + mflr r0 + bcl 20,31,\$+4 + mflr $ptr #vvvvv "distance between . and rcon + addi $ptr,$ptr,-0x48 + mtlr r0 + blr + .long 0 + .byte 0,12,0x14,0,0,0,0,0 +.asciz "AES for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>" + +.globl .${prefix}_set_encrypt_key +.align 5 +.${prefix}_set_encrypt_key: +Lset_encrypt_key: + mflr r11 + $PUSH r11,$LRSAVE($sp) + + li $ptr,-1 + ${UCMP}i $inp,0 + beq- Lenc_key_abort # if ($inp==0) return -1; + ${UCMP}i $out,0 + beq- Lenc_key_abort # if ($out==0) return -1; + li $ptr,-2 + cmpwi $bits,128 + blt- Lenc_key_abort + cmpwi $bits,256 + bgt- Lenc_key_abort + andi. r0,$bits,0x3f + bne- Lenc_key_abort + + lis r0,0xfff0 + mfspr $vrsave,256 + mtspr 256,r0 + + bl Lconsts + mtlr r11 + + neg r9,$inp + lvx $in0,0,$inp + addi $inp,$inp,15 # 15 is not typo + lvsr $key,0,r9 # borrow $key + li r8,0x20 + cmpwi $bits,192 + lvx $in1,0,$inp + le?vspltisb $mask,0x0f # borrow $mask + lvx $rcon,0,$ptr + le?vxor $key,$key,$mask # adjust for byte swap + lvx $mask,r8,$ptr + addi $ptr,$ptr,0x10 + vperm $in0,$in0,$in1,$key # align [and byte swap in LE] + li $cnt,8 + vxor $zero,$zero,$zero + mtctr $cnt + + ?lvsr $outperm,0,$out + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$zero,$outmask,$outperm + + blt Loop128 + addi $inp,$inp,8 + beq L192 + addi $inp,$inp,8 + b L256 + +.align 4 +Loop128: + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + bdnz Loop128 + + lvx $rcon,0,$ptr # last two round keys + + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + + vperm $key,$in0,$in0,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vxor $in0,$in0,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + + addi $inp,$out,15 # 15 is not typo + addi $out,$out,0x50 + + li $rounds,10 + b Ldone + +.align 4 +L192: + lvx $tmp,0,$inp + li $cnt,4 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $out,$out,16 + vperm $in1,$in1,$tmp,$key # align [and byte swap in LE] + vspltisb $key,8 # borrow $key + mtctr $cnt + vsububm $mask,$mask,$key # adjust the mask + +Loop192: + vperm $key,$in1,$in1,$mask # roate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vcipherlast $key,$key,$rcon + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + + vsldoi $stage,$zero,$in1,8 + vspltw $tmp,$in0,3 + vxor $tmp,$tmp,$in1 + vsldoi $in1,$zero,$in1,12 # >>32 + vadduwm $rcon,$rcon,$rcon + vxor $in1,$in1,$tmp + vxor $in0,$in0,$key + vxor $in1,$in1,$key + vsldoi $stage,$stage,$in0,8 + + vperm $key,$in1,$in1,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$stage,$stage,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vsldoi $stage,$in0,$in1,8 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vperm $outtail,$stage,$stage,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + stvx $stage,0,$out + addi $out,$out,16 + + vspltw $tmp,$in0,3 + vxor $tmp,$tmp,$in1 + vsldoi $in1,$zero,$in1,12 # >>32 + vadduwm $rcon,$rcon,$rcon + vxor $in1,$in1,$tmp + vxor $in0,$in0,$key + vxor $in1,$in1,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $inp,$out,15 # 15 is not typo + addi $out,$out,16 + bdnz Loop192 + + li $rounds,12 + addi $out,$out,0x20 + b Ldone + +.align 4 +L256: + lvx $tmp,0,$inp + li $cnt,7 + li $rounds,14 + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $out,$out,16 + vperm $in1,$in1,$tmp,$key # align [and byte swap in LE] + mtctr $cnt + +Loop256: + vperm $key,$in1,$in1,$mask # rotate-n-splat + vsldoi $tmp,$zero,$in0,12 # >>32 + vperm $outtail,$in1,$in1,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + vcipherlast $key,$key,$rcon + stvx $stage,0,$out + addi $out,$out,16 + + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in0,$in0,$tmp + vadduwm $rcon,$rcon,$rcon + vxor $in0,$in0,$key + vperm $outtail,$in0,$in0,$outperm # rotate + vsel $stage,$outhead,$outtail,$outmask + vmr $outhead,$outtail + stvx $stage,0,$out + addi $inp,$out,15 # 15 is not typo + addi $out,$out,16 + bdz Ldone + + vspltw $key,$in0,3 # just splat + vsldoi $tmp,$zero,$in1,12 # >>32 + vsbox $key,$key + + vxor $in1,$in1,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in1,$in1,$tmp + vsldoi $tmp,$zero,$tmp,12 # >>32 + vxor $in1,$in1,$tmp + + vxor $in1,$in1,$key + b Loop256 + +.align 4 +Ldone: + lvx $in1,0,$inp # redundant in aligned case + vsel $in1,$outhead,$in1,$outmask + stvx $in1,0,$inp + li $ptr,0 + mtspr 256,$vrsave + stw $rounds,0($out) + +Lenc_key_abort: + mr r3,$ptr + blr + .long 0 + .byte 0,12,0x14,1,0,0,3,0 + .long 0 +.size .${prefix}_set_encrypt_key,.-.${prefix}_set_encrypt_key + +.globl .${prefix}_set_decrypt_key +.align 5 +.${prefix}_set_decrypt_key: + $STU $sp,-$FRAME($sp) + mflr r10 + $PUSH r10,$FRAME+$LRSAVE($sp) + bl Lset_encrypt_key + mtlr r10 + + cmpwi r3,0 + bne- Ldec_key_abort + + slwi $cnt,$rounds,4 + subi $inp,$out,240 # first round key + srwi $rounds,$rounds,1 + add $out,$inp,$cnt # last round key + mtctr $rounds + +Ldeckey: + lwz r0, 0($inp) + lwz r6, 4($inp) + lwz r7, 8($inp) + lwz r8, 12($inp) + addi $inp,$inp,16 + lwz r9, 0($out) + lwz r10,4($out) + lwz r11,8($out) + lwz r12,12($out) + stw r0, 0($out) + stw r6, 4($out) + stw r7, 8($out) + stw r8, 12($out) + subi $out,$out,16 + stw r9, -16($inp) + stw r10,-12($inp) + stw r11,-8($inp) + stw r12,-4($inp) + bdnz Ldeckey + + xor r3,r3,r3 # return value +Ldec_key_abort: + addi $sp,$sp,$FRAME + blr + .long 0 + .byte 0,12,4,1,0x80,0,3,0 + .long 0 +.size .${prefix}_set_decrypt_key,.-.${prefix}_set_decrypt_key +___ +}}} +######################################################################### +{{{ # Single block en- and decrypt procedures # +sub gen_block () { +my $dir = shift; +my $n = $dir eq "de" ? "n" : ""; +my ($inp,$out,$key,$rounds,$idx)=map("r$_",(3..7)); + +$code.=<<___; +.globl .${prefix}_${dir}crypt +.align 5 +.${prefix}_${dir}crypt: + lwz $rounds,240($key) + lis r0,0xfc00 + mfspr $vrsave,256 + li $idx,15 # 15 is not typo + mtspr 256,r0 + + lvx v0,0,$inp + neg r11,$out + lvx v1,$idx,$inp + lvsl v2,0,$inp # inpperm + le?vspltisb v4,0x0f + ?lvsl v3,0,r11 # outperm + le?vxor v2,v2,v4 + li $idx,16 + vperm v0,v0,v1,v2 # align [and byte swap in LE] + lvx v1,0,$key + ?lvsl v5,0,$key # keyperm + srwi $rounds,$rounds,1 + lvx v2,$idx,$key + addi $idx,$idx,16 + subi $rounds,$rounds,1 + ?vperm v1,v1,v2,v5 # align round key + + vxor v0,v0,v1 + lvx v1,$idx,$key + addi $idx,$idx,16 + mtctr $rounds + +Loop_${dir}c: + ?vperm v2,v2,v1,v5 + v${n}cipher v0,v0,v2 + lvx v2,$idx,$key + addi $idx,$idx,16 + ?vperm v1,v1,v2,v5 + v${n}cipher v0,v0,v1 + lvx v1,$idx,$key + addi $idx,$idx,16 + bdnz Loop_${dir}c + + ?vperm v2,v2,v1,v5 + v${n}cipher v0,v0,v2 + lvx v2,$idx,$key + ?vperm v1,v1,v2,v5 + v${n}cipherlast v0,v0,v1 + + vspltisb v2,-1 + vxor v1,v1,v1 + li $idx,15 # 15 is not typo + ?vperm v2,v1,v2,v3 # outmask + le?vxor v3,v3,v4 + lvx v1,0,$out # outhead + vperm v0,v0,v0,v3 # rotate [and byte swap in LE] + vsel v1,v1,v0,v2 + lvx v4,$idx,$out + stvx v1,0,$out + vsel v0,v0,v4,v2 + stvx v0,$idx,$out + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,3,0 + .long 0 +.size .${prefix}_${dir}crypt,.-.${prefix}_${dir}crypt +___ +} +&gen_block("en"); +&gen_block("de"); +}}} +######################################################################### +{{{ # CBC en- and decrypt procedures # +my ($inp,$out,$len,$key,$ivp,$enc,$rounds,$idx)=map("r$_",(3..10)); +my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3)); +my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm)= + map("v$_",(4..10)); +$code.=<<___; +.globl .${prefix}_cbc_encrypt +.align 5 +.${prefix}_cbc_encrypt: + ${UCMP}i $len,16 + bltlr- + + cmpwi $enc,0 # test direction + lis r0,0xffe0 + mfspr $vrsave,256 + mtspr 256,r0 + + li $idx,15 + vxor $rndkey0,$rndkey0,$rndkey0 + le?vspltisb $tmp,0x0f + + lvx $ivec,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + le?vxor $inpperm,$inpperm,$tmp + vperm $ivec,$ivec,$inptail,$inpperm + + neg r11,$inp + ?lvsl $keyperm,0,$key # prepare for unaligned key + lwz $rounds,240($key) + + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inptail,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + ?lvsr $outperm,0,$out # prepare for unaligned store + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + + srwi $rounds,$rounds,1 + li $idx,16 + subi $rounds,$rounds,1 + beq Lcbc_dec + +Lcbc_enc: + vmr $inout,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + mtctr $rounds + subi $len,$len,16 # len-=16 + + lvx $rndkey0,0,$key + vperm $inout,$inout,$inptail,$inpperm + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + vxor $inout,$inout,$ivec + +Loop_cbc_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_cbc_enc + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipherlast $ivec,$inout,$rndkey0 + ${UCMP}i $len,16 + + vperm $tmp,$ivec,$ivec,$outperm + vsel $inout,$outhead,$tmp,$outmask + vmr $outhead,$tmp + stvx $inout,0,$out + addi $out,$out,16 + bge Lcbc_enc + + b Lcbc_done + +.align 4 +Lcbc_dec: + ${UCMP}i $len,128 + bge _aesp8_cbc_decrypt8x + vmr $tmp,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + mtctr $rounds + subi $len,$len,16 # len-=16 + + lvx $rndkey0,0,$key + vperm $tmp,$tmp,$inptail,$inpperm + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$tmp,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + +Loop_cbc_dec: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_cbc_dec + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipherlast $inout,$inout,$rndkey0 + ${UCMP}i $len,16 + + vxor $inout,$inout,$ivec + vmr $ivec,$tmp + vperm $tmp,$inout,$inout,$outperm + vsel $inout,$outhead,$tmp,$outmask + vmr $outhead,$tmp + stvx $inout,0,$out + addi $out,$out,16 + bge Lcbc_dec + +Lcbc_done: + addi $out,$out,-1 + lvx $inout,0,$out # redundant in aligned case + vsel $inout,$outhead,$inout,$outmask + stvx $inout,0,$out + + neg $enc,$ivp # write [unaligned] iv + li $idx,15 # 15 is not typo + vxor $rndkey0,$rndkey0,$rndkey0 + vspltisb $outmask,-1 + le?vspltisb $tmp,0x0f + ?lvsl $outperm,0,$enc + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + lvx $outhead,0,$ivp + vperm $ivec,$ivec,$ivec,$outperm + vsel $inout,$outhead,$ivec,$outmask + lvx $inptail,$idx,$ivp + stvx $inout,0,$ivp + vsel $inout,$ivec,$inptail,$outmask + stvx $inout,$idx,$ivp + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,6,0 + .long 0 +___ +######################################################################### +{{ # Optimized CBC decrypt procedure # +my $key_="r11"; +my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31)); + $x00=0 if ($flavour =~ /osx/); +my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10..13)); +my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(14..21)); +my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys + # v26-v31 last 6 round keys +my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment + +$code.=<<___; +.align 5 +_aesp8_cbc_decrypt8x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + li r10,`$FRAME+8*16+15` + li r11,`$FRAME+8*16+31` + stvx v20,r10,$sp # ABI says so + addi r10,r10,32 + stvx v21,r11,$sp + addi r11,r11,32 + stvx v22,r10,$sp + addi r10,r10,32 + stvx v23,r11,$sp + addi r11,r11,32 + stvx v24,r10,$sp + addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 + stvx v26,r10,$sp + addi r10,r10,32 + stvx v27,r11,$sp + addi r11,r11,32 + stvx v28,r10,$sp + addi r10,r10,32 + stvx v29,r11,$sp + addi r11,r11,32 + stvx v30,r10,$sp + stvx v31,r11,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + subi $len,$len,128 # bias + + lvx $rndkey0,$x00,$key # load key schedule + lvx v30,$x10,$key + addi $key,$key,0x20 + lvx v31,$x00,$key + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_cbc_dec_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key + addi $key,$key,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_cbc_dec_key + + lvx v26,$x10,$key + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key + ?vperm v29,v29,v30,$keyperm + lvx $out0,$x70,$key # borrow $out0 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$out0,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + #lvx $inptail,0,$inp # "caller" already did this + #addi $inp,$inp,15 # 15 is not typo + subi $inp,$inp,15 # undo "caller" + + le?li $idx,8 + lvx_u $in0,$x00,$inp # load first 8 "words" + le?lvsl $inpperm,0,$idx + le?vspltisb $tmp,0x0f + lvx_u $in1,$x10,$inp + le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u + lvx_u $in2,$x20,$inp + le?vperm $in0,$in0,$in0,$inpperm + lvx_u $in3,$x30,$inp + le?vperm $in1,$in1,$in1,$inpperm + lvx_u $in4,$x40,$inp + le?vperm $in2,$in2,$in2,$inpperm + vxor $out0,$in0,$rndkey0 + lvx_u $in5,$x50,$inp + le?vperm $in3,$in3,$in3,$inpperm + vxor $out1,$in1,$rndkey0 + lvx_u $in6,$x60,$inp + le?vperm $in4,$in4,$in4,$inpperm + vxor $out2,$in2,$rndkey0 + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + le?vperm $in5,$in5,$in5,$inpperm + vxor $out3,$in3,$rndkey0 + le?vperm $in6,$in6,$in6,$inpperm + vxor $out4,$in4,$rndkey0 + le?vperm $in7,$in7,$in7,$inpperm + vxor $out5,$in5,$rndkey0 + vxor $out6,$in6,$rndkey0 + vxor $out7,$in7,$rndkey0 + + mtctr $rounds + b Loop_cbc_dec8x +.align 5 +Loop_cbc_dec8x: + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_cbc_dec8x + + subic $len,$len,128 # $len-=128 + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + + subfe. r0,r0,r0 # borrow?-1:0 + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + + and r0,r0,$len + vncipher $out0,$out0,v26 + vncipher $out1,$out1,v26 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vncipher $out4,$out4,v26 + vncipher $out5,$out5,v26 + vncipher $out6,$out6,v26 + vncipher $out7,$out7,v26 + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in7 are loaded + # with last "words" + vncipher $out0,$out0,v27 + vncipher $out1,$out1,v27 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vncipher $out4,$out4,v27 + vncipher $out5,$out5,v27 + vncipher $out6,$out6,v27 + vncipher $out7,$out7,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vncipher $out0,$out0,v28 + vncipher $out1,$out1,v28 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vncipher $out4,$out4,v28 + vncipher $out5,$out5,v28 + vncipher $out6,$out6,v28 + vncipher $out7,$out7,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + + vncipher $out0,$out0,v29 + vncipher $out1,$out1,v29 + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vncipher $out4,$out4,v29 + vncipher $out5,$out5,v29 + vncipher $out6,$out6,v29 + vncipher $out7,$out7,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + + vncipher $out0,$out0,v30 + vxor $ivec,$ivec,v31 # xor with last round key + vncipher $out1,$out1,v30 + vxor $in0,$in0,v31 + vncipher $out2,$out2,v30 + vxor $in1,$in1,v31 + vncipher $out3,$out3,v30 + vxor $in2,$in2,v31 + vncipher $out4,$out4,v30 + vxor $in3,$in3,v31 + vncipher $out5,$out5,v30 + vxor $in4,$in4,v31 + vncipher $out6,$out6,v30 + vxor $in5,$in5,v31 + vncipher $out7,$out7,v30 + vxor $in6,$in6,v31 + + vncipherlast $out0,$out0,$ivec + vncipherlast $out1,$out1,$in0 + lvx_u $in0,$x00,$inp # load next input block + vncipherlast $out2,$out2,$in1 + lvx_u $in1,$x10,$inp + vncipherlast $out3,$out3,$in2 + le?vperm $in0,$in0,$in0,$inpperm + lvx_u $in2,$x20,$inp + vncipherlast $out4,$out4,$in3 + le?vperm $in1,$in1,$in1,$inpperm + lvx_u $in3,$x30,$inp + vncipherlast $out5,$out5,$in4 + le?vperm $in2,$in2,$in2,$inpperm + lvx_u $in4,$x40,$inp + vncipherlast $out6,$out6,$in5 + le?vperm $in3,$in3,$in3,$inpperm + lvx_u $in5,$x50,$inp + vncipherlast $out7,$out7,$in6 + le?vperm $in4,$in4,$in4,$inpperm + lvx_u $in6,$x60,$inp + vmr $ivec,$in7 + le?vperm $in5,$in5,$in5,$inpperm + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $in6,$in6,$in6,$inpperm + vxor $out0,$in0,$rndkey0 + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $in7,$in7,$in7,$inpperm + vxor $out1,$in1,$rndkey0 + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + vxor $out2,$in2,$rndkey0 + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + vxor $out3,$in3,$rndkey0 + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + vxor $out4,$in4,$rndkey0 + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + vxor $out5,$in5,$rndkey0 + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x60,$out + vxor $out6,$in6,$rndkey0 + stvx_u $out7,$x70,$out + addi $out,$out,0x80 + vxor $out7,$in7,$rndkey0 + + mtctr $rounds + beq Loop_cbc_dec8x # did $len-=128 borrow? + + addic. $len,$len,128 + beq Lcbc_dec8x_done + nop + nop + +Loop_cbc_dec8x_tail: # up to 7 "words" tail... + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_cbc_dec8x_tail + + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + vncipher $out6,$out6,v24 + vncipher $out7,$out7,v24 + + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + vncipher $out6,$out6,v25 + vncipher $out7,$out7,v25 + + vncipher $out1,$out1,v26 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vncipher $out4,$out4,v26 + vncipher $out5,$out5,v26 + vncipher $out6,$out6,v26 + vncipher $out7,$out7,v26 + + vncipher $out1,$out1,v27 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vncipher $out4,$out4,v27 + vncipher $out5,$out5,v27 + vncipher $out6,$out6,v27 + vncipher $out7,$out7,v27 + + vncipher $out1,$out1,v28 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vncipher $out4,$out4,v28 + vncipher $out5,$out5,v28 + vncipher $out6,$out6,v28 + vncipher $out7,$out7,v28 + + vncipher $out1,$out1,v29 + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vncipher $out4,$out4,v29 + vncipher $out5,$out5,v29 + vncipher $out6,$out6,v29 + vncipher $out7,$out7,v29 + + vncipher $out1,$out1,v30 + vxor $ivec,$ivec,v31 # last round key + vncipher $out2,$out2,v30 + vxor $in1,$in1,v31 + vncipher $out3,$out3,v30 + vxor $in2,$in2,v31 + vncipher $out4,$out4,v30 + vxor $in3,$in3,v31 + vncipher $out5,$out5,v30 + vxor $in4,$in4,v31 + vncipher $out6,$out6,v30 + vxor $in5,$in5,v31 + vncipher $out7,$out7,v30 + vxor $in6,$in6,v31 + + cmplwi $len,32 # switch($len) + blt Lcbc_dec8x_one + nop + beq Lcbc_dec8x_two + cmplwi $len,64 + blt Lcbc_dec8x_three + nop + beq Lcbc_dec8x_four + cmplwi $len,96 + blt Lcbc_dec8x_five + nop + beq Lcbc_dec8x_six + +Lcbc_dec8x_seven: + vncipherlast $out1,$out1,$ivec + vncipherlast $out2,$out2,$in1 + vncipherlast $out3,$out3,$in2 + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out1,$out1,$out1,$inpperm + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x00,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x10,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x20,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x30,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x40,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x50,$out + stvx_u $out7,$x60,$out + addi $out,$out,0x70 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_six: + vncipherlast $out2,$out2,$ivec + vncipherlast $out3,$out3,$in2 + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out2,$out2,$out2,$inpperm + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x00,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x10,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x20,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x30,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x40,$out + stvx_u $out7,$x50,$out + addi $out,$out,0x60 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_five: + vncipherlast $out3,$out3,$ivec + vncipherlast $out4,$out4,$in3 + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out3,$out3,$out3,$inpperm + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x00,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x10,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x20,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x30,$out + stvx_u $out7,$x40,$out + addi $out,$out,0x50 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_four: + vncipherlast $out4,$out4,$ivec + vncipherlast $out5,$out5,$in4 + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out4,$out4,$out4,$inpperm + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x00,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x10,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x20,$out + stvx_u $out7,$x30,$out + addi $out,$out,0x40 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_three: + vncipherlast $out5,$out5,$ivec + vncipherlast $out6,$out6,$in5 + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out5,$out5,$out5,$inpperm + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x00,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x10,$out + stvx_u $out7,$x20,$out + addi $out,$out,0x30 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_two: + vncipherlast $out6,$out6,$ivec + vncipherlast $out7,$out7,$in6 + vmr $ivec,$in7 + + le?vperm $out6,$out6,$out6,$inpperm + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x00,$out + stvx_u $out7,$x10,$out + addi $out,$out,0x20 + b Lcbc_dec8x_done + +.align 5 +Lcbc_dec8x_one: + vncipherlast $out7,$out7,$ivec + vmr $ivec,$in7 + + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out7,0,$out + addi $out,$out,0x10 + +Lcbc_dec8x_done: + le?vperm $ivec,$ivec,$ivec,$inpperm + stvx_u $ivec,0,$ivp # write [unaligned] iv + + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $inpperm,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x04,0,0x80,6,6,0 + .long 0 +.size .${prefix}_cbc_encrypt,.-.${prefix}_cbc_encrypt +___ +}} }}} + +######################################################################### +{{{ # CTR procedure[s] # +my ($inp,$out,$len,$key,$ivp,$x10,$rounds,$idx)=map("r$_",(3..10)); +my ($rndkey0,$rndkey1,$inout,$tmp)= map("v$_",(0..3)); +my ($ivec,$inptail,$inpperm,$outhead,$outperm,$outmask,$keyperm,$one)= + map("v$_",(4..11)); +my $dat=$tmp; + +$code.=<<___; +.globl .${prefix}_ctr32_encrypt_blocks +.align 5 +.${prefix}_ctr32_encrypt_blocks: + ${UCMP}i $len,1 + bltlr- + + lis r0,0xfff0 + mfspr $vrsave,256 + mtspr 256,r0 + + li $idx,15 + vxor $rndkey0,$rndkey0,$rndkey0 + le?vspltisb $tmp,0x0f + + lvx $ivec,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + vspltisb $one,1 + le?vxor $inpperm,$inpperm,$tmp + vperm $ivec,$ivec,$inptail,$inpperm + vsldoi $one,$rndkey0,$one,1 + + neg r11,$inp + ?lvsl $keyperm,0,$key # prepare for unaligned key + lwz $rounds,240($key) + + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inptail,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + srwi $rounds,$rounds,1 + li $idx,16 + subi $rounds,$rounds,1 + + ${UCMP}i $len,8 + bge _aesp8_ctr32_encrypt8x + + ?lvsr $outperm,0,$out # prepare for unaligned store + vspltisb $outmask,-1 + lvx $outhead,0,$out + ?vperm $outmask,$rndkey0,$outmask,$outperm + le?vxor $outperm,$outperm,$tmp + + lvx $rndkey0,0,$key + mtctr $rounds + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$ivec,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + b Loop_ctr32_enc + +.align 5 +Loop_ctr32_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + bdnz Loop_ctr32_enc + + vadduwm $ivec,$ivec,$one + vmr $dat,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + subic. $len,$len,1 # blocks-- + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key + vperm $dat,$dat,$inptail,$inpperm + li $idx,16 + ?vperm $rndkey1,$rndkey0,$rndkey1,$keyperm + lvx $rndkey0,0,$key + vxor $dat,$dat,$rndkey1 # last round key + vcipherlast $inout,$inout,$dat + + lvx $rndkey1,$idx,$key + addi $idx,$idx,16 + vperm $inout,$inout,$inout,$outperm + vsel $dat,$outhead,$inout,$outmask + mtctr $rounds + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vmr $outhead,$inout + vxor $inout,$ivec,$rndkey0 + lvx $rndkey0,$idx,$key + addi $idx,$idx,16 + stvx $dat,0,$out + addi $out,$out,16 + bne Loop_ctr32_enc + + addi $out,$out,-1 + lvx $inout,0,$out # redundant in aligned case + vsel $inout,$outhead,$inout,$outmask + stvx $inout,0,$out + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,6,0 + .long 0 +___ +######################################################################### +{{ # Optimized CTR procedure # +my $key_="r11"; +my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,8,26..31)); + $x00=0 if ($flavour =~ /osx/); +my ($in0, $in1, $in2, $in3, $in4, $in5, $in6, $in7 )=map("v$_",(0..3,10,12..14)); +my ($out0,$out1,$out2,$out3,$out4,$out5,$out6,$out7)=map("v$_",(15..22)); +my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys + # v26-v31 last 6 round keys +my ($tmp,$keyperm)=($in3,$in4); # aliases with "caller", redundant assignment +my ($two,$three,$four)=($outhead,$outperm,$outmask); + +$code.=<<___; +.align 5 +_aesp8_ctr32_encrypt8x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + li r10,`$FRAME+8*16+15` + li r11,`$FRAME+8*16+31` + stvx v20,r10,$sp # ABI says so + addi r10,r10,32 + stvx v21,r11,$sp + addi r11,r11,32 + stvx v22,r10,$sp + addi r10,r10,32 + stvx v23,r11,$sp + addi r11,r11,32 + stvx v24,r10,$sp + addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 + stvx v26,r10,$sp + addi r10,r10,32 + stvx v27,r11,$sp + addi r11,r11,32 + stvx v28,r10,$sp + addi r10,r10,32 + stvx v29,r11,$sp + addi r11,r11,32 + stvx v30,r10,$sp + stvx v31,r11,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + + lvx $rndkey0,$x00,$key # load key schedule + lvx v30,$x10,$key + addi $key,$key,0x20 + lvx v31,$x00,$key + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_ctr32_enc_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key + addi $key,$key,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_ctr32_enc_key + + lvx v26,$x10,$key + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key + ?vperm v29,v29,v30,$keyperm + lvx $out0,$x70,$key # borrow $out0 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$out0,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + vadduwm $two,$one,$one + subi $inp,$inp,15 # undo "caller" + $SHL $len,$len,4 + + vadduwm $out1,$ivec,$one # counter values ... + vadduwm $out2,$ivec,$two + vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0] + le?li $idx,8 + vadduwm $out3,$out1,$two + vxor $out1,$out1,$rndkey0 + le?lvsl $inpperm,0,$idx + vadduwm $out4,$out2,$two + vxor $out2,$out2,$rndkey0 + le?vspltisb $tmp,0x0f + vadduwm $out5,$out3,$two + vxor $out3,$out3,$rndkey0 + le?vxor $inpperm,$inpperm,$tmp # transform for lvx_u/stvx_u + vadduwm $out6,$out4,$two + vxor $out4,$out4,$rndkey0 + vadduwm $out7,$out5,$two + vxor $out5,$out5,$rndkey0 + vadduwm $ivec,$out6,$two # next counter value + vxor $out6,$out6,$rndkey0 + vxor $out7,$out7,$rndkey0 + + mtctr $rounds + b Loop_ctr32_enc8x +.align 5 +Loop_ctr32_enc8x: + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + vcipher $out6,$out6,v24 + vcipher $out7,$out7,v24 +Loop_ctr32_enc8x_middle: + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + vcipher $out6,$out6,v25 + vcipher $out7,$out7,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_ctr32_enc8x + + subic r11,$len,256 # $len-256, borrow $key_ + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + vcipher $out6,$out6,v24 + vcipher $out7,$out7,v24 + + subfe r0,r0,r0 # borrow?-1:0 + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + vcipher $out6,$out6,v25 + vcipher $out7,$out7,v25 + + and r0,r0,r11 + addi $key_,$sp,$FRAME+15 # rewind $key_ + vcipher $out0,$out0,v26 + vcipher $out1,$out1,v26 + vcipher $out2,$out2,v26 + vcipher $out3,$out3,v26 + vcipher $out4,$out4,v26 + vcipher $out5,$out5,v26 + vcipher $out6,$out6,v26 + vcipher $out7,$out7,v26 + lvx v24,$x00,$key_ # re-pre-load round[1] + + subic $len,$len,129 # $len-=129 + vcipher $out0,$out0,v27 + addi $len,$len,1 # $len-=128 really + vcipher $out1,$out1,v27 + vcipher $out2,$out2,v27 + vcipher $out3,$out3,v27 + vcipher $out4,$out4,v27 + vcipher $out5,$out5,v27 + vcipher $out6,$out6,v27 + vcipher $out7,$out7,v27 + lvx v25,$x10,$key_ # re-pre-load round[2] + + vcipher $out0,$out0,v28 + lvx_u $in0,$x00,$inp # load input + vcipher $out1,$out1,v28 + lvx_u $in1,$x10,$inp + vcipher $out2,$out2,v28 + lvx_u $in2,$x20,$inp + vcipher $out3,$out3,v28 + lvx_u $in3,$x30,$inp + vcipher $out4,$out4,v28 + lvx_u $in4,$x40,$inp + vcipher $out5,$out5,v28 + lvx_u $in5,$x50,$inp + vcipher $out6,$out6,v28 + lvx_u $in6,$x60,$inp + vcipher $out7,$out7,v28 + lvx_u $in7,$x70,$inp + addi $inp,$inp,0x80 + + vcipher $out0,$out0,v29 + le?vperm $in0,$in0,$in0,$inpperm + vcipher $out1,$out1,v29 + le?vperm $in1,$in1,$in1,$inpperm + vcipher $out2,$out2,v29 + le?vperm $in2,$in2,$in2,$inpperm + vcipher $out3,$out3,v29 + le?vperm $in3,$in3,$in3,$inpperm + vcipher $out4,$out4,v29 + le?vperm $in4,$in4,$in4,$inpperm + vcipher $out5,$out5,v29 + le?vperm $in5,$in5,$in5,$inpperm + vcipher $out6,$out6,v29 + le?vperm $in6,$in6,$in6,$inpperm + vcipher $out7,$out7,v29 + le?vperm $in7,$in7,$in7,$inpperm + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in7 are loaded + # with last "words" + subfe. r0,r0,r0 # borrow?-1:0 + vcipher $out0,$out0,v30 + vxor $in0,$in0,v31 # xor with last round key + vcipher $out1,$out1,v30 + vxor $in1,$in1,v31 + vcipher $out2,$out2,v30 + vxor $in2,$in2,v31 + vcipher $out3,$out3,v30 + vxor $in3,$in3,v31 + vcipher $out4,$out4,v30 + vxor $in4,$in4,v31 + vcipher $out5,$out5,v30 + vxor $in5,$in5,v31 + vcipher $out6,$out6,v30 + vxor $in6,$in6,v31 + vcipher $out7,$out7,v30 + vxor $in7,$in7,v31 + + bne Lctr32_enc8x_break # did $len-129 borrow? + + vcipherlast $in0,$out0,$in0 + vcipherlast $in1,$out1,$in1 + vadduwm $out1,$ivec,$one # counter values ... + vcipherlast $in2,$out2,$in2 + vadduwm $out2,$ivec,$two + vxor $out0,$ivec,$rndkey0 # ... xored with rndkey[0] + vcipherlast $in3,$out3,$in3 + vadduwm $out3,$out1,$two + vxor $out1,$out1,$rndkey0 + vcipherlast $in4,$out4,$in4 + vadduwm $out4,$out2,$two + vxor $out2,$out2,$rndkey0 + vcipherlast $in5,$out5,$in5 + vadduwm $out5,$out3,$two + vxor $out3,$out3,$rndkey0 + vcipherlast $in6,$out6,$in6 + vadduwm $out6,$out4,$two + vxor $out4,$out4,$rndkey0 + vcipherlast $in7,$out7,$in7 + vadduwm $out7,$out5,$two + vxor $out5,$out5,$rndkey0 + le?vperm $in0,$in0,$in0,$inpperm + vadduwm $ivec,$out6,$two # next counter value + vxor $out6,$out6,$rndkey0 + le?vperm $in1,$in1,$in1,$inpperm + vxor $out7,$out7,$rndkey0 + mtctr $rounds + + vcipher $out0,$out0,v24 + stvx_u $in0,$x00,$out + le?vperm $in2,$in2,$in2,$inpperm + vcipher $out1,$out1,v24 + stvx_u $in1,$x10,$out + le?vperm $in3,$in3,$in3,$inpperm + vcipher $out2,$out2,v24 + stvx_u $in2,$x20,$out + le?vperm $in4,$in4,$in4,$inpperm + vcipher $out3,$out3,v24 + stvx_u $in3,$x30,$out + le?vperm $in5,$in5,$in5,$inpperm + vcipher $out4,$out4,v24 + stvx_u $in4,$x40,$out + le?vperm $in6,$in6,$in6,$inpperm + vcipher $out5,$out5,v24 + stvx_u $in5,$x50,$out + le?vperm $in7,$in7,$in7,$inpperm + vcipher $out6,$out6,v24 + stvx_u $in6,$x60,$out + vcipher $out7,$out7,v24 + stvx_u $in7,$x70,$out + addi $out,$out,0x80 + + b Loop_ctr32_enc8x_middle + +.align 5 +Lctr32_enc8x_break: + cmpwi $len,-0x60 + blt Lctr32_enc8x_one + nop + beq Lctr32_enc8x_two + cmpwi $len,-0x40 + blt Lctr32_enc8x_three + nop + beq Lctr32_enc8x_four + cmpwi $len,-0x20 + blt Lctr32_enc8x_five + nop + beq Lctr32_enc8x_six + cmpwi $len,0x00 + blt Lctr32_enc8x_seven + +Lctr32_enc8x_eight: + vcipherlast $out0,$out0,$in0 + vcipherlast $out1,$out1,$in1 + vcipherlast $out2,$out2,$in2 + vcipherlast $out3,$out3,$in3 + vcipherlast $out4,$out4,$in4 + vcipherlast $out5,$out5,$in5 + vcipherlast $out6,$out6,$in6 + vcipherlast $out7,$out7,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + le?vperm $out7,$out7,$out7,$inpperm + stvx_u $out6,$x60,$out + stvx_u $out7,$x70,$out + addi $out,$out,0x80 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_seven: + vcipherlast $out0,$out0,$in1 + vcipherlast $out1,$out1,$in2 + vcipherlast $out2,$out2,$in3 + vcipherlast $out3,$out3,$in4 + vcipherlast $out4,$out4,$in5 + vcipherlast $out5,$out5,$in6 + vcipherlast $out6,$out6,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + le?vperm $out6,$out6,$out6,$inpperm + stvx_u $out5,$x50,$out + stvx_u $out6,$x60,$out + addi $out,$out,0x70 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_six: + vcipherlast $out0,$out0,$in2 + vcipherlast $out1,$out1,$in3 + vcipherlast $out2,$out2,$in4 + vcipherlast $out3,$out3,$in5 + vcipherlast $out4,$out4,$in6 + vcipherlast $out5,$out5,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + le?vperm $out5,$out5,$out5,$inpperm + stvx_u $out4,$x40,$out + stvx_u $out5,$x50,$out + addi $out,$out,0x60 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_five: + vcipherlast $out0,$out0,$in3 + vcipherlast $out1,$out1,$in4 + vcipherlast $out2,$out2,$in5 + vcipherlast $out3,$out3,$in6 + vcipherlast $out4,$out4,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$inpperm + stvx_u $out3,$x30,$out + stvx_u $out4,$x40,$out + addi $out,$out,0x50 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_four: + vcipherlast $out0,$out0,$in4 + vcipherlast $out1,$out1,$in5 + vcipherlast $out2,$out2,$in6 + vcipherlast $out3,$out3,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$inpperm + stvx_u $out2,$x20,$out + stvx_u $out3,$x30,$out + addi $out,$out,0x40 + b Lctr32_enc8x_done + +.align 5 +Lctr32_enc8x_three: + vcipherlast $out0,$out0,$in5 + vcipherlast $out1,$out1,$in6 + vcipherlast $out2,$out2,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + le?vperm $out2,$out2,$out2,$inpperm + stvx_u $out1,$x10,$out + stvx_u $out2,$x20,$out + addi $out,$out,0x30 + b Lcbc_dec8x_done + +.align 5 +Lctr32_enc8x_two: + vcipherlast $out0,$out0,$in6 + vcipherlast $out1,$out1,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + le?vperm $out1,$out1,$out1,$inpperm + stvx_u $out0,$x00,$out + stvx_u $out1,$x10,$out + addi $out,$out,0x20 + b Lcbc_dec8x_done + +.align 5 +Lctr32_enc8x_one: + vcipherlast $out0,$out0,$in7 + + le?vperm $out0,$out0,$out0,$inpperm + stvx_u $out0,0,$out + addi $out,$out,0x10 + +Lctr32_enc8x_done: + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $inpperm,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + stvx $inpperm,r10,$sp + addi r10,r10,32 + stvx $inpperm,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x04,0,0x80,6,6,0 + .long 0 +.size .${prefix}_ctr32_encrypt_blocks,.-.${prefix}_ctr32_encrypt_blocks +___ +}} }}} + +######################################################################### +{{{ # XTS procedures # +# int aes_p8_xts_[en|de]crypt(const char *inp, char *out, size_t len, # +# const AES_KEY *key1, const AES_KEY *key2, # +# [const] unsigned char iv[16]); # +# If $key2 is NULL, then a "tweak chaining" mode is engaged, in which # +# input tweak value is assumed to be encrypted already, and last tweak # +# value, one suitable for consecutive call on same chunk of data, is # +# written back to original buffer. In addition, in "tweak chaining" # +# mode only complete input blocks are processed. # + +my ($inp,$out,$len,$key1,$key2,$ivp,$rounds,$idx) = map("r$_",(3..10)); +my ($rndkey0,$rndkey1,$inout) = map("v$_",(0..2)); +my ($output,$inptail,$inpperm,$leperm,$keyperm) = map("v$_",(3..7)); +my ($tweak,$seven,$eighty7,$tmp,$tweak1) = map("v$_",(8..12)); +my $taillen = $key2; + + ($inp,$idx) = ($idx,$inp); # reassign + +$code.=<<___; +.globl .${prefix}_xts_encrypt +.align 5 +.${prefix}_xts_encrypt: + mr $inp,r3 # reassign + li r3,-1 + ${UCMP}i $len,16 + bltlr- + + lis r0,0xfff0 + mfspr r12,256 # save vrsave + li r11,0 + mtspr 256,r0 + + vspltisb $seven,0x07 # 0x070707..07 + le?lvsl $leperm,r11,r11 + le?vspltisb $tmp,0x0f + le?vxor $leperm,$leperm,$seven + + li $idx,15 + lvx $tweak,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + le?vxor $inpperm,$inpperm,$tmp + vperm $tweak,$tweak,$inptail,$inpperm + + neg r11,$inp + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inout,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + ${UCMP}i $key2,0 # key2==NULL? + beq Lxts_enc_no_key2 + + ?lvsl $keyperm,0,$key2 # prepare for unaligned key + lwz $rounds,240($key2) + srwi $rounds,$rounds,1 + subi $rounds,$rounds,1 + li $idx,16 + + lvx $rndkey0,0,$key2 + lvx $rndkey1,$idx,$key2 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $tweak,$tweak,$rndkey0 + lvx $rndkey0,$idx,$key2 + addi $idx,$idx,16 + mtctr $rounds + +Ltweak_xts_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $tweak,$tweak,$rndkey1 + lvx $rndkey1,$idx,$key2 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $tweak,$tweak,$rndkey0 + lvx $rndkey0,$idx,$key2 + addi $idx,$idx,16 + bdnz Ltweak_xts_enc + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $tweak,$tweak,$rndkey1 + lvx $rndkey1,$idx,$key2 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipherlast $tweak,$tweak,$rndkey0 + + li $ivp,0 # don't chain the tweak + b Lxts_enc + +Lxts_enc_no_key2: + li $idx,-16 + and $len,$len,$idx # in "tweak chaining" + # mode only complete + # blocks are processed +Lxts_enc: + lvx $inptail,0,$inp + addi $inp,$inp,16 + + ?lvsl $keyperm,0,$key1 # prepare for unaligned key + lwz $rounds,240($key1) + srwi $rounds,$rounds,1 + subi $rounds,$rounds,1 + li $idx,16 + + vslb $eighty7,$seven,$seven # 0x808080..80 + vor $eighty7,$eighty7,$seven # 0x878787..87 + vspltisb $tmp,1 # 0x010101..01 + vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01 + + ${UCMP}i $len,96 + bge _aesp8_xts_encrypt6x + + andi. $taillen,$len,15 + subic r0,$len,32 + subi $taillen,$taillen,16 + subfe r0,r0,r0 + and r0,r0,$taillen + add $inp,$inp,r0 + + lvx $rndkey0,0,$key1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + vperm $inout,$inout,$inptail,$inpperm + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$tweak + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + mtctr $rounds + b Loop_xts_enc + +.align 5 +Loop_xts_enc: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + bdnz Loop_xts_enc + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $rndkey0,$rndkey0,$tweak + vcipherlast $output,$inout,$rndkey0 + + le?vperm $tmp,$output,$output,$leperm + be?nop + le?stvx_u $tmp,0,$out + be?stvx_u $output,0,$out + addi $out,$out,16 + + subic. $len,$len,16 + beq Lxts_enc_done + + vmr $inout,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + lvx $rndkey0,0,$key1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + + subic r0,$len,32 + subfe r0,r0,r0 + and r0,r0,$taillen + add $inp,$inp,r0 + + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $tweak,$tweak,$tmp + + vperm $inout,$inout,$inptail,$inpperm + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$tweak + vxor $output,$output,$rndkey0 # just in case $len<16 + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + + mtctr $rounds + ${UCMP}i $len,16 + bge Loop_xts_enc + + vxor $output,$output,$tweak + lvsr $inpperm,0,$len # $inpperm is no longer needed + vxor $inptail,$inptail,$inptail # $inptail is no longer needed + vspltisb $tmp,-1 + vperm $inptail,$inptail,$tmp,$inpperm + vsel $inout,$inout,$output,$inptail + + subi r11,$out,17 + subi $out,$out,16 + mtctr $len + li $len,16 +Loop_xts_enc_steal: + lbzu r0,1(r11) + stb r0,16(r11) + bdnz Loop_xts_enc_steal + + mtctr $rounds + b Loop_xts_enc # one more time... + +Lxts_enc_done: + ${UCMP}i $ivp,0 + beq Lxts_enc_ret + + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $tweak,$tweak,$tmp + + le?vperm $tweak,$tweak,$tweak,$leperm + stvx_u $tweak,0,$ivp + +Lxts_enc_ret: + mtspr 256,r12 # restore vrsave + li r3,0 + blr + .long 0 + .byte 0,12,0x04,0,0x80,6,6,0 + .long 0 +.size .${prefix}_xts_encrypt,.-.${prefix}_xts_encrypt + +.globl .${prefix}_xts_decrypt +.align 5 +.${prefix}_xts_decrypt: + mr $inp,r3 # reassign + li r3,-1 + ${UCMP}i $len,16 + bltlr- + + lis r0,0xfff8 + mfspr r12,256 # save vrsave + li r11,0 + mtspr 256,r0 + + andi. r0,$len,15 + neg r0,r0 + andi. r0,r0,16 + sub $len,$len,r0 + + vspltisb $seven,0x07 # 0x070707..07 + le?lvsl $leperm,r11,r11 + le?vspltisb $tmp,0x0f + le?vxor $leperm,$leperm,$seven + + li $idx,15 + lvx $tweak,0,$ivp # load [unaligned] iv + lvsl $inpperm,0,$ivp + lvx $inptail,$idx,$ivp + le?vxor $inpperm,$inpperm,$tmp + vperm $tweak,$tweak,$inptail,$inpperm + + neg r11,$inp + lvsr $inpperm,0,r11 # prepare for unaligned load + lvx $inout,0,$inp + addi $inp,$inp,15 # 15 is not typo + le?vxor $inpperm,$inpperm,$tmp + + ${UCMP}i $key2,0 # key2==NULL? + beq Lxts_dec_no_key2 + + ?lvsl $keyperm,0,$key2 # prepare for unaligned key + lwz $rounds,240($key2) + srwi $rounds,$rounds,1 + subi $rounds,$rounds,1 + li $idx,16 + + lvx $rndkey0,0,$key2 + lvx $rndkey1,$idx,$key2 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $tweak,$tweak,$rndkey0 + lvx $rndkey0,$idx,$key2 + addi $idx,$idx,16 + mtctr $rounds + +Ltweak_xts_dec: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $tweak,$tweak,$rndkey1 + lvx $rndkey1,$idx,$key2 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipher $tweak,$tweak,$rndkey0 + lvx $rndkey0,$idx,$key2 + addi $idx,$idx,16 + bdnz Ltweak_xts_dec + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vcipher $tweak,$tweak,$rndkey1 + lvx $rndkey1,$idx,$key2 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vcipherlast $tweak,$tweak,$rndkey0 + + li $ivp,0 # don't chain the tweak + b Lxts_dec + +Lxts_dec_no_key2: + neg $idx,$len + andi. $idx,$idx,15 + add $len,$len,$idx # in "tweak chaining" + # mode only complete + # blocks are processed +Lxts_dec: + lvx $inptail,0,$inp + addi $inp,$inp,16 + + ?lvsl $keyperm,0,$key1 # prepare for unaligned key + lwz $rounds,240($key1) + srwi $rounds,$rounds,1 + subi $rounds,$rounds,1 + li $idx,16 + + vslb $eighty7,$seven,$seven # 0x808080..80 + vor $eighty7,$eighty7,$seven # 0x878787..87 + vspltisb $tmp,1 # 0x010101..01 + vsldoi $eighty7,$eighty7,$tmp,15 # 0x870101..01 + + ${UCMP}i $len,96 + bge _aesp8_xts_decrypt6x + + lvx $rndkey0,0,$key1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + vperm $inout,$inout,$inptail,$inpperm + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$tweak + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + mtctr $rounds + + ${UCMP}i $len,16 + blt Ltail_xts_dec + be?b Loop_xts_dec + +.align 5 +Loop_xts_dec: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + bdnz Loop_xts_dec + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $rndkey0,$rndkey0,$tweak + vncipherlast $output,$inout,$rndkey0 + + le?vperm $tmp,$output,$output,$leperm + be?nop + le?stvx_u $tmp,0,$out + be?stvx_u $output,0,$out + addi $out,$out,16 + + subic. $len,$len,16 + beq Lxts_dec_done + + vmr $inout,$inptail + lvx $inptail,0,$inp + addi $inp,$inp,16 + lvx $rndkey0,0,$key1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $tweak,$tweak,$tmp + + vperm $inout,$inout,$inptail,$inpperm + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $inout,$inout,$tweak + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + + mtctr $rounds + ${UCMP}i $len,16 + bge Loop_xts_dec + +Ltail_xts_dec: + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak1,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $tweak1,$tweak1,$tmp + + subi $inp,$inp,16 + add $inp,$inp,$len + + vxor $inout,$inout,$tweak # :-( + vxor $inout,$inout,$tweak1 # :-) + +Loop_xts_dec_short: + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vncipher $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + bdnz Loop_xts_dec_short + + ?vperm $rndkey1,$rndkey1,$rndkey0,$keyperm + vncipher $inout,$inout,$rndkey1 + lvx $rndkey1,$idx,$key1 + li $idx,16 + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + vxor $rndkey0,$rndkey0,$tweak1 + vncipherlast $output,$inout,$rndkey0 + + le?vperm $tmp,$output,$output,$leperm + be?nop + le?stvx_u $tmp,0,$out + be?stvx_u $output,0,$out + + vmr $inout,$inptail + lvx $inptail,0,$inp + #addi $inp,$inp,16 + lvx $rndkey0,0,$key1 + lvx $rndkey1,$idx,$key1 + addi $idx,$idx,16 + vperm $inout,$inout,$inptail,$inpperm + ?vperm $rndkey0,$rndkey0,$rndkey1,$keyperm + + lvsr $inpperm,0,$len # $inpperm is no longer needed + vxor $inptail,$inptail,$inptail # $inptail is no longer needed + vspltisb $tmp,-1 + vperm $inptail,$inptail,$tmp,$inpperm + vsel $inout,$inout,$output,$inptail + + vxor $rndkey0,$rndkey0,$tweak + vxor $inout,$inout,$rndkey0 + lvx $rndkey0,$idx,$key1 + addi $idx,$idx,16 + + subi r11,$out,1 + mtctr $len + li $len,16 +Loop_xts_dec_steal: + lbzu r0,1(r11) + stb r0,16(r11) + bdnz Loop_xts_dec_steal + + mtctr $rounds + b Loop_xts_dec # one more time... + +Lxts_dec_done: + ${UCMP}i $ivp,0 + beq Lxts_dec_ret + + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $tweak,$tweak,$tmp + + le?vperm $tweak,$tweak,$tweak,$leperm + stvx_u $tweak,0,$ivp + +Lxts_dec_ret: + mtspr 256,r12 # restore vrsave + li r3,0 + blr + .long 0 + .byte 0,12,0x04,0,0x80,6,6,0 + .long 0 +.size .${prefix}_xts_decrypt,.-.${prefix}_xts_decrypt +___ +######################################################################### +{{ # Optimized XTS procedures # +my $key_=$key2; +my ($x00,$x10,$x20,$x30,$x40,$x50,$x60,$x70)=map("r$_",(0,3,26..31)); + $x00=0 if ($flavour =~ /osx/); +my ($in0, $in1, $in2, $in3, $in4, $in5 )=map("v$_",(0..5)); +my ($out0, $out1, $out2, $out3, $out4, $out5)=map("v$_",(7,12..16)); +my ($twk0, $twk1, $twk2, $twk3, $twk4, $twk5)=map("v$_",(17..22)); +my $rndkey0="v23"; # v24-v25 rotating buffer for first found keys + # v26-v31 last 6 round keys +my ($keyperm)=($out0); # aliases with "caller", redundant assignment +my $taillen=$x70; + +$code.=<<___; +.align 5 +_aesp8_xts_encrypt6x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + mflr r11 + li r7,`$FRAME+8*16+15` + li r3,`$FRAME+8*16+31` + $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp) + stvx v20,r7,$sp # ABI says so + addi r7,r7,32 + stvx v21,r3,$sp + addi r3,r3,32 + stvx v22,r7,$sp + addi r7,r7,32 + stvx v23,r3,$sp + addi r3,r3,32 + stvx v24,r7,$sp + addi r7,r7,32 + stvx v25,r3,$sp + addi r3,r3,32 + stvx v26,r7,$sp + addi r7,r7,32 + stvx v27,r3,$sp + addi r3,r3,32 + stvx v28,r7,$sp + addi r7,r7,32 + stvx v29,r3,$sp + addi r3,r3,32 + stvx v30,r7,$sp + stvx v31,r3,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + + lvx $rndkey0,$x00,$key1 # load key schedule + lvx v30,$x10,$key1 + addi $key1,$key1,0x20 + lvx v31,$x00,$key1 + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_xts_enc_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key1 + addi $key1,$key1,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key1 + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_xts_enc_key + + lvx v26,$x10,$key1 + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key1 + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key1 + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key1 + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key1 + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key1 + ?vperm v29,v29,v30,$keyperm + lvx $twk5,$x70,$key1 # borrow $twk5 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$twk5,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + vperm $in0,$inout,$inptail,$inpperm + subi $inp,$inp,31 # undo "caller" + vxor $twk0,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $out0,$in0,$twk0 + vxor $tweak,$tweak,$tmp + + lvx_u $in1,$x10,$inp + vxor $twk1,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in1,$in1,$in1,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out1,$in1,$twk1 + vxor $tweak,$tweak,$tmp + + lvx_u $in2,$x20,$inp + andi. $taillen,$len,15 + vxor $twk2,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in2,$in2,$in2,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out2,$in2,$twk2 + vxor $tweak,$tweak,$tmp + + lvx_u $in3,$x30,$inp + sub $len,$len,$taillen + vxor $twk3,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in3,$in3,$in3,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out3,$in3,$twk3 + vxor $tweak,$tweak,$tmp + + lvx_u $in4,$x40,$inp + subi $len,$len,0x60 + vxor $twk4,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in4,$in4,$in4,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out4,$in4,$twk4 + vxor $tweak,$tweak,$tmp + + lvx_u $in5,$x50,$inp + addi $inp,$inp,0x60 + vxor $twk5,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in5,$in5,$in5,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out5,$in5,$twk5 + vxor $tweak,$tweak,$tmp + + vxor v31,v31,$rndkey0 + mtctr $rounds + b Loop_xts_enc6x + +.align 5 +Loop_xts_enc6x: + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_xts_enc6x + + subic $len,$len,96 # $len-=96 + vxor $in0,$twk0,v31 # xor with last round key + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk0,$tweak,$rndkey0 + vaddubm $tweak,$tweak,$tweak + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vsldoi $tmp,$tmp,$tmp,15 + vcipher $out4,$out4,v24 + vcipher $out5,$out5,v24 + + subfe. r0,r0,r0 # borrow?-1:0 + vand $tmp,$tmp,$eighty7 + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vxor $tweak,$tweak,$tmp + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vxor $in1,$twk1,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk1,$tweak,$rndkey0 + vcipher $out4,$out4,v25 + vcipher $out5,$out5,v25 + + and r0,r0,$len + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vcipher $out0,$out0,v26 + vcipher $out1,$out1,v26 + vand $tmp,$tmp,$eighty7 + vcipher $out2,$out2,v26 + vcipher $out3,$out3,v26 + vxor $tweak,$tweak,$tmp + vcipher $out4,$out4,v26 + vcipher $out5,$out5,v26 + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in5 are loaded + # with last "words" + vxor $in2,$twk2,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk2,$tweak,$rndkey0 + vaddubm $tweak,$tweak,$tweak + vcipher $out0,$out0,v27 + vcipher $out1,$out1,v27 + vsldoi $tmp,$tmp,$tmp,15 + vcipher $out2,$out2,v27 + vcipher $out3,$out3,v27 + vand $tmp,$tmp,$eighty7 + vcipher $out4,$out4,v27 + vcipher $out5,$out5,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vxor $tweak,$tweak,$tmp + vcipher $out0,$out0,v28 + vcipher $out1,$out1,v28 + vxor $in3,$twk3,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk3,$tweak,$rndkey0 + vcipher $out2,$out2,v28 + vcipher $out3,$out3,v28 + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vcipher $out4,$out4,v28 + vcipher $out5,$out5,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + vand $tmp,$tmp,$eighty7 + + vcipher $out0,$out0,v29 + vcipher $out1,$out1,v29 + vxor $tweak,$tweak,$tmp + vcipher $out2,$out2,v29 + vcipher $out3,$out3,v29 + vxor $in4,$twk4,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk4,$tweak,$rndkey0 + vcipher $out4,$out4,v29 + vcipher $out5,$out5,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + + vcipher $out0,$out0,v30 + vcipher $out1,$out1,v30 + vand $tmp,$tmp,$eighty7 + vcipher $out2,$out2,v30 + vcipher $out3,$out3,v30 + vxor $tweak,$tweak,$tmp + vcipher $out4,$out4,v30 + vcipher $out5,$out5,v30 + vxor $in5,$twk5,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk5,$tweak,$rndkey0 + + vcipherlast $out0,$out0,$in0 + lvx_u $in0,$x00,$inp # load next input block + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vcipherlast $out1,$out1,$in1 + lvx_u $in1,$x10,$inp + vcipherlast $out2,$out2,$in2 + le?vperm $in0,$in0,$in0,$leperm + lvx_u $in2,$x20,$inp + vand $tmp,$tmp,$eighty7 + vcipherlast $out3,$out3,$in3 + le?vperm $in1,$in1,$in1,$leperm + lvx_u $in3,$x30,$inp + vcipherlast $out4,$out4,$in4 + le?vperm $in2,$in2,$in2,$leperm + lvx_u $in4,$x40,$inp + vxor $tweak,$tweak,$tmp + vcipherlast $tmp,$out5,$in5 # last block might be needed + # in stealing mode + le?vperm $in3,$in3,$in3,$leperm + lvx_u $in5,$x50,$inp + addi $inp,$inp,0x60 + le?vperm $in4,$in4,$in4,$leperm + le?vperm $in5,$in5,$in5,$leperm + + le?vperm $out0,$out0,$out0,$leperm + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk0 + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + vxor $out1,$in1,$twk1 + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + vxor $out2,$in2,$twk2 + le?vperm $out4,$out4,$out4,$leperm + stvx_u $out3,$x30,$out + vxor $out3,$in3,$twk3 + le?vperm $out5,$tmp,$tmp,$leperm + stvx_u $out4,$x40,$out + vxor $out4,$in4,$twk4 + le?stvx_u $out5,$x50,$out + be?stvx_u $tmp, $x50,$out + vxor $out5,$in5,$twk5 + addi $out,$out,0x60 + + mtctr $rounds + beq Loop_xts_enc6x # did $len-=96 borrow? + + addic. $len,$len,0x60 + beq Lxts_enc6x_zero + cmpwi $len,0x20 + blt Lxts_enc6x_one + nop + beq Lxts_enc6x_two + cmpwi $len,0x40 + blt Lxts_enc6x_three + nop + beq Lxts_enc6x_four + +Lxts_enc6x_five: + vxor $out0,$in1,$twk0 + vxor $out1,$in2,$twk1 + vxor $out2,$in3,$twk2 + vxor $out3,$in4,$twk3 + vxor $out4,$in5,$twk4 + + bl _aesp8_xts_enc5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk5 # unused tweak + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + vxor $tmp,$out4,$twk5 # last block prep for stealing + le?vperm $out4,$out4,$out4,$leperm + stvx_u $out3,$x30,$out + stvx_u $out4,$x40,$out + addi $out,$out,0x50 + bne Lxts_enc6x_steal + b Lxts_enc6x_done + +.align 4 +Lxts_enc6x_four: + vxor $out0,$in2,$twk0 + vxor $out1,$in3,$twk1 + vxor $out2,$in4,$twk2 + vxor $out3,$in5,$twk3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_enc5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk4 # unused tweak + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + vxor $tmp,$out3,$twk4 # last block prep for stealing + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + stvx_u $out3,$x30,$out + addi $out,$out,0x40 + bne Lxts_enc6x_steal + b Lxts_enc6x_done + +.align 4 +Lxts_enc6x_three: + vxor $out0,$in3,$twk0 + vxor $out1,$in4,$twk1 + vxor $out2,$in5,$twk2 + vxor $out3,$out3,$out3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_enc5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk3 # unused tweak + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $tmp,$out2,$twk3 # last block prep for stealing + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + stvx_u $out2,$x20,$out + addi $out,$out,0x30 + bne Lxts_enc6x_steal + b Lxts_enc6x_done + +.align 4 +Lxts_enc6x_two: + vxor $out0,$in4,$twk0 + vxor $out1,$in5,$twk1 + vxor $out2,$out2,$out2 + vxor $out3,$out3,$out3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_enc5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk2 # unused tweak + vxor $tmp,$out1,$twk2 # last block prep for stealing + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + stvx_u $out1,$x10,$out + addi $out,$out,0x20 + bne Lxts_enc6x_steal + b Lxts_enc6x_done + +.align 4 +Lxts_enc6x_one: + vxor $out0,$in5,$twk0 + nop +Loop_xts_enc1x: + vcipher $out0,$out0,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vcipher $out0,$out0,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_xts_enc1x + + add $inp,$inp,$taillen + cmpwi $taillen,0 + vcipher $out0,$out0,v24 + + subi $inp,$inp,16 + vcipher $out0,$out0,v25 + + lvsr $inpperm,0,$taillen + vcipher $out0,$out0,v26 + + lvx_u $in0,0,$inp + vcipher $out0,$out0,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vcipher $out0,$out0,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + + vcipher $out0,$out0,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vxor $twk0,$twk0,v31 + + le?vperm $in0,$in0,$in0,$leperm + vcipher $out0,$out0,v30 + + vperm $in0,$in0,$in0,$inpperm + vcipherlast $out0,$out0,$twk0 + + vmr $twk0,$twk1 # unused tweak + vxor $tmp,$out0,$twk1 # last block prep for stealing + le?vperm $out0,$out0,$out0,$leperm + stvx_u $out0,$x00,$out # store output + addi $out,$out,0x10 + bne Lxts_enc6x_steal + b Lxts_enc6x_done + +.align 4 +Lxts_enc6x_zero: + cmpwi $taillen,0 + beq Lxts_enc6x_done + + add $inp,$inp,$taillen + subi $inp,$inp,16 + lvx_u $in0,0,$inp + lvsr $inpperm,0,$taillen # $in5 is no more + le?vperm $in0,$in0,$in0,$leperm + vperm $in0,$in0,$in0,$inpperm + vxor $tmp,$tmp,$twk0 +Lxts_enc6x_steal: + vxor $in0,$in0,$twk0 + vxor $out0,$out0,$out0 + vspltisb $out1,-1 + vperm $out0,$out0,$out1,$inpperm + vsel $out0,$in0,$tmp,$out0 # $tmp is last block, remember? + + subi r30,$out,17 + subi $out,$out,16 + mtctr $taillen +Loop_xts_enc6x_steal: + lbzu r0,1(r30) + stb r0,16(r30) + bdnz Loop_xts_enc6x_steal + + li $taillen,0 + mtctr $rounds + b Loop_xts_enc1x # one more time... + +.align 4 +Lxts_enc6x_done: + ${UCMP}i $ivp,0 + beq Lxts_enc6x_ret + + vxor $tweak,$twk0,$rndkey0 + le?vperm $tweak,$tweak,$tweak,$leperm + stvx_u $tweak,0,$ivp + +Lxts_enc6x_ret: + mtlr r11 + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $seven,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x04,1,0x80,6,6,0 + .long 0 + +.align 5 +_aesp8_xts_enc5x: + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + lvx v25,$x10,$key_ # round[4] + bdnz _aesp8_xts_enc5x + + add $inp,$inp,$taillen + cmpwi $taillen,0 + vcipher $out0,$out0,v24 + vcipher $out1,$out1,v24 + vcipher $out2,$out2,v24 + vcipher $out3,$out3,v24 + vcipher $out4,$out4,v24 + + subi $inp,$inp,16 + vcipher $out0,$out0,v25 + vcipher $out1,$out1,v25 + vcipher $out2,$out2,v25 + vcipher $out3,$out3,v25 + vcipher $out4,$out4,v25 + vxor $twk0,$twk0,v31 + + vcipher $out0,$out0,v26 + lvsr $inpperm,r0,$taillen # $in5 is no more + vcipher $out1,$out1,v26 + vcipher $out2,$out2,v26 + vcipher $out3,$out3,v26 + vcipher $out4,$out4,v26 + vxor $in1,$twk1,v31 + + vcipher $out0,$out0,v27 + lvx_u $in0,0,$inp + vcipher $out1,$out1,v27 + vcipher $out2,$out2,v27 + vcipher $out3,$out3,v27 + vcipher $out4,$out4,v27 + vxor $in2,$twk2,v31 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vcipher $out0,$out0,v28 + vcipher $out1,$out1,v28 + vcipher $out2,$out2,v28 + vcipher $out3,$out3,v28 + vcipher $out4,$out4,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + vxor $in3,$twk3,v31 + + vcipher $out0,$out0,v29 + le?vperm $in0,$in0,$in0,$leperm + vcipher $out1,$out1,v29 + vcipher $out2,$out2,v29 + vcipher $out3,$out3,v29 + vcipher $out4,$out4,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vxor $in4,$twk4,v31 + + vcipher $out0,$out0,v30 + vperm $in0,$in0,$in0,$inpperm + vcipher $out1,$out1,v30 + vcipher $out2,$out2,v30 + vcipher $out3,$out3,v30 + vcipher $out4,$out4,v30 + + vcipherlast $out0,$out0,$twk0 + vcipherlast $out1,$out1,$in1 + vcipherlast $out2,$out2,$in2 + vcipherlast $out3,$out3,$in3 + vcipherlast $out4,$out4,$in4 + blr + .long 0 + .byte 0,12,0x14,0,0,0,0,0 + +.align 5 +_aesp8_xts_decrypt6x: + $STU $sp,-`($FRAME+21*16+6*$SIZE_T)`($sp) + mflr r11 + li r7,`$FRAME+8*16+15` + li r3,`$FRAME+8*16+31` + $PUSH r11,`$FRAME+21*16+6*$SIZE_T+$LRSAVE`($sp) + stvx v20,r7,$sp # ABI says so + addi r7,r7,32 + stvx v21,r3,$sp + addi r3,r3,32 + stvx v22,r7,$sp + addi r7,r7,32 + stvx v23,r3,$sp + addi r3,r3,32 + stvx v24,r7,$sp + addi r7,r7,32 + stvx v25,r3,$sp + addi r3,r3,32 + stvx v26,r7,$sp + addi r7,r7,32 + stvx v27,r3,$sp + addi r3,r3,32 + stvx v28,r7,$sp + addi r7,r7,32 + stvx v29,r3,$sp + addi r3,r3,32 + stvx v30,r7,$sp + stvx v31,r3,$sp + li r0,-1 + stw $vrsave,`$FRAME+21*16-4`($sp) # save vrsave + li $x10,0x10 + $PUSH r26,`$FRAME+21*16+0*$SIZE_T`($sp) + li $x20,0x20 + $PUSH r27,`$FRAME+21*16+1*$SIZE_T`($sp) + li $x30,0x30 + $PUSH r28,`$FRAME+21*16+2*$SIZE_T`($sp) + li $x40,0x40 + $PUSH r29,`$FRAME+21*16+3*$SIZE_T`($sp) + li $x50,0x50 + $PUSH r30,`$FRAME+21*16+4*$SIZE_T`($sp) + li $x60,0x60 + $PUSH r31,`$FRAME+21*16+5*$SIZE_T`($sp) + li $x70,0x70 + mtspr 256,r0 + + subi $rounds,$rounds,3 # -4 in total + + lvx $rndkey0,$x00,$key1 # load key schedule + lvx v30,$x10,$key1 + addi $key1,$key1,0x20 + lvx v31,$x00,$key1 + ?vperm $rndkey0,$rndkey0,v30,$keyperm + addi $key_,$sp,$FRAME+15 + mtctr $rounds + +Load_xts_dec_key: + ?vperm v24,v30,v31,$keyperm + lvx v30,$x10,$key1 + addi $key1,$key1,0x20 + stvx v24,$x00,$key_ # off-load round[1] + ?vperm v25,v31,v30,$keyperm + lvx v31,$x00,$key1 + stvx v25,$x10,$key_ # off-load round[2] + addi $key_,$key_,0x20 + bdnz Load_xts_dec_key + + lvx v26,$x10,$key1 + ?vperm v24,v30,v31,$keyperm + lvx v27,$x20,$key1 + stvx v24,$x00,$key_ # off-load round[3] + ?vperm v25,v31,v26,$keyperm + lvx v28,$x30,$key1 + stvx v25,$x10,$key_ # off-load round[4] + addi $key_,$sp,$FRAME+15 # rewind $key_ + ?vperm v26,v26,v27,$keyperm + lvx v29,$x40,$key1 + ?vperm v27,v27,v28,$keyperm + lvx v30,$x50,$key1 + ?vperm v28,v28,v29,$keyperm + lvx v31,$x60,$key1 + ?vperm v29,v29,v30,$keyperm + lvx $twk5,$x70,$key1 # borrow $twk5 + ?vperm v30,v30,v31,$keyperm + lvx v24,$x00,$key_ # pre-load round[1] + ?vperm v31,v31,$twk5,$keyperm + lvx v25,$x10,$key_ # pre-load round[2] + + vperm $in0,$inout,$inptail,$inpperm + subi $inp,$inp,31 # undo "caller" + vxor $twk0,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vand $tmp,$tmp,$eighty7 + vxor $out0,$in0,$twk0 + vxor $tweak,$tweak,$tmp + + lvx_u $in1,$x10,$inp + vxor $twk1,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in1,$in1,$in1,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out1,$in1,$twk1 + vxor $tweak,$tweak,$tmp + + lvx_u $in2,$x20,$inp + andi. $taillen,$len,15 + vxor $twk2,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in2,$in2,$in2,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out2,$in2,$twk2 + vxor $tweak,$tweak,$tmp + + lvx_u $in3,$x30,$inp + sub $len,$len,$taillen + vxor $twk3,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in3,$in3,$in3,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out3,$in3,$twk3 + vxor $tweak,$tweak,$tmp + + lvx_u $in4,$x40,$inp + subi $len,$len,0x60 + vxor $twk4,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in4,$in4,$in4,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out4,$in4,$twk4 + vxor $tweak,$tweak,$tmp + + lvx_u $in5,$x50,$inp + addi $inp,$inp,0x60 + vxor $twk5,$tweak,$rndkey0 + vsrab $tmp,$tweak,$seven # next tweak value + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + le?vperm $in5,$in5,$in5,$leperm + vand $tmp,$tmp,$eighty7 + vxor $out5,$in5,$twk5 + vxor $tweak,$tweak,$tmp + + vxor v31,v31,$rndkey0 + mtctr $rounds + b Loop_xts_dec6x + +.align 5 +Loop_xts_dec6x: + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_xts_dec6x + + subic $len,$len,96 # $len-=96 + vxor $in0,$twk0,v31 # xor with last round key + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk0,$tweak,$rndkey0 + vaddubm $tweak,$tweak,$tweak + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vsldoi $tmp,$tmp,$tmp,15 + vncipher $out4,$out4,v24 + vncipher $out5,$out5,v24 + + subfe. r0,r0,r0 # borrow?-1:0 + vand $tmp,$tmp,$eighty7 + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vxor $tweak,$tweak,$tmp + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vxor $in1,$twk1,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk1,$tweak,$rndkey0 + vncipher $out4,$out4,v25 + vncipher $out5,$out5,v25 + + and r0,r0,$len + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vncipher $out0,$out0,v26 + vncipher $out1,$out1,v26 + vand $tmp,$tmp,$eighty7 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vxor $tweak,$tweak,$tmp + vncipher $out4,$out4,v26 + vncipher $out5,$out5,v26 + + add $inp,$inp,r0 # $inp is adjusted in such + # way that at exit from the + # loop inX-in5 are loaded + # with last "words" + vxor $in2,$twk2,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk2,$tweak,$rndkey0 + vaddubm $tweak,$tweak,$tweak + vncipher $out0,$out0,v27 + vncipher $out1,$out1,v27 + vsldoi $tmp,$tmp,$tmp,15 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vand $tmp,$tmp,$eighty7 + vncipher $out4,$out4,v27 + vncipher $out5,$out5,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vxor $tweak,$tweak,$tmp + vncipher $out0,$out0,v28 + vncipher $out1,$out1,v28 + vxor $in3,$twk3,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk3,$tweak,$rndkey0 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vncipher $out4,$out4,v28 + vncipher $out5,$out5,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + vand $tmp,$tmp,$eighty7 + + vncipher $out0,$out0,v29 + vncipher $out1,$out1,v29 + vxor $tweak,$tweak,$tmp + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vxor $in4,$twk4,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk4,$tweak,$rndkey0 + vncipher $out4,$out4,v29 + vncipher $out5,$out5,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + + vncipher $out0,$out0,v30 + vncipher $out1,$out1,v30 + vand $tmp,$tmp,$eighty7 + vncipher $out2,$out2,v30 + vncipher $out3,$out3,v30 + vxor $tweak,$tweak,$tmp + vncipher $out4,$out4,v30 + vncipher $out5,$out5,v30 + vxor $in5,$twk5,v31 + vsrab $tmp,$tweak,$seven # next tweak value + vxor $twk5,$tweak,$rndkey0 + + vncipherlast $out0,$out0,$in0 + lvx_u $in0,$x00,$inp # load next input block + vaddubm $tweak,$tweak,$tweak + vsldoi $tmp,$tmp,$tmp,15 + vncipherlast $out1,$out1,$in1 + lvx_u $in1,$x10,$inp + vncipherlast $out2,$out2,$in2 + le?vperm $in0,$in0,$in0,$leperm + lvx_u $in2,$x20,$inp + vand $tmp,$tmp,$eighty7 + vncipherlast $out3,$out3,$in3 + le?vperm $in1,$in1,$in1,$leperm + lvx_u $in3,$x30,$inp + vncipherlast $out4,$out4,$in4 + le?vperm $in2,$in2,$in2,$leperm + lvx_u $in4,$x40,$inp + vxor $tweak,$tweak,$tmp + vncipherlast $out5,$out5,$in5 + le?vperm $in3,$in3,$in3,$leperm + lvx_u $in5,$x50,$inp + addi $inp,$inp,0x60 + le?vperm $in4,$in4,$in4,$leperm + le?vperm $in5,$in5,$in5,$leperm + + le?vperm $out0,$out0,$out0,$leperm + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk0 + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + vxor $out1,$in1,$twk1 + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + vxor $out2,$in2,$twk2 + le?vperm $out4,$out4,$out4,$leperm + stvx_u $out3,$x30,$out + vxor $out3,$in3,$twk3 + le?vperm $out5,$out5,$out5,$leperm + stvx_u $out4,$x40,$out + vxor $out4,$in4,$twk4 + stvx_u $out5,$x50,$out + vxor $out5,$in5,$twk5 + addi $out,$out,0x60 + + mtctr $rounds + beq Loop_xts_dec6x # did $len-=96 borrow? + + addic. $len,$len,0x60 + beq Lxts_dec6x_zero + cmpwi $len,0x20 + blt Lxts_dec6x_one + nop + beq Lxts_dec6x_two + cmpwi $len,0x40 + blt Lxts_dec6x_three + nop + beq Lxts_dec6x_four + +Lxts_dec6x_five: + vxor $out0,$in1,$twk0 + vxor $out1,$in2,$twk1 + vxor $out2,$in3,$twk2 + vxor $out3,$in4,$twk3 + vxor $out4,$in5,$twk4 + + bl _aesp8_xts_dec5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk5 # unused tweak + vxor $twk1,$tweak,$rndkey0 + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk1 + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + le?vperm $out4,$out4,$out4,$leperm + stvx_u $out3,$x30,$out + stvx_u $out4,$x40,$out + addi $out,$out,0x50 + bne Lxts_dec6x_steal + b Lxts_dec6x_done + +.align 4 +Lxts_dec6x_four: + vxor $out0,$in2,$twk0 + vxor $out1,$in3,$twk1 + vxor $out2,$in4,$twk2 + vxor $out3,$in5,$twk3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_dec5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk4 # unused tweak + vmr $twk1,$twk5 + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk5 + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + le?vperm $out3,$out3,$out3,$leperm + stvx_u $out2,$x20,$out + stvx_u $out3,$x30,$out + addi $out,$out,0x40 + bne Lxts_dec6x_steal + b Lxts_dec6x_done + +.align 4 +Lxts_dec6x_three: + vxor $out0,$in3,$twk0 + vxor $out1,$in4,$twk1 + vxor $out2,$in5,$twk2 + vxor $out3,$out3,$out3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_dec5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk3 # unused tweak + vmr $twk1,$twk4 + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk4 + le?vperm $out2,$out2,$out2,$leperm + stvx_u $out1,$x10,$out + stvx_u $out2,$x20,$out + addi $out,$out,0x30 + bne Lxts_dec6x_steal + b Lxts_dec6x_done + +.align 4 +Lxts_dec6x_two: + vxor $out0,$in4,$twk0 + vxor $out1,$in5,$twk1 + vxor $out2,$out2,$out2 + vxor $out3,$out3,$out3 + vxor $out4,$out4,$out4 + + bl _aesp8_xts_dec5x + + le?vperm $out0,$out0,$out0,$leperm + vmr $twk0,$twk2 # unused tweak + vmr $twk1,$twk3 + le?vperm $out1,$out1,$out1,$leperm + stvx_u $out0,$x00,$out # store output + vxor $out0,$in0,$twk3 + stvx_u $out1,$x10,$out + addi $out,$out,0x20 + bne Lxts_dec6x_steal + b Lxts_dec6x_done + +.align 4 +Lxts_dec6x_one: + vxor $out0,$in5,$twk0 + nop +Loop_xts_dec1x: + vncipher $out0,$out0,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Loop_xts_dec1x + + subi r0,$taillen,1 + vncipher $out0,$out0,v24 + + andi. r0,r0,16 + cmpwi $taillen,0 + vncipher $out0,$out0,v25 + + sub $inp,$inp,r0 + vncipher $out0,$out0,v26 + + lvx_u $in0,0,$inp + vncipher $out0,$out0,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vncipher $out0,$out0,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + + vncipher $out0,$out0,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vxor $twk0,$twk0,v31 + + le?vperm $in0,$in0,$in0,$leperm + vncipher $out0,$out0,v30 + + mtctr $rounds + vncipherlast $out0,$out0,$twk0 + + vmr $twk0,$twk1 # unused tweak + vmr $twk1,$twk2 + le?vperm $out0,$out0,$out0,$leperm + stvx_u $out0,$x00,$out # store output + addi $out,$out,0x10 + vxor $out0,$in0,$twk2 + bne Lxts_dec6x_steal + b Lxts_dec6x_done + +.align 4 +Lxts_dec6x_zero: + cmpwi $taillen,0 + beq Lxts_dec6x_done + + lvx_u $in0,0,$inp + le?vperm $in0,$in0,$in0,$leperm + vxor $out0,$in0,$twk1 +Lxts_dec6x_steal: + vncipher $out0,$out0,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + lvx v25,$x10,$key_ # round[4] + bdnz Lxts_dec6x_steal + + add $inp,$inp,$taillen + vncipher $out0,$out0,v24 + + cmpwi $taillen,0 + vncipher $out0,$out0,v25 + + lvx_u $in0,0,$inp + vncipher $out0,$out0,v26 + + lvsr $inpperm,0,$taillen # $in5 is no more + vncipher $out0,$out0,v27 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vncipher $out0,$out0,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + + vncipher $out0,$out0,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vxor $twk1,$twk1,v31 + + le?vperm $in0,$in0,$in0,$leperm + vncipher $out0,$out0,v30 + + vperm $in0,$in0,$in0,$inpperm + vncipherlast $tmp,$out0,$twk1 + + le?vperm $out0,$tmp,$tmp,$leperm + le?stvx_u $out0,0,$out + be?stvx_u $tmp,0,$out + + vxor $out0,$out0,$out0 + vspltisb $out1,-1 + vperm $out0,$out0,$out1,$inpperm + vsel $out0,$in0,$tmp,$out0 + vxor $out0,$out0,$twk0 + + subi r30,$out,1 + mtctr $taillen +Loop_xts_dec6x_steal: + lbzu r0,1(r30) + stb r0,16(r30) + bdnz Loop_xts_dec6x_steal + + li $taillen,0 + mtctr $rounds + b Loop_xts_dec1x # one more time... + +.align 4 +Lxts_dec6x_done: + ${UCMP}i $ivp,0 + beq Lxts_dec6x_ret + + vxor $tweak,$twk0,$rndkey0 + le?vperm $tweak,$tweak,$tweak,$leperm + stvx_u $tweak,0,$ivp + +Lxts_dec6x_ret: + mtlr r11 + li r10,`$FRAME+15` + li r11,`$FRAME+31` + stvx $seven,r10,$sp # wipe copies of round keys + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + stvx $seven,r10,$sp + addi r10,r10,32 + stvx $seven,r11,$sp + addi r11,r11,32 + + mtspr 256,$vrsave + lvx v20,r10,$sp # ABI says so + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + $POP r26,`$FRAME+21*16+0*$SIZE_T`($sp) + $POP r27,`$FRAME+21*16+1*$SIZE_T`($sp) + $POP r28,`$FRAME+21*16+2*$SIZE_T`($sp) + $POP r29,`$FRAME+21*16+3*$SIZE_T`($sp) + $POP r30,`$FRAME+21*16+4*$SIZE_T`($sp) + $POP r31,`$FRAME+21*16+5*$SIZE_T`($sp) + addi $sp,$sp,`$FRAME+21*16+6*$SIZE_T` + blr + .long 0 + .byte 0,12,0x04,1,0x80,6,6,0 + .long 0 + +.align 5 +_aesp8_xts_dec5x: + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + lvx v24,$x20,$key_ # round[3] + addi $key_,$key_,0x20 + + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + lvx v25,$x10,$key_ # round[4] + bdnz _aesp8_xts_dec5x + + subi r0,$taillen,1 + vncipher $out0,$out0,v24 + vncipher $out1,$out1,v24 + vncipher $out2,$out2,v24 + vncipher $out3,$out3,v24 + vncipher $out4,$out4,v24 + + andi. r0,r0,16 + cmpwi $taillen,0 + vncipher $out0,$out0,v25 + vncipher $out1,$out1,v25 + vncipher $out2,$out2,v25 + vncipher $out3,$out3,v25 + vncipher $out4,$out4,v25 + vxor $twk0,$twk0,v31 + + sub $inp,$inp,r0 + vncipher $out0,$out0,v26 + vncipher $out1,$out1,v26 + vncipher $out2,$out2,v26 + vncipher $out3,$out3,v26 + vncipher $out4,$out4,v26 + vxor $in1,$twk1,v31 + + vncipher $out0,$out0,v27 + lvx_u $in0,0,$inp + vncipher $out1,$out1,v27 + vncipher $out2,$out2,v27 + vncipher $out3,$out3,v27 + vncipher $out4,$out4,v27 + vxor $in2,$twk2,v31 + + addi $key_,$sp,$FRAME+15 # rewind $key_ + vncipher $out0,$out0,v28 + vncipher $out1,$out1,v28 + vncipher $out2,$out2,v28 + vncipher $out3,$out3,v28 + vncipher $out4,$out4,v28 + lvx v24,$x00,$key_ # re-pre-load round[1] + vxor $in3,$twk3,v31 + + vncipher $out0,$out0,v29 + le?vperm $in0,$in0,$in0,$leperm + vncipher $out1,$out1,v29 + vncipher $out2,$out2,v29 + vncipher $out3,$out3,v29 + vncipher $out4,$out4,v29 + lvx v25,$x10,$key_ # re-pre-load round[2] + vxor $in4,$twk4,v31 + + vncipher $out0,$out0,v30 + vncipher $out1,$out1,v30 + vncipher $out2,$out2,v30 + vncipher $out3,$out3,v30 + vncipher $out4,$out4,v30 + + vncipherlast $out0,$out0,$twk0 + vncipherlast $out1,$out1,$in1 + vncipherlast $out2,$out2,$in2 + vncipherlast $out3,$out3,$in3 + vncipherlast $out4,$out4,$in4 + mtctr $rounds + blr + .long 0 + .byte 0,12,0x14,0,0,0,0,0 +___ +}} }}} + +my $consts=1; +foreach(split("\n",$code)) { + s/\`([^\`]*)\`/eval($1)/geo; + + # constants table endian-specific conversion + if ($consts && m/\.(long|byte)\s+(.+)\s+(\?[a-z]*)$/o) { + my $conv=$3; + my @bytes=(); + + # convert to endian-agnostic format + if ($1 eq "long") { + foreach (split(/,\s*/,$2)) { + my $l = /^0/?oct:int; + push @bytes,($l>>24)&0xff,($l>>16)&0xff,($l>>8)&0xff,$l&0xff; + } + } else { + @bytes = map(/^0/?oct:int,split(/,\s*/,$2)); + } + + # little-endian conversion + if ($flavour =~ /le$/o) { + SWITCH: for($conv) { + /\?inv/ && do { @bytes=map($_^0xf,@bytes); last; }; + /\?rev/ && do { @bytes=reverse(@bytes); last; }; + } + } + + #emit + print ".byte\t",join(',',map (sprintf("0x%02x",$_),@bytes)),"\n"; + next; + } + $consts=0 if (m/Lconsts:/o); # end of table + + # instructions prefixed with '?' are endian-specific and need + # to be adjusted accordingly... + if ($flavour =~ /le$/o) { # little-endian + s/le\?//o or + s/be\?/#be#/o or + s/\?lvsr/lvsl/o or + s/\?lvsl/lvsr/o or + s/\?(vperm\s+v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+,\s*)(v[0-9]+)/$1$3$2$4/o or + s/\?(vsldoi\s+v[0-9]+,\s*)(v[0-9]+,)\s*(v[0-9]+,\s*)([0-9]+)/$1$3$2 16-$4/o or + s/\?(vspltw\s+v[0-9]+,\s*)(v[0-9]+,)\s*([0-9])/$1$2 3-$3/o; + } else { # big-endian + s/le\?/#le#/o or + s/be\?//o or + s/\?([a-z]+)/$1/o; + } + + print $_,"\n"; +} + +close STDOUT; diff --git a/src/crypto/aes/asm/aesv8-armx.pl b/src/crypto/aes/asm/aesv8-armx.pl index a1804265..f6d0dabd 100644 --- a/src/crypto/aes/asm/aesv8-armx.pl +++ b/src/crypto/aes/asm/aesv8-armx.pl @@ -42,7 +42,7 @@ die "can't locate arm-xlate.pl"; open OUT,"| \"$^X\" $xlate $flavour $output"; *STDOUT=*OUT; -$prefix="aes_v8"; +$prefix="aes_hw"; $code=<<___; #include <openssl/arm_arch.h> diff --git a/src/crypto/aes/key_wrap.c b/src/crypto/aes/key_wrap.c new file mode 100644 index 00000000..e955c475 --- /dev/null +++ b/src/crypto/aes/key_wrap.c @@ -0,0 +1,134 @@ +/* ==================================================================== + * Copyright (c) 2001-2011 The OpenSSL Project. All rights reserved. + * + * 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 above 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 acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED 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 OpenSSL PROJECT OR + * ITS 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. + * ==================================================================== */ + +#include <openssl/aes.h> + +#include <limits.h> +#include <string.h> + +#include <openssl/mem.h> + + +/* kDefaultIV is the default IV value given in RFC 3394, 2.2.3.1. */ +static const uint8_t kDefaultIV[] = { + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, +}; + +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. */ + + if (in_len > INT_MAX - 8 || in_len < 8 || in_len % 8 != 0) { + return -1; + } + + if (iv == NULL) { + iv = kDefaultIV; + } + + memmove(out + 8, in, in_len); + uint8_t A[AES_BLOCK_SIZE]; + memcpy(A, iv, 8); + + size_t n = in_len / 8; + + for (unsigned j = 0; j < 6; j++) { + for (size_t i = 1; i <= n; i++) { + memcpy(A + 8, out + 8 * i, 8); + AES_encrypt(A, A, key); + + uint32_t t = (uint32_t)(n * j + i); + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(out + 8 * i, A + 8, 8); + } + } + + memcpy(out, A, 8); + return (int)in_len + 8; +} + +int AES_unwrap_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.2. */ + + if (in_len > INT_MAX || in_len < 16 || in_len % 8 != 0) { + return -1; + } + + if (iv == NULL) { + iv = kDefaultIV; + } + + uint8_t A[AES_BLOCK_SIZE]; + memcpy(A, in, 8); + memmove(out, in + 8, in_len - 8); + + size_t n = (in_len / 8) - 1; + + for (unsigned j = 5; j < 6; j--) { + for (size_t i = n; i > 0; i--) { + uint32_t t = (uint32_t)(n * j + i); + A[7] ^= t & 0xff; + A[6] ^= (t >> 8) & 0xff; + A[5] ^= (t >> 16) & 0xff; + A[4] ^= (t >> 24) & 0xff; + memcpy(A + 8, out + 8 * (i - 1), 8); + AES_decrypt(A, A, key); + memcpy(out + 8 * (i - 1), A + 8, 8); + } + } + + if (CRYPTO_memcmp(A, iv, 8) != 0) { + return -1; + } + + return (int)in_len - 8; +} diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc index 0a359bda..04888100 100644 --- a/src/crypto/bn/bn_test.cc +++ b/src/crypto/bn/bn_test.cc @@ -340,7 +340,7 @@ static bool TestSquare(FileTest *t, BN_CTX *ctx) { BN_zero(zero.get()); bssl::UniquePtr<BIGNUM> ret(BN_new()), remainder(BN_new()); - if (!ret || + if (!ret || !remainder || !BN_sqr(ret.get(), a.get(), ctx) || !ExpectBIGNUMsEqual(t, "A^2", square.get(), ret.get()) || !BN_mul(ret.get(), a.get(), a.get(), ctx) || @@ -876,6 +876,10 @@ static bool TestMPI() { for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMPITests); i++) { const MPITest &test = kMPITests[i]; bssl::UniquePtr<BIGNUM> bn(ASCIIToBIGNUM(test.base10)); + if (!bn) { + return false; + } + const size_t mpi_len = BN_bn2mpi(bn.get(), NULL); if (mpi_len > sizeof(scratch)) { fprintf(stderr, "MPI test #%u: MPI size is too large to test.\n", diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc index 251aa37e..563c6b0e 100644 --- a/src/crypto/bytestring/bytestring_test.cc +++ b/src/crypto/bytestring/bytestring_test.cc @@ -231,6 +231,25 @@ static bool TestGetASN1() { return false; } + unsigned tag; + CBS_init(&data, kData1, sizeof(kData1)); + if (!CBS_get_any_asn1(&data, &contents, &tag) || + tag != CBS_ASN1_SEQUENCE || + CBS_len(&contents) != 2 || + memcmp(CBS_data(&contents), "\x01\x02", 2) != 0) { + return false; + } + + size_t header_len; + CBS_init(&data, kData1, sizeof(kData1)); + if (!CBS_get_any_asn1_element(&data, &contents, &tag, &header_len) || + tag != CBS_ASN1_SEQUENCE || + header_len != 2 || + CBS_len(&contents) != 4 || + memcmp(CBS_data(&contents), "\x30\x02\x01\x02", 2) != 0) { + return false; + } + return true; } diff --git a/src/crypto/bytestring/cbs.c b/src/crypto/bytestring/cbs.c index a7adc436..f702f062 100644 --- a/src/crypto/bytestring/cbs.c +++ b/src/crypto/bytestring/cbs.c @@ -262,6 +262,20 @@ static int cbs_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, return CBS_get_bytes(cbs, out, len); } +int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag) { + size_t header_len; + if (!CBS_get_any_asn1_element(cbs, out, out_tag, &header_len)) { + return 0; + } + + if (!CBS_skip(out, header_len)) { + assert(0); + return 0; + } + + return 1; +} + int CBS_get_any_asn1_element(CBS *cbs, CBS *out, unsigned *out_tag, size_t *out_header_len) { return cbs_get_any_asn1_element(cbs, out, out_tag, out_header_len, diff --git a/src/crypto/cipher/aead_test.cc b/src/crypto/cipher/aead_test.cc index 0dbb8c61..b33a36df 100644 --- a/src/crypto/cipher/aead_test.cc +++ b/src/crypto/cipher/aead_test.cc @@ -316,8 +316,6 @@ static const struct KnownAEAD kAEADs[] = { { "aes-128-cbc-sha1-ssl3", EVP_aead_aes_128_cbc_sha1_ssl3, true }, { "aes-256-cbc-sha1-ssl3", EVP_aead_aes_256_cbc_sha1_ssl3, true }, { "des-ede3-cbc-sha1-ssl3", EVP_aead_des_ede3_cbc_sha1_ssl3, true }, - { "aes-128-key-wrap", EVP_aead_aes_128_key_wrap, true }, - { "aes-256-key-wrap", EVP_aead_aes_256_key_wrap, true }, { "aes-128-ctr-hmac-sha256", EVP_aead_aes_128_ctr_hmac_sha256, false }, { "aes-256-ctr-hmac-sha256", EVP_aead_aes_256_ctr_hmac_sha256, false }, { "", NULL, false }, diff --git a/src/crypto/cipher/e_aes.c b/src/crypto/cipher/e_aes.c index 6e9ea9f5..9225d6a7 100644 --- a/src/crypto/cipher/e_aes.c +++ b/src/crypto/cipher/e_aes.c @@ -125,18 +125,15 @@ static int hwaes_capable(void) { return CRYPTO_is_ARMv8_AES_capable(); } -int aes_v8_set_encrypt_key(const uint8_t *user_key, const int bits, - AES_KEY *key); -int aes_v8_set_decrypt_key(const uint8_t *user_key, const int bits, - AES_KEY *key); -void aes_v8_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); -void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, - const AES_KEY *key, uint8_t *ivec, const int enc); -void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, - const AES_KEY *key, const uint8_t ivec[16]); +#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_PPC64LE) + +#define HWAES +static int hwaes_capable(void) { + return CRYPTO_is_PPC64LE_vcrypto_capable(); +} + +#endif /* OPENSSL_PPC64LE */ -#endif /* OPENSSL_ARM */ #if defined(BSAES) /* On platforms where BSAES gets defined (just above), then these functions are @@ -202,39 +199,50 @@ static void vpaes_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, } #endif -#if !defined(HWAES) +#if defined(HWAES) +int aes_hw_set_encrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +int aes_hw_set_decrypt_key(const uint8_t *user_key, const int bits, + AES_KEY *key); +void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key); +void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, + const AES_KEY *key, uint8_t *ivec, const int enc); +void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, + const AES_KEY *key, const uint8_t ivec[16]); +#else /* If HWAES isn't defined then we provide dummy functions for each of the hwaes * functions. */ static int hwaes_capable(void) { return 0; } -static int aes_v8_set_encrypt_key(const uint8_t *user_key, int bits, +static int aes_hw_set_encrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static int aes_v8_set_decrypt_key(const uint8_t *user_key, int bits, +static int aes_hw_set_decrypt_key(const uint8_t *user_key, int bits, AES_KEY *key) { abort(); } -static void aes_v8_encrypt(const uint8_t *in, uint8_t *out, +static void aes_hw_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_decrypt(const uint8_t *in, uint8_t *out, +static void aes_hw_decrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key) { abort(); } -static void aes_v8_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, +static void aes_hw_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t length, const AES_KEY *key, uint8_t *ivec, int enc) { abort(); } -static void aes_v8_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, +static void aes_hw_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t len, const AES_KEY *key, const uint8_t ivec[16]) { abort(); @@ -281,11 +289,11 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, mode = ctx->cipher->flags & EVP_CIPH_MODE_MASK; if ((mode == EVP_CIPH_ECB_MODE || mode == EVP_CIPH_CBC_MODE) && !enc) { if (hwaes_capable()) { - ret = aes_v8_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_v8_decrypt; + ret = aes_hw_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_hw_decrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; } } else if (bsaes_capable() && mode == EVP_CIPH_CBC_MODE) { ret = AES_set_decrypt_key(key, ctx->key_len * 8, &dat->ks.ks); @@ -303,13 +311,13 @@ static int aes_init_key(EVP_CIPHER_CTX *ctx, const uint8_t *key, mode == EVP_CIPH_CBC_MODE ? (cbc128_f)AES_cbc_encrypt : NULL; } } else if (hwaes_capable()) { - ret = aes_v8_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); - dat->block = (block128_f)aes_v8_encrypt; + ret = aes_hw_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); + dat->block = (block128_f)aes_hw_encrypt; dat->stream.cbc = NULL; if (mode == EVP_CIPH_CBC_MODE) { - dat->stream.cbc = (cbc128_f)aes_v8_cbc_encrypt; + dat->stream.cbc = (cbc128_f)aes_hw_cbc_encrypt; } else if (mode == EVP_CIPH_CTR_MODE) { - dat->stream.ctr = (ctr128_f)aes_v8_ctr32_encrypt_blocks; + dat->stream.ctr = (ctr128_f)aes_hw_ctr32_encrypt_blocks; } } else if (bsaes_capable() && mode == EVP_CIPH_CTR_MODE) { ret = AES_set_encrypt_key(key, ctx->key_len * 8, &dat->ks.ks); @@ -406,14 +414,14 @@ static ctr128_f aes_ctr_set_key(AES_KEY *aes_key, GCM128_CONTEXT *gcm_ctx, } if (hwaes_capable()) { - aes_v8_set_encrypt_key(key, key_len * 8, aes_key); + aes_hw_set_encrypt_key(key, key_len * 8, aes_key); if (gcm_ctx != NULL) { - CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_v8_encrypt); + CRYPTO_gcm128_init(gcm_ctx, aes_key, (block128_f)aes_hw_encrypt); } if (out_block) { - *out_block = (block128_f) aes_v8_encrypt; + *out_block = (block128_f) aes_hw_encrypt; } - return (ctr128_f)aes_v8_ctr32_encrypt_blocks; + return (ctr128_f)aes_hw_ctr32_encrypt_blocks; } if (bsaes_capable()) { @@ -1171,266 +1179,6 @@ const EVP_AEAD *EVP_aead_aes_128_gcm(void) { return &aead_aes_128_gcm; } const EVP_AEAD *EVP_aead_aes_256_gcm(void) { return &aead_aes_256_gcm; } -/* AES Key Wrap is specified in - * http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf - * or https://tools.ietf.org/html/rfc3394 */ - -struct aead_aes_key_wrap_ctx { - uint8_t key[32]; - unsigned key_bits; -}; - -static int aead_aes_key_wrap_init(EVP_AEAD_CTX *ctx, const uint8_t *key, - size_t key_len, size_t tag_len) { - struct aead_aes_key_wrap_ctx *kw_ctx; - const size_t key_bits = key_len * 8; - - if (key_bits != 128 && key_bits != 256) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_KEY_LENGTH); - return 0; /* EVP_AEAD_CTX_init should catch this. */ - } - - if (tag_len == EVP_AEAD_DEFAULT_TAG_LENGTH) { - tag_len = 8; - } - - if (tag_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_TAG_SIZE); - return 0; - } - - kw_ctx = OPENSSL_malloc(sizeof(struct aead_aes_key_wrap_ctx)); - if (kw_ctx == NULL) { - OPENSSL_PUT_ERROR(CIPHER, ERR_R_MALLOC_FAILURE); - return 0; - } - - memcpy(kw_ctx->key, key, key_len); - kw_ctx->key_bits = key_bits; - - ctx->aead_state = kw_ctx; - return 1; -} - -static void aead_aes_key_wrap_cleanup(EVP_AEAD_CTX *ctx) { - struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - OPENSSL_cleanse(kw_ctx, sizeof(struct aead_aes_key_wrap_ctx)); - OPENSSL_free(kw_ctx); -} - -/* kDefaultAESKeyWrapNonce is the default nonce value given in 2.2.3.1. */ -static const uint8_t kDefaultAESKeyWrapNonce[8] = {0xa6, 0xa6, 0xa6, 0xa6, - 0xa6, 0xa6, 0xa6, 0xa6}; - - -static int aead_aes_key_wrap_seal(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - union { - double align; - AES_KEY ks; - } ks; - /* Variables in this function match up with the variables in the second half - * of section 2.2.1. */ - unsigned i, j, n; - uint8_t A[AES_BLOCK_SIZE]; - - if (ad_len != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); - return 0; - } - - if (nonce_len == 0) { - nonce = kDefaultAESKeyWrapNonce; - nonce_len = sizeof(kDefaultAESKeyWrapNonce); - } - - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - - if (in_len % 8 != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - /* The code below only handles a 32-bit |t| thus 6*|n| must be less than - * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we - * conservatively cap it to 2^32-16 to stop 32-bit platforms complaining that - * a comparison is always true. */ - if (in_len > 0xfffffff0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - n = in_len / 8; - - if (n < 2) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - if (in_len + 8 < in_len) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - if (max_out_len < in_len + 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); - return 0; - } - - if (AES_set_encrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); - return 0; - } - - memmove(out + 8, in, in_len); - memcpy(A, nonce, 8); - - for (j = 0; j < 6; j++) { - for (i = 1; i <= n; i++) { - uint32_t t; - - memcpy(A + 8, out + 8 * i, 8); - AES_encrypt(A, A, &ks.ks); - t = n * j + i; - A[7] ^= t & 0xff; - A[6] ^= (t >> 8) & 0xff; - A[5] ^= (t >> 16) & 0xff; - A[4] ^= (t >> 24) & 0xff; - memcpy(out + 8 * i, A + 8, 8); - } - } - - memcpy(out, A, 8); - *out_len = in_len + 8; - return 1; -} - -static int aead_aes_key_wrap_open(const EVP_AEAD_CTX *ctx, uint8_t *out, - size_t *out_len, size_t max_out_len, - const uint8_t *nonce, size_t nonce_len, - const uint8_t *in, size_t in_len, - const uint8_t *ad, size_t ad_len) { - const struct aead_aes_key_wrap_ctx *kw_ctx = ctx->aead_state; - union { - double align; - AES_KEY ks; - } ks; - /* Variables in this function match up with the variables in the second half - * of section 2.2.1. */ - unsigned i, j, n; - uint8_t A[AES_BLOCK_SIZE]; - - if (ad_len != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_AD_SIZE); - return 0; - } - - if (nonce_len == 0) { - nonce = kDefaultAESKeyWrapNonce; - nonce_len = sizeof(kDefaultAESKeyWrapNonce); - } - - if (nonce_len != 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); - return 0; - } - - if (in_len % 8 != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_INPUT_SIZE); - return 0; - } - - /* The code below only handles a 32-bit |t| thus 6*|n| must be less than - * 2^32, where |n| is |in_len| / 8. So in_len < 4/3 * 2^32 and we - * conservatively cap it to 2^32-8 to stop 32-bit platforms complaining that - * a comparison is always true. */ - if (in_len > 0xfffffff8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); - return 0; - } - - if (in_len < 24) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - - n = (in_len / 8) - 1; - - if (max_out_len < in_len - 8) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); - return 0; - } - - if (AES_set_decrypt_key(kw_ctx->key, kw_ctx->key_bits, &ks.ks) < 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_AES_KEY_SETUP_FAILED); - return 0; - } - - memcpy(A, in, 8); - memmove(out, in + 8, in_len - 8); - - for (j = 5; j < 6; j--) { - for (i = n; i > 0; i--) { - uint32_t t; - - t = n * j + i; - A[7] ^= t & 0xff; - A[6] ^= (t >> 8) & 0xff; - A[5] ^= (t >> 16) & 0xff; - A[4] ^= (t >> 24) & 0xff; - memcpy(A + 8, out + 8 * (i - 1), 8); - AES_decrypt(A, A, &ks.ks); - memcpy(out + 8 * (i - 1), A + 8, 8); - } - } - - if (CRYPTO_memcmp(A, nonce, 8) != 0) { - OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); - return 0; - } - - *out_len = in_len - 8; - return 1; -} - -static const EVP_AEAD aead_aes_128_key_wrap = { - 16, /* key len */ - 8, /* nonce len */ - 8, /* overhead */ - 8, /* max tag length */ - aead_aes_key_wrap_init, - NULL, /* init_with_direction */ - aead_aes_key_wrap_cleanup, - aead_aes_key_wrap_seal, - aead_aes_key_wrap_open, - NULL, /* get_iv */ -}; - -static const EVP_AEAD aead_aes_256_key_wrap = { - 32, /* key len */ - 8, /* nonce len */ - 8, /* overhead */ - 8, /* max tag length */ - aead_aes_key_wrap_init, - NULL, /* init_with_direction */ - aead_aes_key_wrap_cleanup, - aead_aes_key_wrap_seal, - aead_aes_key_wrap_open, - NULL, /* get_iv */ -}; - -const EVP_AEAD *EVP_aead_aes_128_key_wrap(void) { return &aead_aes_128_key_wrap; } - -const EVP_AEAD *EVP_aead_aes_256_key_wrap(void) { return &aead_aes_256_key_wrap; } - - #define EVP_AEAD_AES_CTR_HMAC_SHA256_TAG_LEN SHA256_DIGEST_LENGTH #define EVP_AEAD_AES_CTR_HMAC_SHA256_NONCE_LEN 12 diff --git a/src/crypto/cipher/test/aes_128_key_wrap_tests.txt b/src/crypto/cipher/test/aes_128_key_wrap_tests.txt deleted file mode 100644 index 561ec90b..00000000 --- a/src/crypto/cipher/test/aes_128_key_wrap_tests.txt +++ /dev/null @@ -1,9 +0,0 @@ -# These test vectors have been taken from -# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf - -KEY: 000102030405060708090A0B0C0D0E0F -NONCE: -IN: 00112233445566778899AABBCCDDEEFF -AD: -CT: 1FA68B0A8112B447AEF34BD8FB5A7B82 -TAG: 9D3E862371D2CFE5 diff --git a/src/crypto/cipher/test/aes_256_key_wrap_tests.txt b/src/crypto/cipher/test/aes_256_key_wrap_tests.txt deleted file mode 100644 index 92d3a049..00000000 --- a/src/crypto/cipher/test/aes_256_key_wrap_tests.txt +++ /dev/null @@ -1,23 +0,0 @@ -# These test vectors have been taken from -# http://csrc.nist.gov/groups/ST/toolkit/documents/kms/key-wrap.pdf - -KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F -NONCE: -IN: 00112233445566778899AABBCCDDEEFF -AD: -CT: 64E8C3F9CE0F5BA263E9777905818A2A -TAG: 93C8191E7D6E8AE7 - -KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F -NONCE: -IN: 00112233445566778899AABBCCDDEEFF0001020304050607 -AD: -CT: A8F9BC1612C68B3FF6E6F4FBE30E71E4769C8B80A32CB895 -TAG: 8CD5D17D6B254DA1 - -KEY: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F -NONCE: -IN: 00112233445566778899AABBCCDDEEFF000102030405060708090A0B0C0D0E0F -AD: -CT: 28C9F404C4B810F4CBCCB35CFB87F8263F5786E2D80ED326CBC7F0E71A99F43B -TAG: FB988B9B7A02DD21 diff --git a/src/crypto/cpu-ppc64le.c b/src/crypto/cpu-ppc64le.c new file mode 100644 index 00000000..c431c818 --- /dev/null +++ b/src/crypto/cpu-ppc64le.c @@ -0,0 +1,40 @@ +/* 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/cpu.h> + +#if defined(OPENSSL_PPC64LE) + +#include <sys/auxv.h> + +#include "internal.h" + + +#if !defined(PPC_FEATURE2_HAS_VCRYPTO) +/* PPC_FEATURE2_HAS_VCRYPTO was taken from section 4.1.2.3 of the “OpenPOWER + * ABI for Linux Supplement”. */ +#define PPC_FEATURE2_HAS_VCRYPTO 0x02000000 +#endif + +static unsigned long g_ppc64le_hwcap2 = 0; + +void OPENSSL_cpuid_setup(void) { + g_ppc64le_hwcap2 = getauxval(AT_HWCAP2); +} + +int CRYPTO_is_PPC64LE_vcrypto_capable(void) { + return (g_ppc64le_hwcap2 & PPC_FEATURE2_HAS_VCRYPTO) != 0; +} + +#endif /* OPENSSL_PPC64LE */ diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c index 24431267..c32f5144 100644 --- a/src/crypto/crypto.c +++ b/src/crypto/crypto.c @@ -21,9 +21,11 @@ #if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_STATIC_ARMCAP) && \ (defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || \ - defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)) -/* x86, x86_64 and the ARMs need to record the result of a cpuid call for the - * asm to work correctly, unless compiled without asm code. */ + defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) || \ + defined(OPENSSL_PPC64LE)) +/* x86, x86_64, the ARMs and ppc64le need to record the result of a + * cpuid/getauxval call for the asm to work correctly, unless compiled without + * asm code. */ #define NEED_CPUID #else diff --git a/src/crypto/ec/asm/p256-x86_64-asm.pl b/src/crypto/ec/asm/p256-x86_64-asm.pl index 2a6e5e28..0a7d6405 100755 --- a/src/crypto/ec/asm/p256-x86_64-asm.pl +++ b/src/crypto/ec/asm/p256-x86_64-asm.pl @@ -333,7 +333,7 @@ __ecp_nistz256_mul_montq: adc \$0, $acc0 ######################################################################## - # Second reduction step + # Second reduction step mov $acc1, $t1 shl \$32, $acc1 mulq $poly3 @@ -380,7 +380,7 @@ __ecp_nistz256_mul_montq: adc \$0, $acc1 ######################################################################## - # Third reduction step + # Third reduction step mov $acc2, $t1 shl \$32, $acc2 mulq $poly3 @@ -427,7 +427,7 @@ __ecp_nistz256_mul_montq: adc \$0, $acc2 ######################################################################## - # Final reduction step + # Final reduction step mov $acc3, $t1 shl \$32, $acc3 mulq $poly3 @@ -440,7 +440,7 @@ __ecp_nistz256_mul_montq: mov $acc5, $t1 adc \$0, $acc2 - ######################################################################## + ######################################################################## # Branch-less conditional subtraction of P sub \$-1, $acc4 # .Lpoly[0] mov $acc0, $t2 @@ -1067,6 +1067,8 @@ ecp_nistz256_from_mont: mov $acc1, $in_ptr adc \$0, %rdx + ########################################### + # Branch-less conditional subtraction sub \$-1, $acc0 mov $acc2, %rax sbb $t1, $acc1 @@ -1793,7 +1795,7 @@ $code.=<<___; movq %xmm1, $r_ptr call __ecp_nistz256_sqr_mont$x # p256_sqr_mont(res_y, S); ___ -{ +{ ######## ecp_nistz256_div_by_2(res_y, res_y); ########################## # operate in 4-5-6-7 "name space" that matches squaring output # @@ -1882,7 +1884,7 @@ $code.=<<___; lea $M(%rsp), $b_ptr mov $acc4, $acc6 # harmonize sub output and mul input xor %ecx, %ecx - mov $acc4, $S+8*0(%rsp) # have to save:-( + mov $acc4, $S+8*0(%rsp) # have to save:-( mov $acc5, $acc2 mov $acc5, $S+8*1(%rsp) cmovz $acc0, $acc3 diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata index e19b347b..9045e9a7 100644 --- a/src/crypto/err/ssl.errordata +++ b/src/crypto/err/ssl.errordata @@ -95,6 +95,7 @@ SSL,181,NO_PRIVATE_KEY_ASSIGNED SSL,182,NO_RENEGOTIATION SSL,183,NO_REQUIRED_DIGEST SSL,184,NO_SHARED_CIPHER +SSL,266,NO_SHARED_GROUP SSL,185,NULL_SSL_CTX SSL,186,NULL_SSL_METHOD_PASSED SSL,187,OLD_SESSION_CIPHER_NOT_RETURNED diff --git a/src/crypto/internal.h b/src/crypto/internal.h index 8ac60cbd..896cc3ba 100644 --- a/src/crypto/internal.h +++ b/src/crypto/internal.h @@ -141,8 +141,8 @@ extern "C" { #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) || defined(OPENSSL_ARM) || \ - defined(OPENSSL_AARCH64) -/* OPENSSL_cpuid_setup initializes OPENSSL_ia32cap_P. */ + defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) +/* OPENSSL_cpuid_setup initializes the platform-specific feature cache. */ void OPENSSL_cpuid_setup(void); #endif diff --git a/src/crypto/modes/CMakeLists.txt b/src/crypto/modes/CMakeLists.txt index e8aa2725..17faa155 100644 --- a/src/crypto/modes/CMakeLists.txt +++ b/src/crypto/modes/CMakeLists.txt @@ -34,6 +34,14 @@ if (${ARCH} STREQUAL "aarch64") ) endif() +if (${ARCH} STREQUAL "ppc64le") + set( + MODES_ARCH_SOURCES + + ghashp8-ppc.${ASM_EXT} + ) +endif() + add_library( modes @@ -53,6 +61,7 @@ perlasm(ghash-x86_64.${ASM_EXT} asm/ghash-x86_64.pl) perlasm(ghash-x86.${ASM_EXT} asm/ghash-x86.pl) perlasm(ghash-armv4.${ASM_EXT} asm/ghash-armv4.pl) perlasm(ghashv8-armx.${ASM_EXT} asm/ghashv8-armx.pl) +perlasm(ghashp8-ppc.${ASM_EXT} asm/ghashp8-ppc.pl) add_executable( gcm_test diff --git a/src/crypto/modes/asm/ghashp8-ppc.pl b/src/crypto/modes/asm/ghashp8-ppc.pl new file mode 100644 index 00000000..f0598cb2 --- /dev/null +++ b/src/crypto/modes/asm/ghashp8-ppc.pl @@ -0,0 +1,670 @@ +#! /usr/bin/env perl +# Copyright 2014-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +# +# ==================================================================== +# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL +# project. The module is, however, dual licensed under OpenSSL and +# CRYPTOGAMS licenses depending on where you obtain it. For further +# details see http://www.openssl.org/~appro/cryptogams/. +# ==================================================================== +# +# GHASH for for PowerISA v2.07. +# +# July 2014 +# +# Accurate performance measurements are problematic, because it's +# always virtualized setup with possibly throttled processor. +# Relative comparison is therefore more informative. This initial +# version is ~2.1x slower than hardware-assisted AES-128-CTR, ~12x +# faster than "4-bit" integer-only compiler-generated 64-bit code. +# "Initial version" means that there is room for futher improvement. + +# May 2016 +# +# 2x aggregated reduction improves performance by 50% (resulting +# performance on POWER8 is 1 cycle per processed byte), and 4x +# aggregated reduction - by 170% or 2.7x (resulting in 0.55 cpb). + +$flavour=shift; +$output =shift; + +if ($flavour =~ /64/) { + $SIZE_T=8; + $LRSAVE=2*$SIZE_T; + $STU="stdu"; + $POP="ld"; + $PUSH="std"; + $UCMP="cmpld"; + $SHRI="srdi"; +} elsif ($flavour =~ /32/) { + $SIZE_T=4; + $LRSAVE=$SIZE_T; + $STU="stwu"; + $POP="lwz"; + $PUSH="stw"; + $UCMP="cmplw"; + $SHRI="srwi"; +} else { die "nonsense $flavour"; } + +$sp="r1"; +$FRAME=6*$SIZE_T+13*16; # 13*16 is for v20-v31 offload + +$0 =~ m/(.*[\/\\])[^\/\\]+$/; $dir=$1; +( $xlate="${dir}ppc-xlate.pl" and -f $xlate ) or +( $xlate="${dir}../../perlasm/ppc-xlate.pl" and -f $xlate) or +die "can't locate ppc-xlate.pl"; + +open STDOUT,"| $^X $xlate $flavour $output" || die "can't call $xlate: $!"; + +my ($Xip,$Htbl,$inp,$len)=map("r$_",(3..6)); # argument block + +my ($Xl,$Xm,$Xh,$IN)=map("v$_",(0..3)); +my ($zero,$t0,$t1,$t2,$xC2,$H,$Hh,$Hl,$lemask)=map("v$_",(4..12)); +my ($Xl1,$Xm1,$Xh1,$IN1,$H2,$H2h,$H2l)=map("v$_",(13..19)); +my $vrsave="r12"; + +$code=<<___; +.machine "any" + +.text + +.globl .gcm_init_p8 +.align 5 +.gcm_init_p8: + li r0,-4096 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $H,0,r4 # load H + + vspltisb $xC2,-16 # 0xf0 + vspltisb $t0,1 # one + vaddubm $xC2,$xC2,$xC2 # 0xe0 + vxor $zero,$zero,$zero + vor $xC2,$xC2,$t0 # 0xe1 + vsldoi $xC2,$xC2,$zero,15 # 0xe1... + vsldoi $t1,$zero,$t0,1 # ...1 + vaddubm $xC2,$xC2,$xC2 # 0xc2... + vspltisb $t2,7 + vor $xC2,$xC2,$t1 # 0xc2....01 + vspltb $t1,$H,0 # most significant byte + vsl $H,$H,$t0 # H<<=1 + vsrab $t1,$t1,$t2 # broadcast carry bit + vand $t1,$t1,$xC2 + vxor $IN,$H,$t1 # twisted H + + vsldoi $H,$IN,$IN,8 # twist even more ... + vsldoi $xC2,$zero,$xC2,8 # 0xc2.0 + vsldoi $Hl,$zero,$H,8 # ... and split + vsldoi $Hh,$H,$zero,8 + + stvx_u $xC2,0,r3 # save pre-computed table + stvx_u $Hl,r8,r3 + li r8,0x40 + stvx_u $H, r9,r3 + li r9,0x50 + stvx_u $Hh,r10,r3 + li r10,0x60 + + vpmsumd $Xl,$IN,$Hl # H.lo·H.lo + vpmsumd $Xm,$IN,$H # H.hi·H.lo+H.lo·H.hi + vpmsumd $Xh,$IN,$Hh # H.hi·H.hi + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + vxor $t1,$t1,$Xh + vxor $IN1,$Xl,$t1 + + vsldoi $H2,$IN1,$IN1,8 + vsldoi $H2l,$zero,$H2,8 + vsldoi $H2h,$H2,$zero,8 + + stvx_u $H2l,r8,r3 # save H^2 + li r8,0x70 + stvx_u $H2,r9,r3 + li r9,0x80 + stvx_u $H2h,r10,r3 + li r10,0x90 +___ +{ +my ($t4,$t5,$t6) = ($Hl,$H,$Hh); +$code.=<<___; + vpmsumd $Xl,$IN,$H2l # H.lo·H^2.lo + vpmsumd $Xl1,$IN1,$H2l # H^2.lo·H^2.lo + vpmsumd $Xm,$IN,$H2 # H.hi·H^2.lo+H.lo·H^2.hi + vpmsumd $Xm1,$IN1,$H2 # H^2.hi·H^2.lo+H^2.lo·H^2.hi + vpmsumd $Xh,$IN,$H2h # H.hi·H^2.hi + vpmsumd $Xh1,$IN1,$H2h # H^2.hi·H^2.hi + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + vpmsumd $t6,$Xl1,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vsldoi $t4,$Xm1,$zero,8 + vsldoi $t5,$zero,$Xm1,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + vxor $Xl1,$Xl1,$t4 + vxor $Xh1,$Xh1,$t5 + + vsldoi $Xl,$Xl,$Xl,8 + vsldoi $Xl1,$Xl1,$Xl1,8 + vxor $Xl,$Xl,$t2 + vxor $Xl1,$Xl1,$t6 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vsldoi $t5,$Xl1,$Xl1,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + vpmsumd $Xl1,$Xl1,$xC2 + vxor $t1,$t1,$Xh + vxor $t5,$t5,$Xh1 + vxor $Xl,$Xl,$t1 + vxor $Xl1,$Xl1,$t5 + + vsldoi $H,$Xl,$Xl,8 + vsldoi $H2,$Xl1,$Xl1,8 + vsldoi $Hl,$zero,$H,8 + vsldoi $Hh,$H,$zero,8 + vsldoi $H2l,$zero,$H2,8 + vsldoi $H2h,$H2,$zero,8 + + stvx_u $Hl,r8,r3 # save H^3 + li r8,0xa0 + stvx_u $H,r9,r3 + li r9,0xb0 + stvx_u $Hh,r10,r3 + li r10,0xc0 + stvx_u $H2l,r8,r3 # save H^4 + stvx_u $H2,r9,r3 + stvx_u $H2h,r10,r3 + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,2,0 + .long 0 +.size .gcm_init_p8,.-.gcm_init_p8 +___ +} +$code.=<<___; +.globl .gcm_gmult_p8 +.align 5 +.gcm_gmult_p8: + lis r0,0xfff8 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $IN,0,$Xip # load Xi + + lvx_u $Hl,r8,$Htbl # load pre-computed table + le?lvsl $lemask,r0,r0 + lvx_u $H, r9,$Htbl + le?vspltisb $t0,0x07 + lvx_u $Hh,r10,$Htbl + le?vxor $lemask,$lemask,$t0 + lvx_u $xC2,0,$Htbl + le?vperm $IN,$IN,$IN,$lemask + vxor $zero,$zero,$zero + + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + vxor $t1,$t1,$Xh + vxor $Xl,$Xl,$t1 + + le?vperm $Xl,$Xl,$Xl,$lemask + stvx_u $Xl,0,$Xip # write out Xi + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,2,0 + .long 0 +.size .gcm_gmult_p8,.-.gcm_gmult_p8 + +.globl .gcm_ghash_p8 +.align 5 +.gcm_ghash_p8: + li r0,-4096 + li r8,0x10 + mfspr $vrsave,256 + li r9,0x20 + mtspr 256,r0 + li r10,0x30 + lvx_u $Xl,0,$Xip # load Xi + + lvx_u $Hl,r8,$Htbl # load pre-computed table + li r8,0x40 + le?lvsl $lemask,r0,r0 + lvx_u $H, r9,$Htbl + li r9,0x50 + le?vspltisb $t0,0x07 + lvx_u $Hh,r10,$Htbl + li r10,0x60 + le?vxor $lemask,$lemask,$t0 + lvx_u $xC2,0,$Htbl + le?vperm $Xl,$Xl,$Xl,$lemask + vxor $zero,$zero,$zero + + ${UCMP}i $len,64 + bge Lgcm_ghash_p8_4x + + lvx_u $IN,0,$inp + addi $inp,$inp,16 + subic. $len,$len,16 + le?vperm $IN,$IN,$IN,$lemask + vxor $IN,$IN,$Xl + beq Lshort + + lvx_u $H2l,r8,$Htbl # load H^2 + li r8,16 + lvx_u $H2, r9,$Htbl + add r9,$inp,$len # end of input + lvx_u $H2h,r10,$Htbl + be?b Loop_2x + +.align 5 +Loop_2x: + lvx_u $IN1,0,$inp + le?vperm $IN1,$IN1,$IN1,$lemask + + subic $len,$len,32 + vpmsumd $Xl,$IN,$H2l # H^2.lo·Xi.lo + vpmsumd $Xl1,$IN1,$Hl # H.lo·Xi+1.lo + subfe r0,r0,r0 # borrow?-1:0 + vpmsumd $Xm,$IN,$H2 # H^2.hi·Xi.lo+H^2.lo·Xi.hi + vpmsumd $Xm1,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+1.hi + and r0,r0,$len + vpmsumd $Xh,$IN,$H2h # H^2.hi·Xi.hi + vpmsumd $Xh1,$IN1,$Hh # H.hi·Xi+1.hi + add $inp,$inp,r0 + + vxor $Xl,$Xl,$Xl1 + vxor $Xm,$Xm,$Xm1 + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xh,$Xh,$Xh1 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + lvx_u $IN,r8,$inp + addi $inp,$inp,32 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + le?vperm $IN,$IN,$IN,$lemask + vxor $t1,$t1,$Xh + vxor $IN,$IN,$t1 + vxor $IN,$IN,$Xl + $UCMP r9,$inp + bgt Loop_2x # done yet? + + cmplwi $len,0 + bne Leven + +Lshort: + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + vxor $t1,$t1,$Xh + +Leven: + vxor $Xl,$Xl,$t1 + le?vperm $Xl,$Xl,$Xl,$lemask + stvx_u $Xl,0,$Xip # write out Xi + + mtspr 256,$vrsave + blr + .long 0 + .byte 0,12,0x14,0,0,0,4,0 + .long 0 +___ +{ +my ($Xl3,$Xm2,$IN2,$H3l,$H3,$H3h, + $Xh3,$Xm3,$IN3,$H4l,$H4,$H4h) = map("v$_",(20..31)); +my $IN0=$IN; +my ($H21l,$H21h,$loperm,$hiperm) = ($Hl,$Hh,$H2l,$H2h); + +$code.=<<___; +.align 5 +.gcm_ghash_p8_4x: +Lgcm_ghash_p8_4x: + $STU $sp,-$FRAME($sp) + li r10,`15+6*$SIZE_T` + li r11,`31+6*$SIZE_T` + stvx v20,r10,$sp + addi r10,r10,32 + stvx v21,r11,$sp + addi r11,r11,32 + stvx v22,r10,$sp + addi r10,r10,32 + stvx v23,r11,$sp + addi r11,r11,32 + stvx v24,r10,$sp + addi r10,r10,32 + stvx v25,r11,$sp + addi r11,r11,32 + stvx v26,r10,$sp + addi r10,r10,32 + stvx v27,r11,$sp + addi r11,r11,32 + stvx v28,r10,$sp + addi r10,r10,32 + stvx v29,r11,$sp + addi r11,r11,32 + stvx v30,r10,$sp + li r10,0x60 + stvx v31,r11,$sp + li r0,-1 + stw $vrsave,`$FRAME-4`($sp) # save vrsave + mtspr 256,r0 # preserve all AltiVec registers + + lvsl $t0,0,r8 # 0x0001..0e0f + #lvx_u $H2l,r8,$Htbl # load H^2 + li r8,0x70 + lvx_u $H2, r9,$Htbl + li r9,0x80 + vspltisb $t1,8 # 0x0808..0808 + #lvx_u $H2h,r10,$Htbl + li r10,0x90 + lvx_u $H3l,r8,$Htbl # load H^3 + li r8,0xa0 + lvx_u $H3, r9,$Htbl + li r9,0xb0 + lvx_u $H3h,r10,$Htbl + li r10,0xc0 + lvx_u $H4l,r8,$Htbl # load H^4 + li r8,0x10 + lvx_u $H4, r9,$Htbl + li r9,0x20 + lvx_u $H4h,r10,$Htbl + li r10,0x30 + + vsldoi $t2,$zero,$t1,8 # 0x0000..0808 + vaddubm $hiperm,$t0,$t2 # 0x0001..1617 + vaddubm $loperm,$t1,$hiperm # 0x0809..1e1f + + $SHRI $len,$len,4 # this allows to use sign bit + # as carry + lvx_u $IN0,0,$inp # load input + lvx_u $IN1,r8,$inp + subic. $len,$len,8 + lvx_u $IN2,r9,$inp + lvx_u $IN3,r10,$inp + addi $inp,$inp,0x40 + le?vperm $IN0,$IN0,$IN0,$lemask + le?vperm $IN1,$IN1,$IN1,$lemask + le?vperm $IN2,$IN2,$IN2,$lemask + le?vperm $IN3,$IN3,$IN3,$lemask + + vxor $Xh,$IN0,$Xl + + vpmsumd $Xl1,$IN1,$H3l + vpmsumd $Xm1,$IN1,$H3 + vpmsumd $Xh1,$IN1,$H3h + + vperm $H21l,$H2,$H,$hiperm + vperm $t0,$IN2,$IN3,$loperm + vperm $H21h,$H2,$H,$loperm + vperm $t1,$IN2,$IN3,$hiperm + vpmsumd $Xm2,$IN2,$H2 # H^2.lo·Xi+2.hi+H^2.hi·Xi+2.lo + vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+2.lo+H.lo·Xi+3.lo + vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi + vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+2.hi+H.hi·Xi+3.hi + + vxor $Xm2,$Xm2,$Xm1 + vxor $Xl3,$Xl3,$Xl1 + vxor $Xm3,$Xm3,$Xm2 + vxor $Xh3,$Xh3,$Xh1 + + blt Ltail_4x + +Loop_4x: + lvx_u $IN0,0,$inp + lvx_u $IN1,r8,$inp + subic. $len,$len,4 + lvx_u $IN2,r9,$inp + lvx_u $IN3,r10,$inp + addi $inp,$inp,0x40 + le?vperm $IN1,$IN1,$IN1,$lemask + le?vperm $IN2,$IN2,$IN2,$lemask + le?vperm $IN3,$IN3,$IN3,$lemask + le?vperm $IN0,$IN0,$IN0,$lemask + + vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo + vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi + vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi + vpmsumd $Xl1,$IN1,$H3l + vpmsumd $Xm1,$IN1,$H3 + vpmsumd $Xh1,$IN1,$H3h + + vxor $Xl,$Xl,$Xl3 + vxor $Xm,$Xm,$Xm3 + vxor $Xh,$Xh,$Xh3 + vperm $t0,$IN2,$IN3,$loperm + vperm $t1,$IN2,$IN3,$hiperm + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + vpmsumd $Xl3,$t0,$H21l # H.lo·Xi+3.lo +H^2.lo·Xi+2.lo + vpmsumd $Xh3,$t1,$H21h # H.hi·Xi+3.hi +H^2.hi·Xi+2.hi + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xm2,$IN2,$H2 # H^2.hi·Xi+2.lo+H^2.lo·Xi+2.hi + vpmsumd $Xm3,$IN3,$H # H.hi·Xi+3.lo +H.lo·Xi+3.hi + vpmsumd $Xl,$Xl,$xC2 + + vxor $Xl3,$Xl3,$Xl1 + vxor $Xh3,$Xh3,$Xh1 + vxor $Xh,$Xh,$IN0 + vxor $Xm2,$Xm2,$Xm1 + vxor $Xh,$Xh,$t1 + vxor $Xm3,$Xm3,$Xm2 + vxor $Xh,$Xh,$Xl + bge Loop_4x + +Ltail_4x: + vpmsumd $Xl,$Xh,$H4l # H^4.lo·Xi.lo + vpmsumd $Xm,$Xh,$H4 # H^4.hi·Xi.lo+H^4.lo·Xi.hi + vpmsumd $Xh,$Xh,$H4h # H^4.hi·Xi.hi + + vxor $Xl,$Xl,$Xl3 + vxor $Xm,$Xm,$Xm3 + + vpmsumd $t2,$Xl,$xC2 # 1st reduction phase + + vsldoi $t0,$Xm,$zero,8 + vsldoi $t1,$zero,$Xm,8 + vxor $Xh,$Xh,$Xh3 + vxor $Xl,$Xl,$t0 + vxor $Xh,$Xh,$t1 + + vsldoi $Xl,$Xl,$Xl,8 + vxor $Xl,$Xl,$t2 + + vsldoi $t1,$Xl,$Xl,8 # 2nd reduction phase + vpmsumd $Xl,$Xl,$xC2 + vxor $t1,$t1,$Xh + vxor $Xl,$Xl,$t1 + + addic. $len,$len,4 + beq Ldone_4x + + lvx_u $IN0,0,$inp + ${UCMP}i $len,2 + li $len,-4 + blt Lone + lvx_u $IN1,r8,$inp + beq Ltwo + +Lthree: + lvx_u $IN2,r9,$inp + le?vperm $IN0,$IN0,$IN0,$lemask + le?vperm $IN1,$IN1,$IN1,$lemask + le?vperm $IN2,$IN2,$IN2,$lemask + + vxor $Xh,$IN0,$Xl + vmr $H4l,$H3l + vmr $H4, $H3 + vmr $H4h,$H3h + + vperm $t0,$IN1,$IN2,$loperm + vperm $t1,$IN1,$IN2,$hiperm + vpmsumd $Xm2,$IN1,$H2 # H^2.lo·Xi+1.hi+H^2.hi·Xi+1.lo + vpmsumd $Xm3,$IN2,$H # H.hi·Xi+2.lo +H.lo·Xi+2.hi + vpmsumd $Xl3,$t0,$H21l # H^2.lo·Xi+1.lo+H.lo·Xi+2.lo + vpmsumd $Xh3,$t1,$H21h # H^2.hi·Xi+1.hi+H.hi·Xi+2.hi + + vxor $Xm3,$Xm3,$Xm2 + b Ltail_4x + +.align 4 +Ltwo: + le?vperm $IN0,$IN0,$IN0,$lemask + le?vperm $IN1,$IN1,$IN1,$lemask + + vxor $Xh,$IN0,$Xl + vperm $t0,$zero,$IN1,$loperm + vperm $t1,$zero,$IN1,$hiperm + + vsldoi $H4l,$zero,$H2,8 + vmr $H4, $H2 + vsldoi $H4h,$H2,$zero,8 + + vpmsumd $Xl3,$t0, $H21l # H.lo·Xi+1.lo + vpmsumd $Xm3,$IN1,$H # H.hi·Xi+1.lo+H.lo·Xi+2.hi + vpmsumd $Xh3,$t1, $H21h # H.hi·Xi+1.hi + + b Ltail_4x + +.align 4 +Lone: + le?vperm $IN0,$IN0,$IN0,$lemask + + vsldoi $H4l,$zero,$H,8 + vmr $H4, $H + vsldoi $H4h,$H,$zero,8 + + vxor $Xh,$IN0,$Xl + vxor $Xl3,$Xl3,$Xl3 + vxor $Xm3,$Xm3,$Xm3 + vxor $Xh3,$Xh3,$Xh3 + + b Ltail_4x + +Ldone_4x: + le?vperm $Xl,$Xl,$Xl,$lemask + stvx_u $Xl,0,$Xip # write out Xi + + li r10,`15+6*$SIZE_T` + li r11,`31+6*$SIZE_T` + mtspr 256,$vrsave + lvx v20,r10,$sp + addi r10,r10,32 + lvx v21,r11,$sp + addi r11,r11,32 + lvx v22,r10,$sp + addi r10,r10,32 + lvx v23,r11,$sp + addi r11,r11,32 + lvx v24,r10,$sp + addi r10,r10,32 + lvx v25,r11,$sp + addi r11,r11,32 + lvx v26,r10,$sp + addi r10,r10,32 + lvx v27,r11,$sp + addi r11,r11,32 + lvx v28,r10,$sp + addi r10,r10,32 + lvx v29,r11,$sp + addi r11,r11,32 + lvx v30,r10,$sp + lvx v31,r11,$sp + addi $sp,$sp,$FRAME + blr + .long 0 + .byte 0,12,0x04,0,0x80,0,4,0 + .long 0 +___ +} +$code.=<<___; +.size .gcm_ghash_p8,.-.gcm_ghash_p8 + +.asciz "GHASH for PowerISA 2.07, CRYPTOGAMS by <appro\@openssl.org>" +.align 2 +___ + +foreach (split("\n",$code)) { + s/\`([^\`]*)\`/eval $1/geo; + + if ($flavour =~ /le$/o) { # little-endian + s/le\?//o or + s/be\?/#be#/o; + } else { + s/le\?/#le#/o or + s/be\?//o; + } + print $_,"\n"; +} + +close STDOUT; # enforce flush diff --git a/src/crypto/modes/gcm.c b/src/crypto/modes/gcm.c index 1b43cd4b..69bdfdc2 100644 --- a/src/crypto/modes/gcm.c +++ b/src/crypto/modes/gcm.c @@ -60,7 +60,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 GHASH_ASM #endif @@ -145,7 +146,7 @@ static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { #endif } -#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) +#if !defined(GHASH_ASM) || defined(OPENSSL_AARCH64) || defined(OPENSSL_PPC64LE) static const size_t rem_4bit[16] = { PACK(0x0000), PACK(0x1C20), PACK(0x3840), PACK(0x2460), PACK(0x7080), PACK(0x6CA0), PACK(0x48C0), PACK(0x54E0), @@ -405,6 +406,13 @@ static void gcm_ghash_neon(uint64_t Xi[2], const u128 Htable[16], #endif #endif +#elif defined(OPENSSL_PPC64LE) +#define GHASH_ASM_PPC64LE +#define GCM_FUNCREF_4BIT +void gcm_init_p8(u128 Htable[16], const uint64_t Xi[2]); +void gcm_gmult_p8(uint64_t Xi[2], const u128 Htable[16]); +void gcm_ghash_p8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, + size_t len); #endif #endif @@ -484,6 +492,16 @@ void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key, ctx->gmult = gcm_gmult_4bit; ctx->ghash = gcm_ghash_4bit; } +#elif defined(GHASH_ASM_PPC64LE) + if (CRYPTO_is_PPC64LE_vcrypto_capable()) { + gcm_init_p8(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_p8; + ctx->ghash = gcm_ghash_p8; + } else { + gcm_init_4bit(ctx->Htable, ctx->H.u); + ctx->gmult = gcm_gmult_4bit; + ctx->ghash = gcm_ghash_4bit; + } #else gcm_init_4bit(ctx->Htable, ctx->H.u); ctx->gmult = gcm_gmult_4bit; diff --git a/src/crypto/perlasm/ppc-xlate.pl b/src/crypto/perlasm/ppc-xlate.pl new file mode 100644 index 00000000..55b02bca --- /dev/null +++ b/src/crypto/perlasm/ppc-xlate.pl @@ -0,0 +1,299 @@ +#! /usr/bin/env perl +# Copyright 2006-2016 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +my $flavour = shift; +my $output = shift; +open STDOUT,">$output" || die "can't open $output: $!"; + +my %GLOBALS; +my %TYPES; +my $dotinlocallabels=($flavour=~/linux/)?1:0; + +################################################################ +# directives which need special treatment on different platforms +################################################################ +my $type = sub { + my ($dir,$name,$type) = @_; + + $TYPES{$name} = $type; + if ($flavour =~ /linux/) { + $name =~ s|^\.||; + ".type $name,$type"; + } else { + ""; + } +}; +my $globl = sub { + my $junk = shift; + my $name = shift; + my $global = \$GLOBALS{$name}; + my $type = \$TYPES{$name}; + my $ret; + + $name =~ s|^\.||; + + SWITCH: for ($flavour) { + /aix/ && do { if (!$$type) { + $$type = "\@function"; + } + if ($$type =~ /function/) { + $name = ".$name"; + } + last; + }; + /osx/ && do { $name = "_$name"; + last; + }; + /linux.*(32|64le)/ + && do { $ret .= ".globl $name"; + if (!$$type) { + $ret .= "\n.type $name,\@function"; + $$type = "\@function"; + } + last; + }; + /linux.*64/ && do { $ret .= ".globl $name"; + if (!$$type) { + $ret .= "\n.type $name,\@function"; + $$type = "\@function"; + } + if ($$type =~ /function/) { + $ret .= "\n.section \".opd\",\"aw\""; + $ret .= "\n.align 3"; + $ret .= "\n$name:"; + $ret .= "\n.quad .$name,.TOC.\@tocbase,0"; + $ret .= "\n.previous"; + $name = ".$name"; + } + last; + }; + } + + $ret = ".globl $name" if (!$ret); + $$global = $name; + $ret; +}; +my $text = sub { + my $ret = ($flavour =~ /aix/) ? ".csect\t.text[PR],7" : ".text"; + $ret = ".abiversion 2\n".$ret if ($flavour =~ /linux.*64le/); + $ret; +}; +my $machine = sub { + my $junk = shift; + my $arch = shift; + if ($flavour =~ /osx/) + { $arch =~ s/\"//g; + $arch = ($flavour=~/64/) ? "ppc970-64" : "ppc970" if ($arch eq "any"); + } + ".machine $arch"; +}; +my $size = sub { + if ($flavour =~ /linux/) + { shift; + my $name = shift; + my $real = $GLOBALS{$name} ? \$GLOBALS{$name} : \$name; + my $ret = ".size $$real,.-$$real"; + $name =~ s|^\.||; + if ($$real ne $name) { + $ret .= "\n.size $name,.-$$real"; + } + $ret; + } + else + { ""; } +}; +my $asciz = sub { + shift; + my $line = join(",",@_); + if ($line =~ /^"(.*)"$/) + { ".byte " . join(",",unpack("C*",$1),0) . "\n.align 2"; } + else + { ""; } +}; +my $quad = sub { + shift; + my @ret; + my ($hi,$lo); + for (@_) { + if (/^0x([0-9a-f]*?)([0-9a-f]{1,8})$/io) + { $hi=$1?"0x$1":"0"; $lo="0x$2"; } + elsif (/^([0-9]+)$/o) + { $hi=$1>>32; $lo=$1&0xffffffff; } # error-prone with 32-bit perl + else + { $hi=undef; $lo=$_; } + + if (defined($hi)) + { push(@ret,$flavour=~/le$/o?".long\t$lo,$hi":".long\t$hi,$lo"); } + else + { push(@ret,".quad $lo"); } + } + join("\n",@ret); +}; + +################################################################ +# simplified mnemonics not handled by at least one assembler +################################################################ +my $cmplw = sub { + my $f = shift; + my $cr = 0; $cr = shift if ($#_>1); + # Some out-of-date 32-bit GNU assembler just can't handle cmplw... + ($flavour =~ /linux.*32/) ? + " .long ".sprintf "0x%x",31<<26|$cr<<23|$_[0]<<16|$_[1]<<11|64 : + " cmplw ".join(',',$cr,@_); +}; +my $bdnz = sub { + my $f = shift; + my $bo = $f=~/[\+\-]/ ? 16+9 : 16; # optional "to be taken" hint + " bc $bo,0,".shift; +} if ($flavour!~/linux/); +my $bltlr = sub { + my $f = shift; + my $bo = $f=~/\-/ ? 12+2 : 12; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%x",19<<26|$bo<<21|16<<1 : + " bclr $bo,0"; +}; +my $bnelr = sub { + my $f = shift; + my $bo = $f=~/\-/ ? 4+2 : 4; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%x",19<<26|$bo<<21|2<<16|16<<1 : + " bclr $bo,2"; +}; +my $beqlr = sub { + my $f = shift; + my $bo = $f=~/-/ ? 12+2 : 12; # optional "not to be taken" hint + ($flavour =~ /linux/) ? # GNU as doesn't allow most recent hints + " .long ".sprintf "0x%X",19<<26|$bo<<21|2<<16|16<<1 : + " bclr $bo,2"; +}; +# GNU assembler can't handle extrdi rA,rS,16,48, or when sum of last two +# arguments is 64, with "operand out of range" error. +my $extrdi = sub { + my ($f,$ra,$rs,$n,$b) = @_; + $b = ($b+$n)&63; $n = 64-$n; + " rldicl $ra,$rs,$b,$n"; +}; +my $vmr = sub { + my ($f,$vx,$vy) = @_; + " vor $vx,$vy,$vy"; +}; + +# Some ABIs specify vrsave, special-purpose register #256, as reserved +# for system use. +my $no_vrsave = ($flavour =~ /aix|linux64le/); +my $mtspr = sub { + my ($f,$idx,$ra) = @_; + if ($idx == 256 && $no_vrsave) { + " or $ra,$ra,$ra"; + } else { + " mtspr $idx,$ra"; + } +}; +my $mfspr = sub { + my ($f,$rd,$idx) = @_; + if ($idx == 256 && $no_vrsave) { + " li $rd,-1"; + } else { + " mfspr $rd,$idx"; + } +}; + +# PowerISA 2.06 stuff +sub vsxmem_op { + my ($f, $vrt, $ra, $rb, $op) = @_; + " .long ".sprintf "0x%X",(31<<26)|($vrt<<21)|($ra<<16)|($rb<<11)|($op*2+1); +} +# made-up unaligned memory reference AltiVec/VMX instructions +my $lvx_u = sub { vsxmem_op(@_, 844); }; # lxvd2x +my $stvx_u = sub { vsxmem_op(@_, 972); }; # stxvd2x +my $lvdx_u = sub { vsxmem_op(@_, 588); }; # lxsdx +my $stvdx_u = sub { vsxmem_op(@_, 716); }; # stxsdx +my $lvx_4w = sub { vsxmem_op(@_, 780); }; # lxvw4x +my $stvx_4w = sub { vsxmem_op(@_, 908); }; # stxvw4x + +# PowerISA 2.07 stuff +sub vcrypto_op { + my ($f, $vrt, $vra, $vrb, $op) = @_; + " .long ".sprintf "0x%X",(4<<26)|($vrt<<21)|($vra<<16)|($vrb<<11)|$op; +} +my $vcipher = sub { vcrypto_op(@_, 1288); }; +my $vcipherlast = sub { vcrypto_op(@_, 1289); }; +my $vncipher = sub { vcrypto_op(@_, 1352); }; +my $vncipherlast= sub { vcrypto_op(@_, 1353); }; +my $vsbox = sub { vcrypto_op(@_, 0, 1480); }; +my $vshasigmad = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1730); }; +my $vshasigmaw = sub { my ($st,$six)=splice(@_,-2); vcrypto_op(@_, $st<<4|$six, 1666); }; +my $vpmsumb = sub { vcrypto_op(@_, 1032); }; +my $vpmsumd = sub { vcrypto_op(@_, 1224); }; +my $vpmsubh = sub { vcrypto_op(@_, 1096); }; +my $vpmsumw = sub { vcrypto_op(@_, 1160); }; +my $vaddudm = sub { vcrypto_op(@_, 192); }; + +my $mtsle = sub { + my ($f, $arg) = @_; + " .long ".sprintf "0x%X",(31<<26)|($arg<<21)|(147*2); +}; + +# PowerISA 3.0 stuff +my $maddhdu = sub { + my ($f, $rt, $ra, $rb, $rc) = @_; + " .long ".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|49; +}; +my $maddld = sub { + my ($f, $rt, $ra, $rb, $rc) = @_; + " .long ".sprintf "0x%X",(4<<26)|($rt<<21)|($ra<<16)|($rb<<11)|($rc<<6)|51; +}; + +my $darn = sub { + my ($f, $rt, $l) = @_; + " .long ".sprintf "0x%X",(31<<26)|($rt<<21)|($l<<16)|(755<<1); +}; + +while($line=<>) { + + $line =~ s|[#!;].*$||; # get rid of asm-style comments... + $line =~ s|/\*.*\*/||; # ... and C-style comments... + $line =~ s|^\s+||; # ... and skip white spaces in beginning... + $line =~ s|\s+$||; # ... and at the end + + { + $line =~ s|\.L(\w+)|L$1|g; # common denominator for Locallabel + $line =~ s|\bL(\w+)|\.L$1|g if ($dotinlocallabels); + } + + { + $line =~ s|(^[\.\w]+)\:\s*||; + my $label = $1; + if ($label) { + my $xlated = ($GLOBALS{$label} or $label); + print "$xlated:"; + if ($flavour =~ /linux.*64le/) { + if ($TYPES{$label} =~ /function/) { + printf "\n.localentry %s,0\n",$xlated; + } + } + } + } + + { + $line =~ s|^\s*(\.?)(\w+)([\.\+\-]?)\s*||; + my $c = $1; $c = "\t" if ($c eq ""); + my $mnemonic = $2; + my $f = $3; + my $opcode = eval("\$$mnemonic"); + $line =~ s/\b(c?[rf]|v|vs)([0-9]+)\b/$2/g if ($c ne "." and $flavour !~ /osx/); + if (ref($opcode) eq 'CODE') { $line = &$opcode($f,split(',',$line)); } + elsif ($mnemonic) { $line = $c.$mnemonic.$f."\t".$line; } + } + + print $line if ($line); + print "\n"; +} + +close STDOUT; diff --git a/src/crypto/test/malloc.cc b/src/crypto/test/malloc.cc index 898f2a7c..47ee6da7 100644 --- a/src/crypto/test/malloc.cc +++ b/src/crypto/test/malloc.cc @@ -26,13 +26,9 @@ // This file isn't built on ARM or Aarch64 because we link statically in those // builds and trying to override malloc in a static link doesn't work. It also -// requires glibc. It's also disabled on ASan builds as this interferes with -// ASan's malloc interceptor. -// -// TODO(davidben): See if this and ASan's and MSan's interceptors can be made to -// coexist. +// requires glibc. #if defined(__linux__) && defined(OPENSSL_GLIBC) && !defined(OPENSSL_ARM) && \ - !defined(OPENSSL_AARCH64) && !defined(OPENSSL_ASAN) + !defined(OPENSSL_AARCH64) #include <errno.h> #include <signal.h> @@ -58,10 +54,24 @@ static char failure_enabled = 0, break_on_fail = 0; static int in_call = 0; extern "C" { + +#if defined(OPENSSL_ASAN) +#define REAL_MALLOC __interceptor_malloc +#define REAL_CALLOC __interceptor_calloc +#define REAL_REALLOC __interceptor_realloc +#define REAL_FREE __interceptor_free +#else +#define REAL_MALLOC __libc_malloc +#define REAL_CALLOC __libc_calloc +#define REAL_REALLOC __libc_realloc +#define REAL_FREE __libc_free +#endif + /* These are other names for the standard allocation functions. */ -extern void *__libc_malloc(size_t size); -extern void *__libc_calloc(size_t num_elems, size_t size); -extern void *__libc_realloc(void *ptr, size_t size); +extern void *REAL_MALLOC(size_t size); +extern void *REAL_CALLOC(size_t num_elems, size_t size); +extern void *REAL_REALLOC(void *ptr, size_t size); +extern void REAL_FREE(void *ptr); } static void exit_handler(void) { @@ -124,7 +134,7 @@ void *malloc(size_t size) { return NULL; } - return __libc_malloc(size); + return REAL_MALLOC(size); } void *calloc(size_t num_elems, size_t size) { @@ -133,7 +143,7 @@ void *calloc(size_t num_elems, size_t size) { return NULL; } - return __libc_calloc(num_elems, size); + return REAL_CALLOC(num_elems, size); } void *realloc(void *ptr, size_t size) { @@ -142,7 +152,11 @@ void *realloc(void *ptr, size_t size) { return NULL; } - return __libc_realloc(ptr, size); + return REAL_REALLOC(ptr, size); +} + +void free(void *ptr) { + REAL_FREE(ptr); } } // extern "C" diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index a62088d2..dc5af139 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -222,6 +222,94 @@ static const char kRSAKey[] = "-----END RSA PRIVATE KEY-----\n"; +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"; + +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"; + +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"; + +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"; + +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"; + // CertFromPEM parses the given, NUL-terminated pem block and returns an // |X509*|. static bssl::UniquePtr<X509> CertFromPEM(const char *pem) { @@ -230,6 +318,14 @@ static bssl::UniquePtr<X509> CertFromPEM(const char *pem) { PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)); } +// CRLFromPEM parses the given, NUL-terminated pem block and returns an +// |X509_CRL*|. +static bssl::UniquePtr<X509_CRL> CRLFromPEM(const char *pem) { + bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(pem, strlen(pem))); + return bssl::UniquePtr<X509_CRL>( + PEM_read_bio_X509_CRL(bio.get(), nullptr, nullptr, nullptr)); +} + // PrivateKeyFromPEM parses the given, NUL-terminated pem block and returns an // |EVP_PKEY*|. static bssl::UniquePtr<EVP_PKEY> PrivateKeyFromPEM(const char *pem) { @@ -256,34 +352,58 @@ static STACK_OF(X509)* CertsToStack(const std::vector<X509*> &certs) { return stack.release(); } -static bool Verify(X509 *leaf, const std::vector<X509 *> &roots, +// 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) { + bssl::UniquePtr<STACK_OF(X509_CRL)> stack(sk_X509_CRL_new_null()); + if (!stack) { + return nullptr; + } + for (auto crl : crls) { + if (!sk_X509_CRL_push(stack.get(), crl)) { + return nullptr; + } + X509_CRL_up_ref(crl); + } + + return stack.release(); +} + +static int Verify(X509 *leaf, const std::vector<X509 *> &roots, const std::vector<X509 *> &intermediates, + const std::vector<X509_CRL *> &crls, unsigned long flags = 0) { bssl::UniquePtr<STACK_OF(X509)> roots_stack(CertsToStack(roots)); bssl::UniquePtr<STACK_OF(X509)> intermediates_stack( CertsToStack(intermediates)); + bssl::UniquePtr<STACK_OF(X509_CRL)> crls_stack(CRLsToStack(crls)); if (!roots_stack || - !intermediates_stack) { - return false; + !intermediates_stack || + !crls_stack) { + return X509_V_ERR_UNSPECIFIED; } bssl::UniquePtr<X509_STORE_CTX> ctx(X509_STORE_CTX_new()); - if (!ctx) { - return false; + bssl::UniquePtr<X509_STORE> store(X509_STORE_new()); + if (!ctx || + !store) { + return X509_V_ERR_UNSPECIFIED; } - if (!X509_STORE_CTX_init(ctx.get(), nullptr /* no X509_STORE */, leaf, + + if (!X509_STORE_CTX_init(ctx.get(), store.get(), leaf, intermediates_stack.get())) { - return false; + return X509_V_ERR_UNSPECIFIED; } X509_STORE_CTX_trusted_stack(ctx.get(), roots_stack.get()); + X509_STORE_CTX_set0_crls(ctx.get(), crls_stack.get()); X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); if (param == nullptr) { - return false; + return X509_V_ERR_UNSPECIFIED; } - X509_VERIFY_PARAM_set_time(param, 1452807555 /* Jan 14th, 2016 */); + X509_VERIFY_PARAM_set_time(param, 1474934400 /* Sep 27th, 2016 */); X509_VERIFY_PARAM_set_depth(param, 16); if (flags) { X509_VERIFY_PARAM_set_flags(param, flags); @@ -291,7 +411,11 @@ static bool Verify(X509 *leaf, const std::vector<X509 *> &roots, X509_STORE_CTX_set0_param(ctx.get(), param); ERR_clear_error(); - return X509_verify_cert(ctx.get()) == 1; + if (X509_verify_cert(ctx.get()) != 1) { + return X509_STORE_CTX_get_error(ctx.get()); + } + + return X509_V_OK; } static bool TestVerify() { @@ -318,31 +442,37 @@ static bool TestVerify() { } std::vector<X509*> empty; - if (Verify(leaf.get(), empty, empty)) { + std::vector<X509_CRL*> empty_crls; + if (Verify(leaf.get(), empty, empty, empty_crls) != + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { fprintf(stderr, "Leaf verified with no roots!\n"); return false; } - if (Verify(leaf.get(), empty, {intermediate.get()})) { + if (Verify(leaf.get(), empty, {intermediate.get()}, empty_crls) != + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { fprintf(stderr, "Leaf verified with no roots!\n"); return false; } - if (!Verify(leaf.get(), {root.get()}, {intermediate.get()})) { + if (Verify(leaf.get(), {root.get()}, {intermediate.get()}, empty_crls) != + X509_V_OK) { ERR_print_errors_fp(stderr); fprintf(stderr, "Basic chain didn't verify.\n"); return false; } - if (!Verify(leaf.get(), {cross_signing_root.get()}, - {intermediate.get(), root_cross_signed.get()})) { + if (Verify(leaf.get(), {cross_signing_root.get()}, + {intermediate.get(), root_cross_signed.get()}, + empty_crls) != X509_V_OK) { ERR_print_errors_fp(stderr); fprintf(stderr, "Cross-signed chain didn't verify.\n"); return false; } - if (!Verify(leaf.get(), {cross_signing_root.get(), root.get()}, - {intermediate.get(), root_cross_signed.get()})) { + if (Verify(leaf.get(), {cross_signing_root.get(), root.get()}, + {intermediate.get(), root_cross_signed.get()}, + empty_crls) != X509_V_OK) { ERR_print_errors_fp(stderr); fprintf(stderr, "Cross-signed chain with root didn't verify.\n"); return false; @@ -350,22 +480,25 @@ static bool TestVerify() { /* This is the “altchains” test – we remove the cross-signing CA but include * the cross-sign in the intermediates. */ - if (!Verify(leaf.get(), {root.get()}, - {intermediate.get(), root_cross_signed.get()})) { + if (Verify(leaf.get(), {root.get()}, + {intermediate.get(), root_cross_signed.get()}, + empty_crls) != X509_V_OK) { ERR_print_errors_fp(stderr); fprintf(stderr, "Chain with cross-sign didn't backtrack to find root.\n"); return false; } if (Verify(leaf.get(), {root.get()}, - {intermediate.get(), root_cross_signed.get()}, - X509_V_FLAG_NO_ALT_CHAINS)) { + {intermediate.get(), root_cross_signed.get()}, empty_crls, + X509_V_FLAG_NO_ALT_CHAINS) != + X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) { fprintf(stderr, "Altchains test still passed when disabled.\n"); return false; } if (Verify(forgery.get(), {intermediate_self_signed.get()}, - {leaf_no_key_usage.get()})) { + {leaf_no_key_usage.get()}, + empty_crls) != X509_V_ERR_INVALID_CA) { fprintf(stderr, "Basic constraints weren't checked.\n"); return false; } @@ -374,7 +507,8 @@ static bool TestVerify() { * of roots and intermediates. This is a regression test for CVE-2015-1793. */ if (Verify(forgery.get(), {intermediate_self_signed.get(), root_cross_signed.get()}, - {leaf_no_key_usage.get(), intermediate.get()})) { + {leaf_no_key_usage.get(), intermediate.get()}, + empty_crls) != X509_V_ERR_INVALID_CA) { fprintf(stderr, "Basic constraints weren't checked.\n"); return false; } @@ -382,6 +516,51 @@ static bool TestVerify() { return true; } +static bool TestCRL() { + bssl::UniquePtr<X509> root(CertFromPEM(kCRLTestRoot)); + bssl::UniquePtr<X509> leaf(CertFromPEM(kCRLTestLeaf)); + 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)); + + if (!root || + !leaf || + !basic_crl || + !revoked_crl || + !bad_issuer_crl) { + fprintf(stderr, "Failed to parse certificates\n"); + return false; + } + + if (Verify(leaf.get(), {root.get()}, {root.get()}, {basic_crl.get()}, + X509_V_FLAG_CRL_CHECK) != X509_V_OK) { + fprintf(stderr, "Cert with CRL didn't verify.\n"); + return false; + } + + if (Verify(leaf.get(), {root.get()}, {root.get()}, + {basic_crl.get(), revoked_crl.get()}, + X509_V_FLAG_CRL_CHECK) != X509_V_ERR_CERT_REVOKED) { + fprintf(stderr, "Revoked CRL wasn't checked.\n"); + return false; + } + + std::vector<X509_CRL *> empty_crls; + if (Verify(leaf.get(), {root.get()}, {root.get()}, empty_crls, + X509_V_FLAG_CRL_CHECK) != X509_V_ERR_UNABLE_TO_GET_CRL) { + fprintf(stderr, "CRLs were not required.\n"); + return false; + } + + if (Verify(leaf.get(), {root.get()}, {root.get()}, {bad_issuer_crl.get()}, + X509_V_FLAG_CRL_CHECK) != X509_V_ERR_UNABLE_TO_GET_CRL) { + fprintf(stderr, "Bad CRL issuer was unnoticed.\n"); + return false; + } + + return true; +} + static bool TestPSS() { bssl::UniquePtr<X509> cert(CertFromPEM(kExamplePSSCert)); if (!cert) { @@ -464,6 +643,7 @@ static int Main() { CRYPTO_library_init(); if (!TestVerify() || + !TestCRL() || !TestPSS() || !TestBadPSSParameters() || !TestSignCtx()) { diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c index 8d51703c..fa6a5c51 100644 --- a/src/crypto/x509/x509_vfy.c +++ b/src/crypto/x509/x509_vfy.c @@ -1001,10 +1001,10 @@ static int get_crl_sk(X509_STORE_CTX *ctx, X509_CRL **pcrl, X509_CRL **pdcrl, crl = sk_X509_CRL_value(crls, i); reasons = *preasons; crl_score = get_crl_score(ctx, &crl_issuer, &reasons, crl, x); - if (crl_score < best_score) + if (crl_score < best_score || crl_score == 0) continue; /* If current CRL is equivalent use it if it is newer */ - if (crl_score == best_score) { + if (crl_score == best_score && best_crl != NULL) { int day, sec; if (ASN1_TIME_diff(&day, &sec, X509_CRL_get_lastUpdate(best_crl), X509_CRL_get_lastUpdate(crl)) == 0) diff --git a/src/crypto/x509/x509_vpm.c b/src/crypto/x509/x509_vpm.c index b51bc176..9e9dbf5e 100644 --- a/src/crypto/x509/x509_vpm.c +++ b/src/crypto/x509/x509_vpm.c @@ -192,25 +192,36 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param) OPENSSL_free(param); } -/* +/*- * This function determines how parameters are "inherited" from one structure - * to another. There are several different ways this can happen. 1. If a - * child structure needs to have its values initialized from a parent they are - * simply copied across. For example SSL_CTX copied to SSL. 2. If the - * structure should take on values only if they are currently unset. For - * example the values in an SSL structure will take appropriate value for SSL - * servers or clients but only if the application has not set new ones. The - * "inh_flags" field determines how this function behaves. Normally any - * values which are set in the default are not copied from the destination and - * verify flags are ORed together. If X509_VP_FLAG_DEFAULT is set then - * anything set in the source is copied to the destination. Effectively the - * values in "to" become default values which will be used only if nothing new - * is set in "from". If X509_VP_FLAG_OVERWRITE is set then all value are - * copied across whether they are set or not. Flags is still Ored though. If - * X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead of - * ORed. If X509_VP_FLAG_LOCKED is set then no values are copied. If - * X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed after - * the next call. + * to another. There are several different ways this can happen. + * + * 1. If a child structure needs to have its values initialized from a parent + * they are simply copied across. For example SSL_CTX copied to SSL. + * 2. If the structure should take on values only if they are currently unset. + * For example the values in an SSL structure will take appropriate value + * for SSL servers or clients but only if the application has not set new + * ones. + * + * The "inh_flags" field determines how this function behaves. + * + * Normally any values which are set in the default are not copied from the + * destination and verify flags are ORed together. + * + * If X509_VP_FLAG_DEFAULT is set then anything set in the source is copied + * to the destination. Effectively the values in "to" become default values + * which will be used only if nothing new is set in "from". + * + * If X509_VP_FLAG_OVERWRITE is set then all value are copied across whether + * they are set or not. Flags is still Ored though. + * + * If X509_VP_FLAG_RESET_FLAGS is set then the flags value is copied instead + * of ORed. + * + * If X509_VP_FLAG_LOCKED is set then no values are copied. + * + * If X509_VP_FLAG_ONCE is set then the current inh_flags setting is zeroed + * after the next call. */ /* Macro to test if a field should be copied from src to dest */ diff --git a/src/crypto/x509/x_crl.c b/src/crypto/x509/x_crl.c index 934571dd..89cd5d14 100644 --- a/src/crypto/x509/x_crl.c +++ b/src/crypto/x509/x_crl.c @@ -299,7 +299,9 @@ static int crl_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, break; case ASN1_OP_FREE_POST: - if (crl->meth->crl_free) { + /* |crl->meth| may be NULL if constructing the object failed before + * |ASN1_OP_NEW_POST| was run. */ + if (crl->meth && crl->meth->crl_free) { if (!crl->meth->crl_free(crl)) return 0; } diff --git a/src/decrepit/ssl/ssl_decrepit.c b/src/decrepit/ssl/ssl_decrepit.c index e25cbf31..12a03da4 100644 --- a/src/decrepit/ssl/ssl_decrepit.c +++ b/src/decrepit/ssl/ssl_decrepit.c @@ -114,111 +114,51 @@ #include <dirent.h> #include <errno.h> -#include <stdlib.h> #include <string.h> #include <openssl/err.h> #include <openssl/mem.h> -typedef struct { - DIR *dir; - struct dirent dirent; -} OPENSSL_DIR_CTX; - -static const char *OPENSSL_DIR_read(OPENSSL_DIR_CTX **ctx, - const char *directory) { - struct dirent *dirent; - - if (ctx == NULL || directory == NULL) { - errno = EINVAL; - return NULL; - } - - errno = 0; - if (*ctx == NULL) { - *ctx = malloc(sizeof(OPENSSL_DIR_CTX)); - if (*ctx == NULL) { - errno = ENOMEM; - return 0; - } - memset(*ctx, 0, sizeof(OPENSSL_DIR_CTX)); - - (*ctx)->dir = opendir(directory); - if ((*ctx)->dir == NULL) { - int save_errno = errno; /* Probably not needed, but I'm paranoid */ - free(*ctx); - *ctx = NULL; - errno = save_errno; - return 0; - } - } - - if (readdir_r((*ctx)->dir, &(*ctx)->dirent, &dirent) != 0 || - dirent == NULL) { +int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *path) { + DIR *dir = opendir(path); + if (dir == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); + ERR_add_error_data(3, "opendir('", dir, "')"); return 0; } - return (*ctx)->dirent.d_name; -} - -static int OPENSSL_DIR_end(OPENSSL_DIR_CTX **ctx) { - if (ctx != NULL && *ctx != NULL) { - int r = closedir((*ctx)->dir); - free(*ctx); - *ctx = NULL; - return r == 0; - } - - errno = EINVAL; - return 0; -} - - -/* Add a directory of certs to a stack. - * - * \param stack the stack to append to. - * \param dir the directory to append from. All files in this directory will be - * examined as potential certs. Any that are acceptable to - * SSL_add_dir_cert_subjects_to_stack() that are not already in the stack will - * be included. - * \return 1 for success, 0 for failure. Note that in the case of failure some - * certs may have been added to \c stack. */ -int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, - const char *dir) { - OPENSSL_DIR_CTX *d = NULL; - const char *filename; int ret = 0; + for (;;) { + /* |readdir| may fail with or without setting |errno|. */ + errno = 0; + struct dirent *dirent = readdir(dir); + if (dirent == NULL) { + if (errno) { + OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); + ERR_add_error_data(3, "readdir('", path, "')"); + } else { + ret = 1; + } + break; + } - /* Note that a side effect is that the CAs will be sorted by name */ - while ((filename = OPENSSL_DIR_read(&d, dir))) { char buf[1024]; - int r; - - if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) { + if (strlen(path) + strlen(dirent->d_name) + 2 > sizeof(buf)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PATH_TOO_LONG); - goto err; + break; } - r = BIO_snprintf(buf, sizeof buf, "%s/%s", dir, filename); - if (r <= 0 || r >= (int)sizeof(buf) || + int r = BIO_snprintf(buf, sizeof(buf), "%s/%s", path, dirent->d_name); + if (r <= 0 || + r >= (int)sizeof(buf) || !SSL_add_file_cert_subjects_to_stack(stack, buf)) { - goto err; + break; } } - if (errno) { - OPENSSL_PUT_ERROR(SSL, ERR_R_SYS_LIB); - ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); - goto err; - } - - ret = 1; - -err: - if (d) { - OPENSSL_DIR_end(&d); - } + closedir(dir); return ret; } diff --git a/src/include/openssl/aead.h b/src/include/openssl/aead.h index af81fa65..fff0e496 100644 --- a/src/include/openssl/aead.h +++ b/src/include/openssl/aead.h @@ -105,20 +105,6 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305(void); * suites. */ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_chacha20_poly1305_old(void); -/* EVP_aead_aes_128_key_wrap is AES-128 Key Wrap mode. This should never be - * used except to interoperate with existing systems that use this mode. - * - * If the nonce is empty then the default nonce will be used, otherwise it must - * be eight bytes long. The input must be a multiple of eight bytes long. No - * additional data can be given to this mode. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_key_wrap(void); - -/* EVP_aead_aes_256_key_wrap is AES-256 in Key Wrap mode. This should never be - * used except to interoperate with existing systems that use this mode. - * - * See |EVP_aead_aes_128_key_wrap| for details. */ -OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_key_wrap(void); - /* EVP_aead_aes_128_ctr_hmac_sha256 is AES-128 in CTR mode with HMAC-SHA256 for * authentication. The nonce is 12 bytes; the bottom 32-bits are used as the * block counter, thus the maximum plaintext size is 64GB. */ diff --git a/src/include/openssl/aes.h b/src/include/openssl/aes.h index ed060ff6..2aef9182 100644 --- a/src/include/openssl/aes.h +++ b/src/include/openssl/aes.h @@ -139,16 +139,28 @@ OPENSSL_EXPORT void AES_cfb128_encrypt(const uint8_t *in, uint8_t *out, uint8_t *ivec, int *num, int enc); -/* Android compatibility section. +/* AES key wrap. * - * These functions are declared, temporarily, for Android because - * wpa_supplicant will take a little time to sync with upstream. Outside of - * Android they'll have no definition. */ - -OPENSSL_EXPORT int AES_wrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, - const uint8_t *in, unsigned in_len); -OPENSSL_EXPORT int AES_unwrap_key(AES_KEY *key, const uint8_t *iv, uint8_t *out, - const uint8_t *in, unsigned in_len); + * These functions implement AES Key Wrap mode, as defined in RFC 3394. They + * should never be used except to interoperate with existing systems that use + * this mode. */ + +/* AES_wrap_key performs AES key wrap on |in| which must be a multiple of 8 + * bytes. |iv| must point to an 8 byte value or be NULL to use the default IV. + * |key| must have been configured for encryption. On success, it writes + * |in_len| + 8 bytes to |out| and returns |in_len| + 8. Otherwise, it returns + * -1. */ +OPENSSL_EXPORT int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, + uint8_t *out, const uint8_t *in, size_t in_len); + +/* AES_unwrap_key performs AES key unwrap on |in| which must be a multiple of 8 + * bytes. |iv| must point to an 8 byte value or be NULL to use the default IV. + * |key| must have been configured for decryption. On success, it writes + * |in_len| - 8 bytes to |out| and returns |in_len| - 8. Otherwise, it returns + * -1. */ +OPENSSL_EXPORT int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, + uint8_t *out, const uint8_t *in, + size_t in_len); #if defined(__cplusplus) diff --git a/src/include/openssl/base.h b/src/include/openssl/base.h index fab293ea..888b594a 100644 --- a/src/include/openssl/base.h +++ b/src/include/openssl/base.h @@ -83,8 +83,9 @@ extern "C" { #elif defined(__arm) || defined(__arm__) || defined(_M_ARM) #define OPENSSL_32_BIT #define OPENSSL_ARM -#elif defined(__PPC64__) || defined(__powerpc64__) +#elif (defined(__PPC64__) || defined(__powerpc64__)) && defined(_LITTLE_ENDIAN) #define OPENSSL_64_BIT +#define OPENSSL_PPC64LE #elif defined(__mips__) && !defined(__LP64__) #define OPENSSL_32_BIT #define OPENSSL_MIPS @@ -116,7 +117,7 @@ extern "C" { #define OPENSSL_IS_BORINGSSL #define BORINGSSL_201512 #define BORINGSSL_201603 -#define OPENSSL_VERSION_NUMBER 0x10002000 +#define OPENSSL_VERSION_NUMBER 0x100020af #define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER /* BORINGSSL_API_VERSION is a positive integer that increments as BoringSSL @@ -360,6 +361,9 @@ class StackAllocated { StackAllocated() { init(&ctx_); } ~StackAllocated() { cleanup(&ctx_); } + StackAllocated(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete; + T& operator=(const StackAllocated<T, CleanupRet, init, cleanup> &) = delete; + T *get() { return &ctx_; } const T *get() const { return &ctx_; } diff --git a/src/include/openssl/bytestring.h b/src/include/openssl/bytestring.h index 2985268e..a873956c 100644 --- a/src/include/openssl/bytestring.h +++ b/src/include/openssl/bytestring.h @@ -190,6 +190,14 @@ OPENSSL_EXPORT int CBS_get_asn1_element(CBS *cbs, CBS *out, unsigned tag_value); * element is malformed. */ OPENSSL_EXPORT int CBS_peek_asn1_tag(const CBS *cbs, unsigned tag_value); +/* CBS_get_any_asn1 sets |*out| to contain the next ASN.1 element from |*cbs| + * (not including tag and length bytes), sets |*out_tag| to the tag number, and + * advances |*cbs|. It returns one on success and zero on error. Either of |out| + * and |out_tag| may be NULL to ignore the value. + * + * Tag numbers greater than 30 are not supported (i.e. short form only). */ +OPENSSL_EXPORT int CBS_get_any_asn1(CBS *cbs, CBS *out, unsigned *out_tag); + /* CBS_get_any_asn1_element sets |*out| to contain the next ASN.1 element from * |*cbs| (including header bytes) and advances |*cbs|. It sets |*out_tag| to * the tag number and |*out_header_len| to the length of the ASN.1 header. Each @@ -327,8 +335,10 @@ OPENSSL_EXPORT void CBB_cleanup(CBB *cbb); OPENSSL_EXPORT int CBB_finish(CBB *cbb, uint8_t **out_data, size_t *out_len); /* CBB_flush causes any pending length prefixes to be written out and any child - * |CBB| objects of |cbb| to be invalidated. It returns one on success or zero - * on error. */ + * |CBB| objects of |cbb| to be invalidated. This allows |cbb| to continue to be + * used after the children go out of scope, e.g. when local |CBB| objects are + * added as children to a |CBB| that persists after a function returns. This + * function returns one on success or zero on error. */ OPENSSL_EXPORT int CBB_flush(CBB *cbb); /* CBB_data returns a pointer to the bytes written to |cbb|. It does not flush diff --git a/src/include/openssl/cpu.h b/src/include/openssl/cpu.h index 55be4c1f..457a4768 100644 --- a/src/include/openssl/cpu.h +++ b/src/include/openssl/cpu.h @@ -165,6 +165,14 @@ static inline int CRYPTO_is_ARMv8_PMULL_capable(void) { #endif /* OPENSSL_STATIC_ARMCAP */ #endif /* OPENSSL_ARM || OPENSSL_AARCH64 */ +#if defined(OPENSSL_PPC64LE) + +/* CRYPTO_is_PPC64LE_vcrypto_capable returns true iff the current CPU supports + * the Vector.AES category of instructions. */ +int CRYPTO_is_PPC64LE_vcrypto_capable(void); + +#endif /* OPENSSL_PPC64LE */ + #if defined(__cplusplus) } /* extern C */ diff --git a/src/include/openssl/ec.h b/src/include/openssl/ec.h index c2ef0665..e780347b 100644 --- a/src/include/openssl/ec.h +++ b/src/include/openssl/ec.h @@ -86,7 +86,7 @@ typedef enum { * is. */ POINT_CONVERSION_COMPRESSED = 2, - /* POINT_CONVERSION_COMPRESSED indicates that the point is encoded as + /* POINT_CONVERSION_UNCOMPRESSED indicates that the point is encoded as * z||x||y, where z is the octet 0x04. */ POINT_CONVERSION_UNCOMPRESSED = 4, diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 8454c307..88fe845e 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 14 +#define TLS1_3_DRAFT_VERSION 0x7f0f /* 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 @@ -1197,7 +1197,8 @@ OPENSSL_EXPORT uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher); OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *cipher); /* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange - * method used by |cipher|. For example, "ECDHE_ECDSA". */ + * method used by |cipher|. For example, "ECDHE_ECDSA". TLS 1.3 AEAD-only + * ciphers return the string "GENERIC". */ OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher); /* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard @@ -1934,6 +1935,18 @@ OPENSSL_EXPORT int SSL_CTX_set1_curves(SSL_CTX *ctx, const int *curves, OPENSSL_EXPORT int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len); +/* SSL_CTX_set1_curves_list sets the preferred curves for |ctx| to be the + * colon-separated list |curves|. Each element of |curves| should be a curve + * name (e.g. P-256, X25519, ...). It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves); + +/* SSL_set1_curves_list sets the preferred curves for |ssl| to be the + * colon-separated list |curves|. Each element of |curves| should be a curve + * name (e.g. P-256, X25519, ...). It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); + /* SSL_CURVE_* define TLS curve IDs. */ #define SSL_CURVE_SECP256R1 23 #define SSL_CURVE_SECP384R1 24 @@ -3101,6 +3114,10 @@ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl); OPENSSL_EXPORT void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enable); +/* SSL_CTX_set_grease_enabled configures whether client sockets on |ctx| should + * enable GREASE. See draft-davidben-tls-grease-01. */ +OPENSSL_EXPORT void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled); + /* Deprecated functions. */ @@ -3137,6 +3154,9 @@ OPENSSL_EXPORT int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); /* SSL_COMP_get_name returns NULL. */ OPENSSL_EXPORT const char *SSL_COMP_get_name(const COMP_METHOD *comp); +/* SSL_COMP_free_compression_methods does nothing. */ +OPENSSL_EXPORT void SSL_COMP_free_compression_methods(void); + /* SSLv23_method calls |TLS_method|. */ OPENSSL_EXPORT const SSL_METHOD *SSLv23_method(void); @@ -3696,7 +3716,6 @@ struct ssl_session_st { uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ - uint32_t ticket_flags; uint32_t ticket_age_add; /* extended_master_secret is true if the master secret in this session was @@ -3992,11 +4011,15 @@ struct ssl_ctx_st { /* If true, a client will request certificate timestamps. */ unsigned signed_cert_timestamps_enabled:1; - /* tlsext_channel_id_enabled is copied from the |SSL_CTX|. For a server, - * means that we'll accept Channel IDs from clients. For a client, means that - * we'll advertise support. */ + /* tlsext_channel_id_enabled is one if Channel ID is enabled and zero + * otherwise. For a server, means that we'll accept Channel IDs from clients. + * For a client, means that we'll advertise support. */ unsigned tlsext_channel_id_enabled:1; + /* grease_enabled is one if draft-davidben-tls-grease-01 is enabled and zero + * otherwise. */ + unsigned grease_enabled:1; + /* extra_certs is a dummy value included for compatibility. * TODO(agl): remove once node.js no longer references this. */ STACK_OF(X509)* extra_certs; @@ -4506,6 +4529,7 @@ typedef struct ssl3_state_st { #define SSL_CTRL_SESS_NUMBER doesnt_exist #define SSL_CTRL_SET_CHANNEL_ID doesnt_exist #define SSL_CTRL_SET_CURVES doesnt_exist +#define SSL_CTRL_SET_CURVES_LIST doesnt_exist #define SSL_CTRL_SET_MAX_CERT_LIST doesnt_exist #define SSL_CTRL_SET_MAX_SEND_FRAGMENT doesnt_exist #define SSL_CTRL_SET_MSG_CALLBACK doesnt_exist @@ -4784,6 +4808,7 @@ BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free) #define SSL_R_RENEGOTIATION_EMS_MISMATCH 263 #define SSL_R_DUPLICATE_KEY_SHARE 264 #define SSL_R_NO_GROUPS_SPECIFIED 265 +#define SSL_R_NO_SHARED_GROUP 266 #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/tls1.h b/src/include/openssl/tls1.h index 3c97d26a..c1db7abc 100644 --- a/src/include/openssl/tls1.h +++ b/src/include/openssl/tls1.h @@ -209,16 +209,9 @@ extern "C" { #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 -/* TLSEXT_TYPE_draft_version is the extension used to advertise the TLS 1.3 - * draft implemented. - * - * See - * https://github.com/tlswg/tls13-spec/wiki/Implementations#version-negotiation - */ -#define TLSEXT_TYPE_draft_version 0xff02 - /* ExtensionType value from RFC5746 */ #define TLSEXT_TYPE_renegotiate 0xff01 @@ -420,15 +413,16 @@ extern "C" { #define TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x0300CCA9 #define TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0x0300CCAC -/* PSK ciphersuites from mattsson-tls-ecdhe-psk-aead */ -#define TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 0x0300D001 -#define TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384 0x0300D002 - /* TODO(davidben): Remove this. Historically, the CK names for CHACHA20_POLY1305 * were missing 'WITH' and 'SHA256'. */ #define TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305 \ TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 +/* TLS 1.3 ciphersuites from draft-ietf-tls-tls13-15 */ +#define TLS1_CK_AES_128_GCM_SHA256 0x03001301 +#define TLS1_CK_AES_256_GCM_SHA384 0x03001302 +#define TLS1_CK_CHACHA20_POLY1305_SHA256 0x03001303 + /* CECPQ1 ciphersuites. These are specific to BoringSSL and not standard. */ #define TLS1_CK_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 0x030016B7 #define TLS1_CK_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0x030016B8 @@ -615,9 +609,10 @@ extern "C" { #define TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305 \ TLS1_TXT_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 -/* PSK ciphersuites from mattsson-tls-ecdhe-psk-aead */ -#define TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256 "ECDHE-PSK-AES128-GCM-SHA256" -#define TLS1_TXT_ECDHE_PSK_WITH_AES_256_GCM_SHA384 "ECDHE-PSK-AES256-GCM-SHA384" +/* TLS 1.3 ciphersuites from draft-ietf-tls-tls13-15 */ +#define TLS1_TXT_AES_128_GCM_SHA256 "AEAD-AES128-GCM-SHA256" +#define TLS1_TXT_AES_256_GCM_SHA384 "AEAD-AES256-GCM-SHA384" +#define TLS1_TXT_CHACHA20_POLY1305_SHA256 "AEAD-CHACHA20-POLY1305-SHA256" /* CECPQ1 ciphersuites. These are specific to BoringSSL and not standard. */ #define TLS1_TXT_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 \ diff --git a/src/include/openssl/x509.h b/src/include/openssl/x509.h index 667e8947..51be3201 100644 --- a/src/include/openssl/x509.h +++ b/src/include/openssl/x509.h @@ -1234,6 +1234,7 @@ BORINGSSL_MAKE_STACK_DELETER(X509_CRL, X509_CRL_free) BORINGSSL_MAKE_STACK_DELETER(X509_EXTENSION, X509_EXTENSION_free) BORINGSSL_MAKE_STACK_DELETER(X509_NAME, X509_NAME_free) +BORINGSSL_MAKE_DELETER(NETSCAPE_SPKI, NETSCAPE_SPKI_free) BORINGSSL_MAKE_DELETER(X509, X509_free) BORINGSSL_MAKE_DELETER(X509_ALGOR, X509_ALGOR_free) BORINGSSL_MAKE_DELETER(X509_CRL, X509_CRL_free) diff --git a/src/include/openssl/x509v3.h b/src/include/openssl/x509v3.h index c39cf1b0..d25a1254 100644 --- a/src/include/openssl/x509v3.h +++ b/src/include/openssl/x509v3.h @@ -737,8 +737,14 @@ extern "C++" { namespace bssl { +BORINGSSL_MAKE_STACK_DELETER(DIST_POINT, DIST_POINT_free) BORINGSSL_MAKE_STACK_DELETER(GENERAL_NAME, GENERAL_NAME_free) +// A STACK_OF(POLICYINFO) is also known as a CERTIFICATEPOLICIES. +BORINGSSL_MAKE_STACK_DELETER(POLICYINFO, POLICYINFO_free) +BORINGSSL_MAKE_DELETER(AUTHORITY_KEYID, AUTHORITY_KEYID_free) +BORINGSSL_MAKE_DELETER(BASIC_CONSTRAINTS, BASIC_CONSTRAINTS_free) +BORINGSSL_MAKE_DELETER(DIST_POINT, DIST_POINT_free) BORINGSSL_MAKE_DELETER(GENERAL_NAME, GENERAL_NAME_free) } // namespace bssl diff --git a/src/ssl/d1_srtp.c b/src/ssl/d1_srtp.c index 324bff77..10853777 100644 --- a/src/ssl/d1_srtp.c +++ b/src/ssl/d1_srtp.c @@ -160,27 +160,27 @@ static int find_profile_by_name(const char *profile_name, static int ssl_ctx_make_profiles(const char *profiles_string, STACK_OF(SRTP_PROTECTION_PROFILE) **out) { - STACK_OF(SRTP_PROTECTION_PROFILE) *profiles; - - const char *col; - const char *ptr = profiles_string; - - profiles = sk_SRTP_PROTECTION_PROFILE_new_null(); + STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = + sk_SRTP_PROTECTION_PROFILE_new_null(); if (profiles == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES); return 0; } + const char *col; + const char *ptr = profiles_string; do { - const SRTP_PROTECTION_PROFILE *p; - col = strchr(ptr, ':'); - if (find_profile_by_name(ptr, &p, - col ? (size_t)(col - ptr) : strlen(ptr))) { - sk_SRTP_PROTECTION_PROFILE_push(profiles, p); - } else { + + const SRTP_PROTECTION_PROFILE *profile; + if (!find_profile_by_name(ptr, &profile, + col ? (size_t)(col - ptr) : strlen(ptr))) { OPENSSL_PUT_ERROR(SSL, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE); - return 0; + goto err; + } + + if (!sk_SRTP_PROTECTION_PROFILE_push(profiles, profile)) { + goto err; } if (col) { @@ -190,8 +190,11 @@ static int ssl_ctx_make_profiles(const char *profiles_string, sk_SRTP_PROTECTION_PROFILE_free(*out); *out = profiles; - return 1; + +err: + sk_SRTP_PROTECTION_PROFILE_free(profiles); + return 0; } int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) { diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c index d78d0a4f..31394c0a 100644 --- a/src/ssl/handshake_client.c +++ b/src/ssl/handshake_client.c @@ -579,6 +579,18 @@ end: return ret; } +uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index) { + /* Use the client_random for entropy. This both avoids calling |RAND_bytes| on + * a single byte repeatedly and ensures the values are deterministic. This + * allows the same ClientHello be sent twice for a HelloRetryRequest or the + * same group be advertised in both supported_groups and key_shares. */ + uint16_t ret = ssl->s3->client_random[index]; + /* This generates a random value of the form 0xωaωa, for all 0 ≤ ω < 16. */ + ret = (ret & 0xf0) | 0x0a; + ret |= ret << 8; + return ret; +} + static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, uint16_t min_version, uint16_t max_version) { @@ -590,6 +602,12 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, return 0; } + /* Add a fake cipher suite. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&child, ssl_get_grease_value(ssl, ssl_grease_cipher))) { + return 0; + } + STACK_OF(SSL_CIPHER) *ciphers = SSL_get_ciphers(ssl); int any_enabled = 0; @@ -608,18 +626,6 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, if (!CBB_add_u16(&child, ssl_cipher_get_value(cipher))) { return 0; } - /* Add PSK ciphers for TLS 1.3 resumption. */ - uint16_t session_version; - if (ssl->session != NULL && - ssl->method->version_from_wire(&session_version, - ssl->session->ssl_version) && - session_version >= TLS1_3_VERSION) { - uint16_t resumption_cipher; - if (ssl_cipher_get_ecdhe_psk_cipher(cipher, &resumption_cipher) && - !CBB_add_u16(&child, resumption_cipher)) { - return 0; - } - } } /* If all ciphers were disabled, return the error to the caller. */ @@ -713,6 +719,10 @@ static int ssl3_send_client_hello(SSL *ssl) { * key exchange, the ClientHello version is checked in the premaster secret. * Some servers fail when this value changes. */ ssl->client_version = ssl->version; + + if (max_version >= TLS1_3_VERSION) { + ssl->client_version = ssl->method->version_to_wire(TLS1_2_VERSION); + } } /* If the configured session has expired or was created at a disabled @@ -930,14 +940,14 @@ static int ssl3_get_server_hello(SSL *ssl) { } if (ssl->session != NULL) { - if (ssl->session->cipher != c) { + if (ssl->session->ssl_version != ssl->version) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); goto f_err; } - if (ssl->session->ssl_version != ssl->version) { + if (ssl->session->cipher != c) { al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_VERSION_NOT_RETURNED); + OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); goto f_err; } if (!ssl_session_is_context_valid(ssl, ssl->session)) { diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c index d57735a9..fd0223f6 100644 --- a/src/ssl/handshake_server.c +++ b/src/ssl/handshake_server.c @@ -564,38 +564,75 @@ static int negotiate_version( return 0; } - /* For TLS versions which use ClientHello.version, convert it to a version we - * are aware of. */ uint16_t version = 0; - if (SSL_is_dtls(ssl)) { - if (client_hello->version <= DTLS1_2_VERSION) { - version = TLS1_2_VERSION; - } else if (client_hello->version <= DTLS1_VERSION) { - version = TLS1_1_VERSION; + /* Check supported_versions extension if it is present. */ + CBS supported_versions; + if (ssl_early_callback_get_extension(client_hello, &supported_versions, + TLSEXT_TYPE_supported_versions)) { + CBS versions; + if (!CBS_get_u8_length_prefixed(&supported_versions, &versions) || + CBS_len(&supported_versions) != 0 || + CBS_len(&versions) == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + int found_version = 0; + while (CBS_len(&versions) != 0) { + uint16_t ext_version; + if (!CBS_get_u16(&versions, &ext_version)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + if (!ssl->method->version_from_wire(&ext_version, ext_version)) { + continue; + } + if (min_version <= ext_version && + ext_version <= max_version) { + version = ext_version; + found_version = 1; + break; + } + } + + if (!found_version) { + goto unsupported_protocol; } } else { - if (client_hello->version >= TLS1_3_VERSION) { - version = TLS1_3_VERSION; - } else if (client_hello->version >= TLS1_2_VERSION) { - version = TLS1_2_VERSION; - } else if (client_hello->version >= TLS1_1_VERSION) { - version = TLS1_1_VERSION; - } else if (client_hello->version >= TLS1_VERSION) { - version = TLS1_VERSION; - } else if (client_hello->version >= SSL3_VERSION) { - version = SSL3_VERSION; + /* Process ClientHello.version instead. Note that versions beyond (D)TLS 1.2 + * do not use this mechanism. */ + if (SSL_is_dtls(ssl)) { + if (client_hello->version <= DTLS1_2_VERSION) { + version = TLS1_2_VERSION; + } else if (client_hello->version <= DTLS1_VERSION) { + version = TLS1_1_VERSION; + } else { + goto unsupported_protocol; + } + } else { + if (client_hello->version >= TLS1_2_VERSION) { + version = TLS1_2_VERSION; + } else if (client_hello->version >= TLS1_1_VERSION) { + version = TLS1_1_VERSION; + } else if (client_hello->version >= TLS1_VERSION) { + version = TLS1_VERSION; + } else if (client_hello->version >= SSL3_VERSION) { + version = SSL3_VERSION; + } else { + goto unsupported_protocol; + } } - } - /* Apply our minimum and maximum version. */ - if (version > max_version) { - version = max_version; - } + /* Apply our minimum and maximum version. */ + if (version > max_version) { + version = max_version; + } - if (version < min_version) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); - *out_alert = SSL_AD_PROTOCOL_VERSION; - return 0; + if (version < min_version) { + goto unsupported_protocol; + } } /* Handle FALLBACK_SCSV. */ @@ -617,6 +654,11 @@ static int negotiate_version( ssl->s3->have_version = 1; return 1; + +unsupported_protocol: + OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL); + *out_alert = SSL_AD_PROTOCOL_VERSION; + return 0; } static int ssl3_get_client_hello(SSL *ssl) { @@ -1839,8 +1881,13 @@ static int ssl3_get_channel_id(SSL *ssl) { /* We stored the handshake hash in |tlsext_channel_id| the first time that we * were called. */ - if (!ECDSA_do_verify(channel_id_hash, channel_id_hash_len, &sig, key)) { + 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; } diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 232364ee..3e7c053e 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -172,12 +172,14 @@ extern "C" { /* SSL_kPSK is only set for plain PSK, not ECDHE_PSK. */ #define SSL_kPSK 0x00000008L #define SSL_kCECPQ1 0x00000010L +#define SSL_kGENERIC 0x00000020L /* Bits for |algorithm_auth| (server authentication). */ #define SSL_aRSA 0x00000001L #define SSL_aECDSA 0x00000002L /* SSL_aPSK is set for both PSK and ECDHE_PSK. */ #define SSL_aPSK 0x00000004L +#define SSL_aGENERIC 0x00000008L #define SSL_aCERT (SSL_aRSA | SSL_aECDSA) @@ -241,11 +243,6 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, /* ssl_cipher_get_value returns the cipher suite id of |cipher|. */ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher); -/* ssl_cipher_get_resumption_cipher returns the cipher suite id of the cipher - * matching |cipher| with PSK enabled. */ -int ssl_cipher_get_ecdhe_psk_cipher(const SSL_CIPHER *cipher, - uint16_t *out_cipher); - /* ssl_cipher_get_key_type returns the |EVP_PKEY_*| value corresponding to the * server key used in |cipher| or |EVP_PKEY_NONE| if there is none. */ int ssl_cipher_get_key_type(const SSL_CIPHER *cipher); @@ -609,6 +606,11 @@ struct ssl_ecdh_method_st { * zero. */ int ssl_nid_to_group_id(uint16_t *out_group_id, int nid); +/* ssl_name_to_group_id looks up the group corresponding to the |name| string + * of length |len|. On success, it sets |*out_group_id| to the group ID and + * returns one. Otherwise, it returns zero. */ +int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len); + /* SSL_ECDH_CTX_init sets up |ctx| for use with curve |group_id|. It returns one * on success and zero on error. */ int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id); @@ -1014,6 +1016,23 @@ int ssl_client_cipher_list_contains_cipher( const struct ssl_early_callback_ctx *client_hello, uint16_t id); +/* GREASE. */ + +enum ssl_grease_index_t { + ssl_grease_cipher = 0, + ssl_grease_group, + ssl_grease_extension1, + ssl_grease_extension2, + ssl_grease_version, +}; + +/* ssl_get_grease_value returns a GREASE value for |ssl|. For a given + * connection, the values for each index will be deterministic. This allows the + * same ClientHello be sent twice for a HelloRetryRequest or the same group be + * advertised in both supported_groups and key_shares. */ +uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index); + + /* Underdocumented functions. * * Functions below here haven't been touched up and may be underdocumented. */ @@ -1250,10 +1269,12 @@ 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-14, used in determining ticket validity. */ -#define SSL_TICKET_ALLOW_EARLY_DATA 1 -#define SSL_TICKET_ALLOW_DHE_RESUMPTION 2 -#define SSL_TICKET_ALLOW_PSK_RESUMPTION 4 +/* From draft-ietf-tls-tls13-15, 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 CERT *ssl_cert_new(void); CERT *ssl_cert_dup(CERT *cert); @@ -1455,6 +1476,13 @@ int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id); int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len, const int *curves, size_t ncurves); +/* tls1_set_curves_list converts the string of curves pointed to by |curves| + * into a newly allocated array of TLS group IDs. On success, the function + * returns one and writes the array to |*out_group_ids| and its size to + * |*out_group_ids_len|. Otherwise, it returns zero. */ +int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len, + const char *curves); + /* tls1_check_ec_cert returns one if |x| is an ECC certificate with curve and * point format compatible with the client's preferences. Otherwise it returns * zero. */ diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index 6395a005..eeea8261 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -121,7 +121,6 @@ * extendedMasterSecret [17] BOOLEAN OPTIONAL, * keyExchangeInfo [18] INTEGER OPTIONAL, * certChain [19] SEQUENCE OF Certificate OPTIONAL, - * ticketFlags [20] INTEGER OPTIONAL, * ticketAgeAdd [21] OCTET STRING OPTIONAL, * } * @@ -131,7 +130,9 @@ * keyArg [0] IMPLICIT OCTET STRING OPTIONAL, * pskIdentityHint [7] OCTET STRING OPTIONAL, * compressionMethod [11] OCTET STRING OPTIONAL, - * srpUsername [12] OCTET STRING OPTIONAL, */ + * srpUsername [12] OCTET STRING OPTIONAL, + * ticketFlags [20] INTEGER OPTIONAL, + */ static const unsigned kVersion = 1; @@ -167,8 +168,6 @@ static const int kKeyExchangeInfoTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 18; static const int kCertChainTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 19; -static const int kTicketFlagsTag = - CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 20; static const int kTicketAgeAddTag = CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 21; @@ -347,14 +346,6 @@ static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data, } } - if (in->ticket_flags > 0) { - if (!CBB_add_asn1(&session, &child, kTicketFlagsTag) || - !CBB_add_asn1_uint64(&child, in->ticket_flags)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - if (in->ticket_age_add_valid) { if (!CBB_add_asn1(&session, &child, kTicketAgeAddTag) || !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || @@ -543,12 +534,6 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } - /* Only support SSLv3/TLS and DTLS. */ - if ((ssl_version >> 8) != SSL3_VERSION_MAJOR && - (ssl_version >> 8) != (DTLS1_VERSION >> 8)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION); - goto err; - } ret->ssl_version = ssl_version; CBS cipher; @@ -693,9 +678,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { CBS age_add; int age_add_present; - if (!SSL_SESSION_parse_u32(&session, &ret->ticket_flags, - kTicketFlagsTag, 0) || - !CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present, + if (!CBS_get_optional_asn1_octet_string(&session, &age_add, &age_add_present, kTicketAgeAddTag) || (age_add_present && !CBS_get_u32(&age_add, &ret->ticket_age_add)) || diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c index 55070e9b..6d48c89b 100644 --- a/src/ssl/ssl_cipher.c +++ b/src/ssl/ssl_cipher.c @@ -343,6 +343,41 @@ static const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_SHA384, }, + /* TLS 1.3 suites. */ + + /* Cipher 1301 */ + { + TLS1_TXT_AES_128_GCM_SHA256, + TLS1_CK_AES_128_GCM_SHA256, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_AES128GCM, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA256, + }, + + /* Cipher 1302 */ + { + TLS1_TXT_AES_256_GCM_SHA384, + TLS1_CK_AES_256_GCM_SHA384, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_AES256GCM, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA384, + }, + + /* Cipher 1303 */ + { + TLS1_TXT_CHACHA20_POLY1305_SHA256, + TLS1_CK_CHACHA20_POLY1305_SHA256, + SSL_kGENERIC, + SSL_aGENERIC, + SSL_CHACHA20POLY1305, + SSL_AEAD, + SSL_HANDSHAKE_MAC_SHA256, + }, + /* CECPQ1 (combined elliptic curve + post-quantum) suites. */ /* Cipher 16B7 */ @@ -608,28 +643,6 @@ static const SSL_CIPHER kCiphers[] = { SSL_HANDSHAKE_MAC_SHA256, }, - /* Cipher D001 */ - { - TLS1_TXT_ECDHE_PSK_WITH_AES_128_GCM_SHA256, - TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256, - SSL_kECDHE, - SSL_aPSK, - SSL_AES128GCM, - SSL_AEAD, - SSL_HANDSHAKE_MAC_SHA256, - }, - - /* Cipher D002 */ - { - TLS1_TXT_ECDHE_PSK_WITH_AES_256_GCM_SHA384, - TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384, - SSL_kECDHE, - SSL_aPSK, - SSL_AES256GCM, - SSL_AEAD, - SSL_HANDSHAKE_MAC_SHA384, - }, - }; static const size_t kCiphersLen = OPENSSL_ARRAY_SIZE(kCiphers); @@ -725,6 +738,9 @@ 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}, @@ -1063,14 +1079,6 @@ static void ssl_cipher_apply_rule( (min_version != 0 && SSL_CIPHER_get_min_version(cp) != min_version)) { continue; } - - /* The following ciphers are internal implementation details of TLS 1.3 - * resumption but are not yet finalized. Disable them by default until - * then. */ - if (cp->id == TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 || - cp->id == TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384) { - continue; - } } /* add the cipher if it has not been added yet. */ @@ -1179,12 +1187,11 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, uint32_t alg_mkey, alg_auth, alg_enc, alg_mac; uint16_t min_version; const char *l, *buf; - int multi, skip_rule, rule, retval, ok, in_group = 0, has_group = 0; + int multi, skip_rule, rule, ok, in_group = 0, has_group = 0; size_t j, buf_len; uint32_t cipher_id; char ch; - retval = 1; l = rule_str; for (;;) { ch = *l; @@ -1210,8 +1217,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } else if (!(ch >= 'a' && ch <= 'z') && !(ch >= 'A' && ch <= 'Z') && !(ch >= '0' && ch <= '9')) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_OPERATOR_IN_GROUP); - retval = in_group = 0; - break; + return 0; } else { rule = CIPHER_ADD; } @@ -1230,8 +1236,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } else if (ch == '[') { if (in_group) { OPENSSL_PUT_ERROR(SSL, SSL_R_NESTED_GROUP); - retval = in_group = 0; - break; + return 0; } in_group = 1; has_group = 1; @@ -1245,8 +1250,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, * Otherwise the in_group bits will get mixed up. */ if (has_group && rule != CIPHER_ADD) { OPENSSL_PUT_ERROR(SSL, SSL_R_MIXED_SPECIAL_OPERATOR_WITH_GROUPS); - retval = in_group = 0; - break; + return 0; } if (ITEM_SEP(ch)) { @@ -1277,9 +1281,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, /* We hit something we cannot deal with, it is no command or separator * nor alphanumeric, so we call this an error. */ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); - retval = in_group = 0; - l++; - break; + return 0; } if (rule == CIPHER_SPECIAL) { @@ -1362,7 +1364,7 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, } if (ok == 0) { - retval = 0; + return 0; } /* We do not support any "multi" options together with "@", so throw away @@ -1378,10 +1380,10 @@ static int ssl_cipher_process_rulestr(const SSL_PROTOCOL_METHOD *ssl_method, if (in_group) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMMAND); - retval = 0; + return 0; } - return retval; + return 1; } STACK_OF(SSL_CIPHER) * @@ -1416,15 +1418,17 @@ 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 ECDHE_ECDSA then ECDHE_RSA over other - * key exchange mechanisms */ + /* 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); 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, &head, &tail); - ssl_cipher_apply_rule(0, SSL_kECDHE, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, - &head, &tail); + ssl_cipher_apply_rule(0, ~0u, ~0u, ~0u, ~0u, 0, CIPHER_DEL, -1, 0, &head, + &tail); /* Order the bulk ciphers. First the preferred AEAD ciphers. We prefer * CHACHA20 unless there is hardware support for fast and constant-time @@ -1464,7 +1468,7 @@ ssl_create_cipher_list(const SSL_PROTOCOL_METHOD *ssl_method, &tail); /* Move ciphers without forward secrecy to the end. */ - ssl_cipher_apply_rule(0, ~(SSL_kDHE | SSL_kECDHE), ~0u, ~0u, ~0u, 0, + ssl_cipher_apply_rule(0, (SSL_kRSA | SSL_kPSK), ~0u, ~0u, ~0u, 0, CIPHER_ORD, -1, 0, &head, &tail); /* Now disable everything (maintaining the ordering!) */ @@ -1575,30 +1579,6 @@ uint16_t ssl_cipher_get_value(const SSL_CIPHER *cipher) { return id & 0xffff; } -int ssl_cipher_get_ecdhe_psk_cipher(const SSL_CIPHER *cipher, - uint16_t *out_cipher) { - switch (cipher->id) { - case TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: - case TLS1_CK_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: - case TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: - *out_cipher = TLS1_CK_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 & 0xffff; - return 1; - - case TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: - case TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256: - *out_cipher = TLS1_CK_ECDHE_PSK_WITH_AES_128_GCM_SHA256 & 0xffff; - return 1; - - case TLS1_CK_ECDHE_RSA_WITH_AES_256_GCM_SHA384: - case TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: - case TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384: - *out_cipher = TLS1_CK_ECDHE_PSK_WITH_AES_256_GCM_SHA384 & 0xffff; - return 1; - } - return 0; -} - int SSL_CIPHER_is_AES(const SSL_CIPHER *cipher) { return (cipher->algorithm_enc & SSL_AES) != 0; } @@ -1662,6 +1642,11 @@ int SSL_CIPHER_is_CECPQ1(const SSL_CIPHER *cipher) { } uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) { + if (cipher->algorithm_mkey == SSL_kGENERIC || + cipher->algorithm_auth == SSL_aGENERIC) { + return TLS1_3_VERSION; + } + if (cipher->algorithm_prf != SSL_HANDSHAKE_MAC_DEFAULT) { /* Cipher suites before TLS 1.2 use the default PRF, while all those added * afterwards specify a particular hash. */ @@ -1671,11 +1656,8 @@ uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) { } uint16_t SSL_CIPHER_get_max_version(const SSL_CIPHER *cipher) { - if (cipher->algorithm_mac == SSL_AEAD && - (cipher->algorithm_enc & SSL_CHACHA20POLY1305_OLD) == 0 && - (cipher->algorithm_mkey & SSL_kECDHE) != 0 && - /* TODO(davidben,svaldez): Support PSK-based ciphers in TLS 1.3. */ - (cipher->algorithm_auth & SSL_aCERT) != 0) { + if (cipher->algorithm_mkey == SSL_kGENERIC || + cipher->algorithm_auth == SSL_aGENERIC) { return TLS1_3_VERSION; } return TLS1_2_VERSION; @@ -1736,6 +1718,10 @@ const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) { assert(cipher->algorithm_auth == SSL_aPSK); return "PSK"; + case SSL_kGENERIC: + assert(cipher->algorithm_auth == SSL_aGENERIC); + return "GENERIC"; + default: assert(0); return "UNKNOWN"; @@ -1794,16 +1780,23 @@ char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { const char *enc_name = ssl_cipher_get_enc_name(cipher); const char *prf_name = ssl_cipher_get_prf_name(cipher); - /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name}. */ - size_t len = 4 + strlen(kx_name) + 6 + strlen(enc_name) + 1 + - strlen(prf_name) + 1; + /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name} or + * TLS_{enc_name}_{prf_name} depending on whether the cipher is AEAD-only. */ + size_t len = 4 + strlen(enc_name) + 1 + strlen(prf_name) + 1; + + if (cipher->algorithm_mkey != SSL_kGENERIC) { + len += strlen(kx_name) + 6; + } + char *ret = OPENSSL_malloc(len); if (ret == NULL) { return NULL; } + if (BUF_strlcpy(ret, "TLS_", len) >= len || - BUF_strlcat(ret, kx_name, len) >= len || - BUF_strlcat(ret, "_WITH_", len) >= len || + (cipher->algorithm_mkey != SSL_kGENERIC && + (BUF_strlcat(ret, kx_name, len) >= len || + BUF_strlcat(ret, "_WITH_", len) >= len)) || BUF_strlcat(ret, enc_name, len) >= len || BUF_strlcat(ret, "_", len) >= len || BUF_strlcat(ret, prf_name, len) >= len) { @@ -1811,6 +1804,7 @@ char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) { OPENSSL_free(ret); return NULL; } + assert(strlen(ret) + 1 == len); return ret; } @@ -1891,6 +1885,10 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, kx = "PSK"; break; + case SSL_kGENERIC: + kx = "GENERIC"; + break; + default: kx = "unknown"; } @@ -1908,6 +1906,10 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, au = "PSK"; break; + case SSL_aGENERIC: + au = "GENERIC"; + break; + default: au = "unknown"; break; @@ -2002,6 +2004,8 @@ int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm) { return 1; } const char *SSL_COMP_get_name(const COMP_METHOD *comp) { return NULL; } +void SSL_COMP_free_compression_methods(void) {} + int ssl_cipher_get_key_type(const SSL_CIPHER *cipher) { uint32_t alg_a = cipher->algorithm_auth; diff --git a/src/ssl/ssl_ecdh.c b/src/ssl/ssl_ecdh.c index 16599e47..bcb3af47 100644 --- a/src/ssl/ssl_ecdh.c +++ b/src/ssl/ssl_ecdh.c @@ -521,6 +521,16 @@ static const SSL_ECDH_METHOD *method_from_nid(int nid) { return NULL; } +static const SSL_ECDH_METHOD *method_from_name(const char *name, size_t len) { + for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMethods); i++) { + if (len == strlen(kMethods[i].name) && + !strncmp(kMethods[i].name, name, len)) { + return &kMethods[i]; + } + } + return NULL; +} + const char* SSL_get_curve_name(uint16_t group_id) { const SSL_ECDH_METHOD *method = method_from_group_id(group_id); if (method == NULL) { @@ -538,6 +548,15 @@ int ssl_nid_to_group_id(uint16_t *out_group_id, int nid) { return 1; } +int ssl_name_to_group_id(uint16_t *out_group_id, const char *name, size_t len) { + const SSL_ECDH_METHOD *method = method_from_name(name, len); + if (method == NULL) { + return 0; + } + *out_group_id = method->group_id; + return 1; +} + int SSL_ECDH_CTX_init(SSL_ECDH_CTX *ctx, uint16_t group_id) { SSL_ECDH_CTX_cleanup(ctx); diff --git a/src/ssl/ssl_file.c b/src/ssl/ssl_file.c index 748d50ca..e1ebaa69 100644 --- a/src/ssl/ssl_file.c +++ b/src/ssl/ssl_file.c @@ -164,16 +164,17 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) { goto err; } - /* check for duplicates */ - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } + /* Check for duplicates. */ if (sk_X509_NAME_find(sk, NULL, xn)) { + continue; + } + + xn = X509_NAME_dup(xn); + if (xn == NULL || + !sk_X509_NAME_push(sk /* non-owning */, xn) || + !sk_X509_NAME_push(ret /* owning */, xn)) { X509_NAME_free(xn); - } else { - sk_X509_NAME_push(sk, xn); - sk_X509_NAME_push(ret, xn); + goto err; } } @@ -197,7 +198,7 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, BIO *in; X509 *x = NULL; X509_NAME *xn = NULL; - int ret = 1; + int ret = 0; int (*oldcmp)(const X509_NAME **a, const X509_NAME **b); oldcmp = sk_X509_NAME_set_cmp_func(stack, xname_cmp); @@ -220,24 +221,24 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, if (xn == NULL) { goto err; } - xn = X509_NAME_dup(xn); - if (xn == NULL) { - goto err; - } + + /* Check for duplicates. */ if (sk_X509_NAME_find(stack, NULL, xn)) { + continue; + } + + xn = X509_NAME_dup(xn); + if (xn == NULL || + !sk_X509_NAME_push(stack, xn)) { X509_NAME_free(xn); - } else { - sk_X509_NAME_push(stack, xn); + goto err; } } ERR_clear_error(); + ret = 1; - if (0) { - err: - ret = 0; - } - +err: BIO_free(in); X509_free(x); diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 6ec7d257..f17dc0ac 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -951,6 +951,10 @@ static int set_min_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out, return 1; } + if (version == TLS1_3_VERSION) { + version = TLS1_3_DRAFT_VERSION; + } + return method->version_from_wire(out, version); } @@ -965,6 +969,10 @@ static int set_max_version(const SSL_PROTOCOL_METHOD *method, uint16_t *out, return 1; } + if (version == TLS1_3_VERSION) { + version = TLS1_3_DRAFT_VERSION; + } + return method->version_from_wire(out, version); } @@ -1491,13 +1499,24 @@ int SSL_set1_curves(SSL *ssl, const int *curves, size_t curves_len) { curves_len); } +int SSL_CTX_set1_curves_list(SSL_CTX *ctx, const char *curves) { + return tls1_set_curves_list(&ctx->supported_group_list, + &ctx->supported_group_list_len, curves); +} + +int SSL_set1_curves_list(SSL *ssl, const char *curves) { + return tls1_set_curves_list(&ssl->supported_group_list, + &ssl->supported_group_list_len, curves); +} + uint16_t SSL_get_curve_id(const SSL *ssl) { /* TODO(davidben): This checks the wrong session if there is a renegotiation in * progress. */ SSL_SESSION *session = SSL_get_session(ssl); if (session == NULL || session->cipher == NULL || - !SSL_CIPHER_is_ECDHE(session->cipher)) { + (ssl3_protocol_version(ssl) < TLS1_3_VERSION && + !SSL_CIPHER_is_ECDHE(session->cipher))) { return 0; } @@ -2012,6 +2031,12 @@ size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k, uint32_t *out_mask_a) { + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + *out_mask_k = SSL_kGENERIC; + *out_mask_a = SSL_aGENERIC; + return; + } + uint32_t mask_k = 0; uint32_t mask_a = 0; @@ -2109,7 +2134,8 @@ void ssl_update_cache(SSL *ssl, int mode) { static const char *ssl_get_version(int version) { switch (version) { - case TLS1_3_VERSION: + /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ + case TLS1_3_DRAFT_VERSION: return "TLSv1.3"; case TLS1_2_VERSION: @@ -2271,7 +2297,14 @@ int SSL_get_shutdown(const SSL *ssl) { return ret; } -int SSL_version(const SSL *ssl) { return ssl->version; } +int SSL_version(const SSL *ssl) { + /* Report TLS 1.3 draft version as TLS 1.3 in the public API. */ + if (ssl->version == TLS1_3_DRAFT_VERSION) { + return TLS1_3_VERSION; + } + + return ssl->version; +} SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { return ssl->ctx; } @@ -2884,6 +2917,10 @@ void SSL_CTX_set_retain_only_sha256_of_client_certs(SSL_CTX *ctx, int enabled) { ctx->retain_only_sha256_of_client_certs = !!enabled; } +void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) { + ctx->grease_enabled = !!enabled; +} + int SSL_clear(SSL *ssl) { if (ssl->method == NULL) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED); @@ -2958,7 +2995,7 @@ void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, version = 0; break; default: - version = ssl->version; + version = SSL_version(ssl); } ssl->msg_callback(is_write, version, content_type, buf, len, ssl, @@ -3013,7 +3050,10 @@ void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock) { return; } -#if defined(OPENSSL_WINDOWS) +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + out_clock->tv_sec = 1234; + out_clock->tv_usec = 1234; +#elif defined(OPENSSL_WINDOWS) struct _timeb time; _ftime(&time); out_clock->tv_sec = time.time; diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_rsa.c index a5f15f45..6f8ceae3 100644 --- a/src/ssl/ssl_rsa.c +++ b/src/ssl/ssl_rsa.c @@ -763,8 +763,7 @@ int ssl_private_key_supports_signature_algorithm(SSL *ssl, return 1; } - /* TODO(davidben): Remove support for EVP_PKEY_EC keys. */ - return curve != NID_undef && (type == EVP_PKEY_EC || type == curve); + return curve != NID_undef && type == curve; } if (is_rsa_pss(&md, signature_algorithm)) { diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c index 78dfeab6..c2396b17 100644 --- a/src/ssl/ssl_session.c +++ b/src/ssl/ssl_session.c @@ -234,6 +234,9 @@ 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; + new_session->timeout = session->timeout; + new_session->time = session->time; + /* Copy non-authentication connection properties. */ if (dup_flags & SSL_SESSION_INCLUDE_NONAUTH) { new_session->session_id_length = session->session_id_length; @@ -241,8 +244,6 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { session->session_id_length); new_session->key_exchange_info = session->key_exchange_info; - new_session->timeout = session->timeout; - new_session->time = session->time; if (session->tlsext_hostname != NULL) { new_session->tlsext_hostname = BUF_strdup(session->tlsext_hostname); @@ -257,7 +258,6 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { new_session->original_handshake_hash_len = session->original_handshake_hash_len; new_session->tlsext_tick_lifetime_hint = session->tlsext_tick_lifetime_hint; - new_session->ticket_flags = session->ticket_flags; new_session->ticket_age_add = session->ticket_age_add; new_session->extended_master_secret = session->extended_master_secret; } @@ -547,8 +547,12 @@ int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { goto err; } - int len; size_t total = 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + memcpy(ptr, session_buf, session_len); + total = session_len; +#else + int len; if (!EVP_EncryptUpdate(&ctx, ptr + total, &len, session_buf, session_len)) { goto err; } @@ -557,6 +561,7 @@ int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { goto err; } total += len; +#endif if (!CBB_did_write(out, total)) { goto err; } diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 48dbbac4..419cce56 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -56,6 +56,13 @@ struct CipherTest { std::vector<ExpectedCipher> expected; }; +struct CurveTest { + // The rule string to apply. + const char *rule; + // The list of expected curves, in order. + std::vector<uint16_t> expected; +}; + static const CipherTest kCipherTests[] = { // Selecting individual ciphers should work. { @@ -245,6 +252,8 @@ static const char *kBadRules[] = { "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:!FOO", "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:-FOO", "[ECDHE-RSA-CHACHA20-POLY1305|ECDHE-RSA-AES128-GCM-SHA256]:@STRENGTH", + // Opcode supplied, but missing selector. + "+", }; static const char *kMustNotIncludeNull[] = { @@ -260,6 +269,7 @@ static const char *kMustNotIncludeNull[] = { "SSLv3", "TLSv1", "TLSv1.2", + "GENERIC", }; static const char *kMustNotIncludeCECPQ1[] = { @@ -284,6 +294,34 @@ static const char *kMustNotIncludeCECPQ1[] = { "AES256", "AESGCM", "CHACHA20", + "GENERIC", +}; + +static const CurveTest kCurveTests[] = { + { + "P-256", + { SSL_CURVE_SECP256R1 }, + }, + { + "P-256:P-384:P-521:X25519", + { + SSL_CURVE_SECP256R1, + SSL_CURVE_SECP384R1, + SSL_CURVE_SECP521R1, + SSL_CURVE_X25519, + }, + }, +}; + +static const char *kBadCurvesLists[] = { + "", + ":", + "::", + "P-256::X25519", + "RSA:P-256", + "P-256:RSA", + "X25519:P-256:", + ":X25519:P-256", }; static void PrintCipherPreferenceList(ssl_cipher_preference_list_st *list) { @@ -408,6 +446,55 @@ static bool TestCipherRules() { return true; } +static bool TestCurveRule(const CurveTest &t) { + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); + if (!ctx) { + return false; + } + + if (!SSL_CTX_set1_curves_list(ctx.get(), t.rule)) { + fprintf(stderr, "Error testing curves list '%s'\n", t.rule); + return false; + } + + // Compare the two lists. + if (ctx->supported_group_list_len != t.expected.size()) { + fprintf(stderr, "Error testing curves list '%s': length\n", t.rule); + return false; + } + + for (size_t i = 0; i < t.expected.size(); i++) { + if (t.expected[i] != ctx->supported_group_list[i]) { + fprintf(stderr, "Error testing curves list '%s': mismatch\n", t.rule); + return false; + } + } + + return true; +} + +static bool TestCurveRules() { + for (const CurveTest &test : kCurveTests) { + if (!TestCurveRule(test)) { + return false; + } + } + + for (const char *rule : kBadCurvesLists) { + bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(SSLv23_server_method())); + if (!ctx) { + return false; + } + if (SSL_CTX_set1_curves_list(ctx.get(), rule)) { + fprintf(stderr, "Curves list '%s' unexpectedly succeeded\n", rule); + return false; + } + ERR_clear_error(); + } + + return true; +} + // kOpenSSLSession is a serialized SSL_SESSION generated from openssl // s_client -sess_out. static const char kOpenSSLSession[] = @@ -729,30 +816,34 @@ typedef struct { } CIPHER_RFC_NAME_TEST; static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = { - { SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA" }, - { TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA" }, - { TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" }, - { TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, - "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" }, - { TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, - "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" }, - { TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" }, - { TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" }, - { TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA, - "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA" }, - { TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" }, - // These names are non-standard: - { TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, - "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" }, - { TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, - "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" }, + {SSL3_CK_RSA_DES_192_CBC3_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA"}, + {TLS1_CK_RSA_WITH_AES_128_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA"}, + {TLS1_CK_DHE_RSA_WITH_AES_256_SHA, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"}, + {TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"}, + {TLS1_CK_ECDHE_RSA_WITH_AES_128_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"}, + {TLS1_CK_ECDHE_RSA_WITH_AES_256_SHA384, + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"}, + {TLS1_CK_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"}, + {TLS1_CK_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}, + {TLS1_CK_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"}, + {TLS1_CK_ECDHE_PSK_WITH_AES_128_CBC_SHA, + "TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA"}, + {TLS1_CK_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"}, + {TLS1_CK_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384"}, + {TLS1_CK_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256"}, + {TLS1_CK_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256"}, + + // These names are non-standard: + {TLS1_CK_ECDHE_RSA_CHACHA20_POLY1305_OLD, + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"}, + {TLS1_CK_ECDHE_ECDSA_CHACHA20_POLY1305_OLD, + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256"}, }; static bool TestCipherGetRFCName(void) { @@ -1505,10 +1596,14 @@ static bool TestSetBIO() { return true; } -static uint16_t kVersions[] = { +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 int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; } static bool TestGetPeerCertificate() { @@ -1518,7 +1613,7 @@ static bool TestGetPeerCertificate() { return false; } - for (uint16_t version : kVersions) { + 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 || @@ -1584,7 +1679,7 @@ static bool TestRetainOnlySHA256OfCerts() { uint8_t cert_sha256[SHA256_DIGEST_LENGTH]; SHA256(cert_der, cert_der_len, cert_sha256); - for (uint16_t version : kVersions) { + 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())); @@ -1864,7 +1959,7 @@ static bool TestSessionIDContext() { static const uint8_t kContext1[] = {1}; static const uint8_t kContext2[] = {2}; - for (uint16_t version : kVersions) { + 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 || @@ -1926,7 +2021,7 @@ static bool TestSessionTimeout() { return false; } - for (uint16_t version : kVersions) { + 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 || @@ -1990,7 +2085,7 @@ static bool TestSNICallback() { // At each version, test that switching the |SSL_CTX| at the SNI callback // behaves correctly. - for (uint16_t version : kVersions) { + for (uint16_t version : kTLSVersions) { if (version == SSL3_VERSION) { continue; } @@ -2160,10 +2255,56 @@ static bool TestSetVersion() { return true; } +static bool TestVersions() { + 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; + } + + 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; + } + } + } + + return true; +} + int main() { CRYPTO_library_init(); if (!TestCipherRules() || + !TestCurveRules() || !TestSSL_SESSIONEncoding(kOpenSSLSession) || !TestSSL_SESSIONEncoding(kCustomSession) || !TestSSL_SESSIONEncoding(kBoringSSLSession) || @@ -2196,7 +2337,8 @@ int main() { !TestSessionTimeout() || !TestSNICallback() || !TestEarlyCallbackVersionSwitch() || - !TestSetVersion()) { + !TestSetVersion() || + !TestVersions()) { ERR_print_errors_fp(stderr); return 1; } diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index 81dbdc4b..2aca2687 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -402,6 +402,49 @@ int tls1_set_curves(uint16_t **out_group_ids, size_t *out_group_ids_len, return 1; } +int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len, + const char *curves) { + uint16_t *group_ids = NULL; + size_t ncurves = 0; + + const char *col; + const char *ptr = curves; + + do { + col = strchr(ptr, ':'); + + uint16_t group_id; + if (!ssl_name_to_group_id(&group_id, ptr, + col ? (size_t)(col - ptr) : strlen(ptr))) { + goto err; + } + + uint16_t *new_group_ids = OPENSSL_realloc(group_ids, + (ncurves + 1) * sizeof(uint16_t)); + if (new_group_ids == NULL) { + goto err; + } + group_ids = new_group_ids; + + group_ids[ncurves] = group_id; + ncurves++; + + if (col) { + ptr = col + 1; + } + } while (col); + + OPENSSL_free(*out_group_ids); + *out_group_ids = group_ids; + *out_group_ids_len = ncurves; + + return 1; + +err: + OPENSSL_free(group_ids); + return 0; +} + /* tls1_curve_params_from_ec_key sets |*out_group_id| and |*out_comp_id| to the * TLS group ID and point format, respectively, for |ec|. It returns one on * success and zero on failure. */ @@ -1197,20 +1240,26 @@ static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } - /* OCSP stapling is forbidden on a non-certificate cipher. */ - if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - return 0; - } - if (ssl3_protocol_version(ssl) < TLS1_3_VERSION) { - if (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; } + /* 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->tmp.certificate_status_expected = 1; return 1; } + /* In TLS 1.3, OCSP stapling is forbidden on resumption. */ + if (ssl->s3->session_reused) { + return 0; + } + uint8_t status_type; CBS ocsp_response; if (!CBS_get_u8(contents, &status_type) || @@ -1251,7 +1300,9 @@ 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->tmp.ocsp_stapling_requested || ssl->ctx->ocsp_response_length == 0 || - !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { + ssl->s3->session_reused || + (ssl3_protocol_version(ssl) < TLS1_3_VERSION && + !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher))) { return 1; } @@ -1446,7 +1497,11 @@ static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } - /* Session resumption uses the original session information. */ + /* Session resumption uses the original session information. The extension + * should not be sent on resumption, but RFC 6962 did not make it a + * requirement, so tolerate this. + * + * TODO(davidben): Enforce this anyway. */ if (!ssl->s3->session_reused && !CBS_stow( contents, @@ -1966,30 +2021,9 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { return ext_ec_point_add_extension(ssl, out); } - -/* Draft Version Extension */ - -static int ext_draft_version_add_clienthello(SSL *ssl, CBB *out) { - uint16_t min_version, max_version; - if (!ssl_get_version_range(ssl, &min_version, &max_version) || - max_version < TLS1_3_VERSION) { - return 1; - } - - CBB contents; - if (!CBB_add_u16(out, TLSEXT_TYPE_draft_version) || - !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16(&contents, TLS1_3_DRAFT_VERSION)) { - return 0; - } - - return CBB_flush(out); -} - - /* Pre Shared Key * - * https://tools.ietf.org/html/draft-ietf-tls-tls13-14 */ + * https://tools.ietf.org/html/draft-ietf-tls-tls13-15 */ static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) { uint16_t min_version, max_version; @@ -2005,12 +2039,16 @@ static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) { return 1; } - CBB contents, identities, identity; + CBB contents, identity, ke_modes, auth_modes, ticket; if (!CBB_add_u16(out, TLSEXT_TYPE_pre_shared_key) || !CBB_add_u16_length_prefixed(out, &contents) || - !CBB_add_u16_length_prefixed(&contents, &identities) || - !CBB_add_u16_length_prefixed(&identities, &identity) || - !CBB_add_bytes(&identity, ssl->session->tlsext_tick, + !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)) { return 0; } @@ -2023,11 +2061,13 @@ int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert, uint16_t psk_id; if (!CBS_get_u16(contents, &psk_id) || CBS_len(contents) != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); *out_alert = SSL_AD_DECODE_ERROR; return 0; } if (psk_id != 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); *out_alert = SSL_AD_UNKNOWN_PSK_IDENTITY; return 0; } @@ -2039,19 +2079,30 @@ int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl, SSL_SESSION **out_session, uint8_t *out_alert, CBS *contents) { - CBS identities, identity; - if (!CBS_get_u16_length_prefixed(contents, &identities) || - !CBS_get_u16_length_prefixed(&identities, &identity) || - CBS_len(contents) != 0) { + /* We only process the first PSK identity since we don't support pure PSK. */ + CBS identity, ke_modes, auth_modes, ticket; + 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) { *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; + } + /* 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(&identity), - CBS_len(&identity), NULL, 0); + return tls_process_ticket(ssl, out_session, &renew, CBS_data(&ticket), + CBS_len(&ticket), NULL, 0); } int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) { @@ -2106,6 +2157,15 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { group_id = ssl->s3->hs->retry_group; } else { + /* Add a fake group. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + (!CBB_add_u16(&kse_bytes, + ssl_get_grease_value(ssl, ssl_grease_group)) || + !CBB_add_u16(&kse_bytes, 1 /* length */) || + !CBB_add_u8(&kse_bytes, 0 /* one byte key share */))) { + return 0; + } + /* Predict the most preferred group. */ const uint16_t *groups; size_t groups_len; @@ -2177,8 +2237,13 @@ int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, uint8_t *out_alert, CBS *contents) { uint16_t group_id; CBS key_shares; - if (!tls1_get_shared_group(ssl, &group_id) || - !CBS_get_u16_length_prefixed(contents, &key_shares) || + if (!tls1_get_shared_group(ssl, &group_id)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP); + *out_alert = SSL_AD_HANDSHAKE_FAILURE; + return 0; + } + + if (!CBS_get_u16_length_prefixed(contents, &key_shares) || CBS_len(contents) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return 0; @@ -2232,6 +2297,7 @@ int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, OPENSSL_free(secret); SSL_ECDH_CTX_cleanup(&group); CBB_cleanup(&public_key); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -2244,10 +2310,6 @@ int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, } int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->s3->tmp.new_cipher->algorithm_mkey != SSL_kECDHE) { - return 1; - } - uint16_t group_id; CBB kse_bytes, public_key; if (!tls1_get_shared_group(ssl, &group_id) || @@ -2270,6 +2332,47 @@ int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) { } +/* Supported Versions + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.1 */ + +static int ext_supported_versions_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_2_VERSION) { + return 1; + } + + CBB contents, versions; + if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) || + !CBB_add_u16_length_prefixed(out, &contents) || + !CBB_add_u8_length_prefixed(&contents, &versions)) { + return 0; + } + + /* Add a fake version. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&versions, ssl_get_grease_value(ssl, ssl_grease_version))) { + return 0; + } + + for (uint16_t version = max_version; version >= min_version; version--) { + if (!CBB_add_u16(&versions, ssl->method->version_to_wire(version))) { + return 0; + } + } + + if (!CBB_flush(out)) { + return 0; + } + + return 1; +} + + /* Negotiated Groups * * https://tools.ietf.org/html/rfc4492#section-5.1.2 @@ -2293,6 +2396,13 @@ static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) { return 0; } + /* Add a fake group. See draft-davidben-tls-grease-01. */ + if (ssl->ctx->grease_enabled && + !CBB_add_u16(&groups_bytes, + ssl_get_grease_value(ssl, ssl_grease_group))) { + return 0; + } + const uint16_t *groups; size_t groups_len; tls1_get_grouplist(ssl, 0, &groups, &groups_len); @@ -2460,25 +2570,25 @@ static const struct tls_extension kExtensions[] = { ext_ec_point_add_serverhello, }, { - TLSEXT_TYPE_draft_version, + TLSEXT_TYPE_key_share, NULL, - ext_draft_version_add_clienthello, + ext_key_share_add_clienthello, forbid_parse_serverhello, ignore_parse_clienthello, dont_add_serverhello, }, { - TLSEXT_TYPE_key_share, + TLSEXT_TYPE_pre_shared_key, NULL, - ext_key_share_add_clienthello, + ext_pre_shared_key_add_clienthello, forbid_parse_serverhello, ignore_parse_clienthello, dont_add_serverhello, }, { - TLSEXT_TYPE_pre_shared_key, + TLSEXT_TYPE_supported_versions, NULL, - ext_pre_shared_key_add_clienthello, + ext_supported_versions_add_clienthello, forbid_parse_serverhello, ignore_parse_clienthello, dont_add_serverhello, @@ -2546,6 +2656,16 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { } } + uint16_t grease_ext1 = 0; + if (ssl->ctx->grease_enabled) { + /* Add a fake empty extension. See draft-davidben-tls-grease-01. */ + grease_ext1 = ssl_get_grease_value(ssl, ssl_grease_extension1); + if (!CBB_add_u16(&extensions, grease_ext1) || + !CBB_add_u16(&extensions, 0 /* zero length */)) { + goto err; + } + } + for (size_t i = 0; i < kNumExtensions; i++) { const size_t len_before = CBB_len(&extensions); if (!kExtensions[i].add_clienthello(ssl, &extensions)) { @@ -2563,6 +2683,24 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { goto err; } + if (ssl->ctx->grease_enabled) { + /* Add a fake non-empty extension. See draft-davidben-tls-grease-01. */ + uint16_t grease_ext2 = ssl_get_grease_value(ssl, ssl_grease_extension2); + + /* The two fake extensions must not have the same value. GREASE values are + * of the form 0x1a1a, 0x2a2a, 0x3a3a, etc., so XOR to generate a different + * one. */ + if (grease_ext1 == grease_ext2) { + grease_ext2 ^= 0x1010; + } + + if (!CBB_add_u16(&extensions, grease_ext2) || + !CBB_add_u16(&extensions, 1 /* one byte length */) || + !CBB_add_u8(&extensions, 0 /* single zero byte as contents */)) { + goto err; + } + } + if (!SSL_is_dtls(ssl)) { header_len += 2 + CBB_len(&extensions); if (header_len > 0xff && header_len < 0x200) { @@ -2963,7 +3101,12 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, } HMAC_Update(&hmac_ctx, ticket, ticket_len - mac_len); HMAC_Final(&hmac_ctx, mac, NULL); - if (CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) != 0) { + int mac_ok = + CRYPTO_memcmp(mac, ticket + (ticket_len - mac_len), mac_len) == 0; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + mac_ok = 1; +#endif + if (!mac_ok) { goto done; } @@ -2976,6 +3119,11 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, ret = 0; goto done; } + size_t plaintext_len; +#if defined(BORINGSSL_UNSAFE_FUZZER_MODE) + memcpy(plaintext, ciphertext, ciphertext_len); + plaintext_len = ciphertext_len; +#else if (ciphertext_len >= INT_MAX) { goto done; } @@ -2986,9 +3134,11 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, ERR_clear_error(); /* Don't leave an error on the queue. */ goto done; } + plaintext_len = (size_t)(len1 + len2); +#endif /* Decode the session. */ - SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, len1 + len2); + SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, plaintext_len); if (session == NULL) { ERR_clear_error(); /* Don't leave an error on the queue. */ goto done; diff --git a/src/ssl/test/PORTING.md b/src/ssl/test/PORTING.md index 1d5ac574..86ad24d0 100644 --- a/src/ssl/test/PORTING.md +++ b/src/ssl/test/PORTING.md @@ -98,6 +98,9 @@ enough calls to reach the number, the shim should fail with exit code See `crypto/test/malloc.cc` for an example malloc implementation. +Note these tests are slow and will hit Go's test timeout. Pass `-timeout 72h` to +avoid crashing after 10 minutes. + ## Example: Running Against NSS diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index dc6e99d2..c4407daa 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -942,6 +942,10 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) { SSL_CTX_set_client_CA_list(ssl_ctx.get(), nullptr); } + if (config->enable_grease) { + SSL_CTX_set_grease_enabled(ssl_ctx.get(), 1); + } + return ssl_ctx; } @@ -1020,11 +1024,33 @@ static int DoRead(SSL *ssl, uint8_t *out, size_t max_out) { // trigger a retransmit, so disconnect the write quota. AsyncBioEnforceWriteQuota(test_state->async_bio, false); } - ret = SSL_read(ssl, out, max_out); + ret = config->peek_then_read ? SSL_peek(ssl, out, max_out) + : SSL_read(ssl, out, max_out); if (config->async) { AsyncBioEnforceWriteQuota(test_state->async_bio, true); } } while (config->async && RetryAsync(ssl, ret)); + + if (config->peek_then_read && ret > 0) { + std::unique_ptr<uint8_t[]> buf(new uint8_t[static_cast<size_t>(ret)]); + + // SSL_peek should synchronously return the same data. + int ret2 = SSL_peek(ssl, buf.get(), ret); + if (ret2 != ret || + memcmp(buf.get(), out, ret) != 0) { + fprintf(stderr, "First and second SSL_peek did not match.\n"); + return -1; + } + + // SSL_read should synchronously return the same data and consume it. + ret2 = SSL_read(ssl, buf.get(), ret); + if (ret2 != ret || + memcmp(buf.get(), out, ret) != 0) { + fprintf(stderr, "SSL_peek and SSL_read did not match.\n"); + return -1; + } + } + return ret; } @@ -1414,6 +1440,9 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, DTLSv1_set_initial_timeout_duration(ssl.get(), config->initial_timeout_duration_ms); } + if (config->max_cert_list > 0) { + SSL_set_max_cert_list(ssl.get(), config->max_cert_list); + } int sock = Connect(config->port); if (sock == -1) { diff --git a/src/ssl/test/runner/cipher_suites.go b/src/ssl/test/runner/cipher_suites.go index 4ce4629a..656a3d0d 100644 --- a/src/ssl/test/runner/cipher_suites.go +++ b/src/ssl/test/runner/cipher_suites.go @@ -101,38 +101,20 @@ func (cs cipherSuite) hash() crypto.Hash { return crypto.SHA256 } -// TODO(nharper): Remove this function when TLS 1.3 cipher suites get -// refactored to break out the AEAD/PRF from everything else. Once that's -// done, this won't be necessary anymore. -func ecdhePSKSuite(id uint16) uint16 { - switch id { - case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256: - return TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 - case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256: - return TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 - case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384: - return TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 - } - return 0 -} - var cipherSuites = []*cipherSuite{ // Ciphersuite order is chosen so that ECDHE comes before plain RSA // and RC4 comes before AES (because of the Lucky13 attack). - {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305}, - {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305}, + {TLS_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, nil, suiteTLS13, nil, nil, aeadCHACHA20POLY1305}, + {TLS_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, nil, suiteTLS13, nil, nil, aeadAESGCM}, + {TLS_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, nil, suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, + {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD, 32, 0, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadCHACHA20POLY1305Old}, {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD, 32, 0, noIV, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadCHACHA20POLY1305Old}, - {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM}, - {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM}, - {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM}, - {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheRSAKA, suiteECDHE | suiteNoDTLS, cipherRC4, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, noIV, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteNoDTLS, cipherRC4, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, ivLenAES, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, @@ -164,9 +146,7 @@ var cipherSuites = []*cipherSuite{ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, dheRSAKA, 0, cipher3DES, macSHA1, nil}, {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, ivLen3DES, rsaKA, 0, cipher3DES, macSHA1, nil}, - {TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13, nil, nil, aeadCHACHA20POLY1305}, - {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, ivLenAESGCM, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13, nil, nil, aeadAESGCM}, - {TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384, 32, 0, ivLenAESGCM, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12 | suiteTLS13 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256, 32, 0, ivLenChaCha20Poly1305, ecdhePSKKA, suiteECDHE | suitePSK | suiteTLS12, nil, nil, aeadCHACHA20POLY1305}, {TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, 16, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, {TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, 32, 20, ivLenAES, ecdhePSKKA, suiteECDHE | suitePSK, cipherAES, macSHA1, nil}, {TLS_PSK_WITH_RC4_128_SHA, 16, 20, noIV, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil}, @@ -562,8 +542,9 @@ const ( const ( TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc13 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256_OLD uint16 = 0xcc14 - TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xd001 - TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384 uint16 = 0xd002 + TLS_AES_128_GCM_SHA256 uint16 = 0x1301 + TLS_AES_256_GCM_SHA384 uint16 = 0x1302 + TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303 TLS_CECPQ1_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b7 TLS_CECPQ1_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0x16b8 TLS_CECPQ1_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x16b9 diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 715a94be..309cd82c 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -26,9 +26,8 @@ const ( VersionTLS13 = 0x0304 ) -// The draft version of TLS 1.3 that is implemented here and sent in the draft -// indicator extension. -const tls13DraftVersion = 14 +// A draft version of TLS 1.3 that is sent over the wire for the current draft. +const tls13DraftVersion = 0x7f0f const ( maxPlaintext = 16384 // maximum plaintext payload length @@ -93,11 +92,11 @@ const ( extensionKeyShare uint16 = 40 // draft-ietf-tls-tls13-13 extensionPreSharedKey uint16 = 41 // draft-ietf-tls-tls13-13 extensionEarlyData uint16 = 42 // draft-ietf-tls-tls13-13 + extensionSupportedVersions uint16 = 43 // draft-ietf-tls-tls13-16 extensionCookie uint16 = 44 // draft-ietf-tls-tls13-13 extensionCustom uint16 = 1234 // not IANA assigned extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionRenegotiationInfo uint16 = 0xff01 - extensionTLS13Draft uint16 = 0xff02 extensionChannelID uint16 = 30032 // not IANA assigned ) @@ -190,11 +189,16 @@ const ( SRTP_AES128_CM_HMAC_SHA1_32 = 0x0002 ) -// TicketFlags values (see draft-ietf-tls-tls13-14, section 4.4.1) +// PskKeyExchangeMode values (see draft-ietf-tls-tls13-15) const ( - ticketAllowEarlyData = 1 - ticketAllowDHEResumption = 2 - ticketAllowPSKResumption = 4 + pskKEMode = 0 + pskDHEKEMode = 1 +) + +// PskAuthenticationMode values (see draft-ietf-tls-tls13-15) +const ( + pskAuthMode = 0 + pskSignAuthMode = 1 ) // ConnectionState records basic TLS details about the connection. @@ -244,8 +248,6 @@ type ClientSessionState struct { ocspResponse []byte ticketCreationTime time.Time ticketExpiration time.Time - ticketFlags uint32 - ticketAgeAdd uint32 } // ClientSessionCache is a cache of ClientSessionState objects that can be used @@ -597,10 +599,18 @@ type ProtocolBugs struct { // send a NewSessionTicket message during an abbreviated handshake. RenewTicketOnResume bool - // SendClientVersion, if non-zero, causes the client to send a different - // TLS version in the ClientHello than the maximum supported version. + // SendClientVersion, if non-zero, causes the client to send the + // specified value in the ClientHello version field. SendClientVersion uint16 + // OmitSupportedVersions, if true, causes the client to omit the + // supported versions extension. + OmitSupportedVersions bool + + // SendSupportedVersions, if non-empty, causes the client to send a + // supported versions extension with the values from array. + SendSupportedVersions []uint16 + // NegotiateVersion, if non-zero, causes the server to negotiate the // specifed TLS version rather than the version supported by either // peer. @@ -736,8 +746,8 @@ type ProtocolBugs struct { // across a renego. RequireSameRenegoClientVersion bool - // ExpectInitialRecordVersion, if non-zero, is the expected - // version of the records before the version is determined. + // ExpectInitialRecordVersion, if non-zero, is the expected value of + // record-layer version field before the version is determined. ExpectInitialRecordVersion uint16 // MaxPacketLength, if non-zero, is the maximum acceptable size for a @@ -853,9 +863,9 @@ type ProtocolBugs struct { // be packed into records, up to the largest size record available. PackHandshakeFlight bool - // EnableAllCiphers, if true, causes all configured ciphers to be - // enabled. - EnableAllCiphers bool + // AdvertiseAllConfiguredCiphers, if true, causes the client to + // advertise all configured cipher suite values. + AdvertiseAllConfiguredCiphers bool // EmptyCertificateList, if true, causes the server to send an empty // certificate list in the Certificate message. @@ -907,6 +917,13 @@ type ProtocolBugs struct { // session ticket. SendEmptySessionTicket bool + // SnedPSKKeyExchangeModes, if present, determines the PSK key exchange modes + // to send. + SendPSKKeyExchangeModes []byte + + // SendPSKAuthModes, if present, determines the PSK auth modes to send. + SendPSKAuthModes []byte + // FailIfSessionOffered, if true, causes the server to fail any // connections where the client offers a non-empty session ID or session // ticket. @@ -951,6 +968,11 @@ type ProtocolBugs struct { // supplied SCT list in resumption handshakes. SendSCTListOnResume []byte + // SendOCSPResponseOnResume, if not nil, causes the server to advertise + // OCSP stapling in resumption handshakes and, if applicable, send the + // supplied stapled response. + SendOCSPResponseOnResume []byte + // CECPQ1BadX25519Part corrupts the X25519 part of a CECPQ1 key exchange, as // a trivial proof that it is actually used. CECPQ1BadX25519Part bool @@ -1004,6 +1026,26 @@ type ProtocolBugs struct { // advertised in server extensions AdvertiseTicketExtension bool + // NegotiatePSKResumption, if true, causes the server to attempt pure PSK + // resumption. + NegotiatePSKResumption bool + + // AlwaysSelectPSKIdentity, if true, causes the server in TLS 1.3 to + // always acknowledge a session, regardless of one was offered. + AlwaysSelectPSKIdentity bool + + // SelectPSKIdentityOnResume, if non-zero, causes the server to select + // 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 + // MissingKeyShare, if true, causes the TLS 1.3 implementation to skip // sending a key_share extension and use the zero ECDHE secret // instead. @@ -1040,7 +1082,7 @@ type ProtocolBugs struct { SecondHelloRetryRequest bool // SendServerHelloVersion, if non-zero, causes the server to send the - // specified version in ServerHello rather than the true version. + // specified value in ServerHello version field. SendServerHelloVersion uint16 // SkipHelloRetryRequest, if true, causes the TLS 1.3 server to not send @@ -1080,6 +1122,14 @@ type ProtocolBugs struct { // TrailingKeyShareData, if true, causes the client key share list to // include a trailing byte. TrailingKeyShareData bool + + // InvalidChannelIDSignature, if true, causes the client to generate an + // invalid Channel ID signature. + InvalidChannelIDSignature bool + + // ExpectGREASE, if true, causes the server to reject a ClientHello + // unless it contains GREASE values. See draft-davidben-tls-grease-01. + ExpectGREASE bool } func (c *Config) serverInit() { @@ -1180,24 +1230,10 @@ func (c *Config) defaultCurves() map[CurveID]bool { return defaultCurves } -// mutualVersion returns the protocol version to use given the advertised -// version of the peer. -func (c *Config) mutualVersion(vers uint16, isDTLS bool) (uint16, bool) { - // There is no such thing as DTLS 1.1. - if isDTLS && vers == VersionTLS11 { - vers = VersionTLS10 - } - - minVersion := c.minVersion(isDTLS) - maxVersion := c.maxVersion(isDTLS) - - if vers < minVersion { - return 0, false - } - if vers > maxVersion { - vers = maxVersion - } - return vers, true +// isSupportedVersion returns true if the specified protocol version is +// acceptable. +func (c *Config) isSupportedVersion(vers uint16, isDTLS bool) bool { + return c.minVersion(isDTLS) <= vers && vers <= c.maxVersion(isDTLS) } // getCertificateForName returns the best certificate for the given name, diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index f532237c..84e1eb84 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -1345,7 +1345,9 @@ func (c *Conn) Write(b []byte) (int, error) { } if c.config.Bugs.SendKeyUpdateBeforeEveryAppDataRecord { - c.sendKeyUpdateLocked() + if err := c.sendKeyUpdateLocked(); err != nil { + return 0, err + } } // SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext @@ -1400,6 +1402,23 @@ func (c *Conn) handlePostHandshakeMessage() error { return nil } + 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 { + return nil + } + session := &ClientSessionState{ sessionTicket: newSessionTicket.ticket, vers: c.vers, @@ -1410,8 +1429,6 @@ func (c *Conn) handlePostHandshakeMessage() error { ocspResponse: c.ocspResponse, ticketCreationTime: c.config.time(), ticketExpiration: c.config.time().Add(time.Duration(newSessionTicket.ticketLifetime) * time.Second), - ticketFlags: newSessionTicket.ticketFlags, - ticketAgeAdd: newSessionTicket.ticketAgeAdd, } cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config) @@ -1691,17 +1708,19 @@ func (c *Conn) SendNewSessionTicket() error { peerCertificatesRaw = append(peerCertificatesRaw, cert.Raw) } - var ageAdd uint32 - if err := binary.Read(c.config.rand(), binary.LittleEndian, &ageAdd); err != nil { - return err - } - // TODO(davidben): Allow configuring these values. m := &newSessionTicketMsg{ version: c.vers, ticketLifetime: uint32(24 * time.Hour / time.Second), - ticketFlags: ticketAllowDHEResumption | ticketAllowPSKResumption, - ticketAgeAdd: ageAdd, + keModes: []byte{pskDHEKEMode}, + authModes: []byte{pskAuthMode}, + } + + 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 } state := sessionState{ @@ -1711,8 +1730,6 @@ func (c *Conn) SendNewSessionTicket() error { certificates: peerCertificatesRaw, ticketCreationTime: c.config.time(), ticketExpiration: c.config.time().Add(time.Duration(m.ticketLifetime) * time.Second), - ticketFlags: m.ticketFlags, - ticketAgeAdd: ageAdd, } if !c.config.Bugs.SendEmptySessionTicket { @@ -1736,6 +1753,10 @@ func (c *Conn) SendKeyUpdate() error { } func (c *Conn) sendKeyUpdateLocked() error { + if c.vers < VersionTLS13 { + return errors.New("tls: attempted to send KeyUpdate before TLS 1.3") + } + m := new(keyUpdateMsg) if _, err := c.writeRecord(recordTypeHandshake, m.marshal()); err != nil { return err diff --git a/src/ssl/test/runner/dtls.go b/src/ssl/test/runner/dtls.go index 788bec86..e273bc79 100644 --- a/src/ssl/test/runner/dtls.go +++ b/src/ssl/test/runner/dtls.go @@ -25,16 +25,42 @@ import ( func versionToWire(vers uint16, isDTLS bool) uint16 { if isDTLS { - return ^(vers - 0x0201) + switch vers { + case VersionTLS12: + return 0xfefd + case VersionTLS10: + return 0xfeff + } + } else { + switch vers { + case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12: + return vers + case VersionTLS13: + return tls13DraftVersion + } } - return vers + + panic("unknown version") } -func wireToVersion(vers uint16, isDTLS bool) uint16 { +func wireToVersion(vers uint16, isDTLS bool) (uint16, bool) { if isDTLS { - return ^vers + 0x0201 + switch vers { + case 0xfefd: + return VersionTLS12, true + case 0xfeff: + return VersionTLS10, true + } + } else { + switch vers { + case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12: + return vers, true + case tls13DraftVersion: + return VersionTLS13, true + } } - return vers + + return 0, false } func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) { @@ -70,15 +96,15 @@ func (c *Conn) dtlsDoReadRecord(want recordType) (recordType, *block, error) { return 0, nil, errors.New("dtls: failed to read record header") } typ := recordType(b.data[0]) - vers := wireToVersion(uint16(b.data[1])<<8|uint16(b.data[2]), c.isDTLS) + vers := uint16(b.data[1])<<8 | uint16(b.data[2]) // Alerts sent near version negotiation do not have a well-defined // record-layer version prior to TLS 1.3. (In TLS 1.3, the record-layer // version is irrelevant.) if typ != recordTypeAlert { if c.haveVers { - if vers != c.vers { + if wireVers := versionToWire(c.vers, c.isDTLS); vers != wireVers { c.sendAlert(alertProtocolVersion) - return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, c.vers)) + return 0, nil, c.in.setErrorLocked(fmt.Errorf("dtls: received record with version %x when expecting version %x", vers, wireVers)) } } else { // Pre-version-negotiation alerts may be sent with any version. diff --git a/src/ssl/test/runner/fuzzer_mode.json b/src/ssl/test/runner/fuzzer_mode.json new file mode 100644 index 00000000..94903c5a --- /dev/null +++ b/src/ssl/test/runner/fuzzer_mode.json @@ -0,0 +1,26 @@ +{ + "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.", + + "BadRSAClientKeyExchange*": "Fuzzer mode does not notice a bad premaster secret.", + "CECPQ1-*-BadNewhopePart": "Fuzzer mode does not notice a bad premaster secret.", + "CECPQ1-*-BadX25519Part": "Fuzzer mode does not notice a bad premaster secret.", + + "TrailingMessageData-TLS13-ServerHello": "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", + + "*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." + } +} diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index c5c4495c..c5be2b76 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -57,9 +57,11 @@ func (c *Conn) clientHandshake() error { return errors.New("tls: NextProtos values too large") } + minVersion := c.config.minVersion(c.isDTLS) + maxVersion := c.config.maxVersion(c.isDTLS) hello := &clientHelloMsg{ isDTLS: c.isDTLS, - vers: c.config.maxVersion(c.isDTLS), + vers: versionToWire(maxVersion, c.isDTLS), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, @@ -73,7 +75,7 @@ func (c *Conn) clientHandshake() error { duplicateExtension: c.config.Bugs.DuplicateExtension, channelIDSupported: c.config.ChannelID != nil, npnLast: c.config.Bugs.SwapNPNAndALPN, - extendedMasterSecret: c.config.maxVersion(c.isDTLS) >= VersionTLS10, + extendedMasterSecret: maxVersion >= VersionTLS10, srtpProtectionProfiles: c.config.SRTPProtectionProfiles, srtpMasterKeyIdentifier: c.config.Bugs.SRTPMasterKeyIdentifer, customExtension: c.config.Bugs.CustomExtension, @@ -110,7 +112,7 @@ func (c *Conn) clientHandshake() error { } var keyShares map[CurveID]ecdhCurve - if hello.vers >= VersionTLS13 { + if maxVersion >= VersionTLS13 { keyShares = make(map[CurveID]ecdhCurve) hello.hasKeyShares = true hello.trailingKeyShareData = c.config.Bugs.TrailingKeyShareData @@ -160,22 +162,24 @@ NextCipherSuite: if suite.id != suiteId { continue } - if !c.config.Bugs.EnableAllCiphers { - // Don't advertise TLS 1.2-only cipher suites unless - // we're attempting TLS 1.2. - if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 { - continue - } - // Don't advertise non-DTLS cipher suites in DTLS. - if c.isDTLS && suite.flags&suiteNoDTLS != 0 { - continue - } + // Don't advertise TLS 1.2-only cipher suites unless + // we're attempting TLS 1.2. + if maxVersion < VersionTLS12 && suite.flags&suiteTLS12 != 0 { + continue + } + // Don't advertise non-DTLS cipher suites in DTLS. + if c.isDTLS && suite.flags&suiteNoDTLS != 0 { + continue } hello.cipherSuites = append(hello.cipherSuites, suiteId) continue NextCipherSuite } } + if c.config.Bugs.AdvertiseAllConfiguredCiphers { + hello.cipherSuites = possibleCipherSuites + } + if c.config.Bugs.SendRenegotiationSCSV { hello.cipherSuites = append(hello.cipherSuites, renegotiationSCSV) } @@ -190,7 +194,7 @@ NextCipherSuite: return errors.New("tls: short read from Rand: " + err.Error()) } - if hello.vers >= VersionTLS12 && !c.config.Bugs.NoSignatureAlgorithms { + if maxVersion >= VersionTLS12 && !c.config.Bugs.NoSignatureAlgorithms { hello.signatureAlgorithms = c.config.verifySignatureAlgorithms() } @@ -213,29 +217,15 @@ NextCipherSuite: // Check that the ciphersuite/version used for the // previous session are still valid. cipherSuiteOk := false - if candidateSession.vers >= VersionTLS13 { - // Account for ciphers changing on resumption. - // - // TODO(davidben): This will be gone with the - // new cipher negotiation scheme. - resumeCipher := ecdhePSKSuite(candidateSession.cipherSuite) - for _, id := range hello.cipherSuites { - if ecdhePSKSuite(id) == resumeCipher { - cipherSuiteOk = true - break - } - } - } else { - for _, id := range hello.cipherSuites { - if id == candidateSession.cipherSuite { - cipherSuiteOk = true - break - } + for _, id := range hello.cipherSuites { + if id == candidateSession.cipherSuite { + cipherSuiteOk = true + break } } - versOk := candidateSession.vers >= c.config.minVersion(c.isDTLS) && - candidateSession.vers <= c.config.maxVersion(c.isDTLS) + versOk := candidateSession.vers >= minVersion && + candidateSession.vers <= maxVersion if ticketOk && versOk && cipherSuiteOk { session = candidateSession } @@ -257,10 +247,19 @@ NextCipherSuite: if session.vers >= VersionTLS13 || c.config.Bugs.SendBothTickets { // TODO(nharper): Support sending more // than one PSK identity. - if session.ticketFlags&ticketAllowDHEResumption != 0 || c.config.Bugs.SendBothTickets { - hello.pskIdentities = [][]uint8{ticket} - hello.cipherSuites = append(hello.cipherSuites, ecdhePSKSuite(session.cipherSuite)) + 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 } + + hello.pskIdentities = []pskIdentity{psk} } if session.vers < VersionTLS13 || c.config.Bugs.SendBothTickets { @@ -284,6 +283,19 @@ NextCipherSuite: } } + if maxVersion == VersionTLS13 && !c.config.Bugs.OmitSupportedVersions { + if hello.vers >= VersionTLS13 { + hello.vers = VersionTLS12 + } + for version := maxVersion; version >= minVersion; version-- { + hello.supportedVersions = append(hello.supportedVersions, versionToWire(version, c.isDTLS)) + } + } + + if len(c.config.Bugs.SendSupportedVersions) > 0 { + hello.supportedVersions = c.config.Bugs.SendSupportedVersions + } + if c.config.Bugs.SendClientVersion != 0 { hello.vers = c.config.Bugs.SendClientVersion } @@ -352,23 +364,26 @@ NextCipherSuite: } } - var serverVersion uint16 + var serverWireVersion uint16 switch m := msg.(type) { case *helloRetryRequestMsg: - serverVersion = m.vers + serverWireVersion = m.vers case *serverHelloMsg: - serverVersion = m.vers + serverWireVersion = m.vers default: c.sendAlert(alertUnexpectedMessage) return fmt.Errorf("tls: received unexpected message of type %T when waiting for HelloRetryRequest or ServerHello", msg) } - var ok bool - c.vers, ok = c.config.mutualVersion(serverVersion, c.isDTLS) + serverVersion, ok := wireToVersion(serverWireVersion, c.isDTLS) + if ok { + ok = c.config.isSupportedVersion(serverVersion, c.isDTLS) + } if !ok { c.sendAlert(alertProtocolVersion) return fmt.Errorf("tls: server selected unsupported protocol version %x", c.vers) } + c.vers = serverVersion c.haveVers = true helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg) @@ -427,9 +442,9 @@ NextCipherSuite: return unexpectedMessageError(serverHello, msg) } - if c.vers != serverHello.vers { + if serverWireVersion != serverHello.vers { c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: server sent non-matching version %x vs %x", serverHello.vers, c.vers) + return fmt.Errorf("tls: server sent non-matching version %x vs %x", serverWireVersion, serverHello.vers) } // Check for downgrade signals in the server random, per @@ -576,10 +591,10 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // TODO(davidben): This will need to be handled slightly earlier once // 0-RTT is implemented. var psk []byte - if hs.suite.flags&suitePSK != 0 { - if !hs.serverHello.hasPSKIdentity { - c.sendAlert(alertMissingExtension) - return errors.New("tls: server omitted the PSK identity extension") + 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. @@ -587,17 +602,17 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.sendAlert(alertUnknownPSKIdentity) return errors.New("tls: server sent unknown PSK identity") } - if ecdhePSKSuite(hs.session.cipherSuite) != hs.suite.id { + if hs.session.cipherSuite != hs.suite.id { c.sendAlert(alertHandshakeFailure) - return errors.New("tls: server sent invalid cipher suite for PSK") + return errors.New("tls: server sent invalid cipher suite") } psk = deriveResumptionPSK(hs.suite, hs.session.masterSecret) hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.session.masterSecret)) c.didResume = true } else { - if hs.serverHello.hasPSKIdentity { + if !hs.serverHello.useCertAuth || !hs.serverHello.hasKeyShare { c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent unexpected PSK identity") + return errors.New("tls: server omitted KeyShare and SignatureAlgorithms on non-resumption.") } psk = zeroSecret @@ -608,12 +623,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // Resolve ECDHE and compute the handshake secret. var ecdheSecret []byte - if hs.suite.flags&suiteECDHE != 0 && !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare { - if !hs.serverHello.hasKeyShare { - c.sendAlert(alertMissingExtension) - return errors.New("tls: server omitted the key share extension") - } - + if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare { curve, ok := hs.keyShares[hs.serverHello.keyShare.group] if !ok { c.sendAlert(alertHandshakeFailure) @@ -627,11 +637,6 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { return err } } else { - if hs.serverHello.hasKeyShare { - c.sendAlert(alertUnsupportedExtension) - return errors.New("tls: server sent unexpected key share extension") - } - ecdheSecret = zeroSecret } @@ -662,7 +667,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { var chainToSend *Certificate var certReq *certificateRequestMsg - if hs.suite.flags&suitePSK != 0 { + if !hs.serverHello.useCertAuth { if encryptedExtensions.extensions.ocspResponse != nil { c.sendAlert(alertUnsupportedExtension) return errors.New("tls: server sent OCSP response without a certificate") @@ -1349,6 +1354,9 @@ func (hs *clientHandshakeState) sendFinished(out []byte, isResume bool) error { 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 diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go index 63290fb4..19578e88 100644 --- a/src/ssl/test/runner/handshake_messages.go +++ b/src/ssl/test/runner/handshake_messages.go @@ -124,6 +124,12 @@ type keyShareEntry struct { keyExchange []byte } +type pskIdentity struct { + keModes []byte + authModes []byte + ticket []uint8 +} + type clientHelloMsg struct { raw []byte isDTLS bool @@ -143,12 +149,13 @@ type clientHelloMsg struct { hasKeyShares bool keyShares []keyShareEntry trailingKeyShareData bool - pskIdentities [][]uint8 + pskIdentities []pskIdentity hasEarlyData bool earlyDataContext []byte ticketSupported bool sessionTicket []uint8 signatureAlgorithms []signatureAlgorithm + supportedVersions []uint16 secureRenegotiation []byte alpnProtocols []string duplicateExtension bool @@ -159,6 +166,7 @@ type clientHelloMsg struct { srtpMasterKeyIdentifier string sctListSupported bool customExtension string + hasGREASEExtension bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -183,12 +191,13 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.hasKeyShares == m1.hasKeyShares && eqKeyShareEntryLists(m.keyShares, m1.keyShares) && m.trailingKeyShareData == m1.trailingKeyShareData && - eqByteSlices(m.pskIdentities, m1.pskIdentities) && + eqPSKIdentityLists(m.pskIdentities, m1.pskIdentities) && m.hasEarlyData == m1.hasEarlyData && bytes.Equal(m.earlyDataContext, m1.earlyDataContext) && m.ticketSupported == m1.ticketSupported && bytes.Equal(m.sessionTicket, m1.sessionTicket) && eqSignatureAlgorithms(m.signatureAlgorithms, m1.signatureAlgorithms) && + eqUint16s(m.supportedVersions, m1.supportedVersions) && bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) && eqStrings(m.alpnProtocols, m1.alpnProtocols) && @@ -199,7 +208,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool { eqUint16s(m.srtpProtectionProfiles, m1.srtpProtectionProfiles) && m.srtpMasterKeyIdentifier == m1.srtpMasterKeyIdentifier && m.sctListSupported == m1.sctListSupported && - m.customExtension == m1.customExtension + m.customExtension == m1.customExtension && + m.hasGREASEExtension == m1.hasGREASEExtension } func (m *clientHelloMsg) marshal() []byte { @@ -210,8 +220,7 @@ func (m *clientHelloMsg) marshal() []byte { handshakeMsg := newByteBuilder() handshakeMsg.addU8(typeClientHello) hello := handshakeMsg.addU24LengthPrefixed() - vers := versionToWire(m.vers, m.isDTLS) - hello.addU16(vers) + hello.addU16(m.vers) hello.addBytes(m.random) sessionId := hello.addU8LengthPrefixed() sessionId.addBytes(m.sessionId) @@ -313,8 +322,9 @@ func (m *clientHelloMsg) marshal() []byte { pskIdentities := pskExtension.addU16LengthPrefixed() for _, psk := range m.pskIdentities { - pskIdentity := pskIdentities.addU16LengthPrefixed() - pskIdentity.addBytes(psk) + pskIdentities.addU8LengthPrefixed().addBytes(psk.keModes) + pskIdentities.addU8LengthPrefixed().addBytes(psk.authModes) + pskIdentities.addU16LengthPrefixed().addBytes(psk.ticket) } } if m.hasEarlyData { @@ -339,6 +349,14 @@ func (m *clientHelloMsg) marshal() []byte { signatureAlgorithms.addU16(uint16(sigAlg)) } } + if len(m.supportedVersions) > 0 { + extensions.addU16(extensionSupportedVersions) + supportedVersionsExtension := extensions.addU16LengthPrefixed() + supportedVersions := supportedVersionsExtension.addU8LengthPrefixed() + for _, version := range m.supportedVersions { + supportedVersions.addU16(uint16(version)) + } + } if m.secureRenegotiation != nil { extensions.addU16(extensionRenegotiationInfo) secureRenegoExt := extensions.addU16LengthPrefixed() @@ -399,11 +417,6 @@ func (m *clientHelloMsg) marshal() []byte { customExt := extensions.addU16LengthPrefixed() customExt.addBytes([]byte(m.customExtension)) } - if m.vers == VersionTLS13 { - extensions.addU16(extensionTLS13Draft) - extValue := extensions.addU16LengthPrefixed() - extValue.addU16(tls13DraftVersion) - } if extensions.len() == 0 { hello.discardChild() @@ -418,7 +431,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.raw = data - m.vers = wireToVersion(uint16(data[4])<<8|uint16(data[5]), m.isDTLS) + m.vers = uint16(data[4])<<8 | uint16(data[5]) m.random = data[6:38] sessionIdLen := int(data[38]) if sessionIdLen > 32 || len(data) < 39+sessionIdLen { @@ -476,6 +489,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.ticketSupported = false m.sessionTicket = nil m.signatureAlgorithms = nil + m.supportedVersions = nil m.alpnProtocols = nil m.extendedMasterSecret = false m.customExtension = "" @@ -605,15 +619,39 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } d := data[2:length] for len(d) > 0 { + var psk pskIdentity + + if len(d) < 1 { + return false + } + keModesLen := int(d[0]) + d = d[1:] + if len(d) < keModesLen { + return false + } + psk.keModes = d[:keModesLen] + d = d[keModesLen:] + + if len(d) < 1 { + return false + } + authModesLen := int(d[0]) + d = d[1:] + if len(d) < authModesLen { + 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:] + if len(d) < pskLen { return false } - psk := d[:pskLen] + psk.ticket = d[:pskLen] m.pskIdentities = append(m.pskIdentities, psk) d = d[pskLen:] } @@ -644,6 +682,21 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.signatureAlgorithms[i] = signatureAlgorithm(d[0])<<8 | signatureAlgorithm(d[1]) d = d[2:] } + case extensionSupportedVersions: + if length < 1+2 { + return false + } + l := int(data[0]) + if l != length-1 || l%2 == 1 || l < 2 { + return false + } + n := l / 2 + d := data[1:] + m.supportedVersions = make([]uint16, n) + for i := range m.supportedVersions { + m.supportedVersions[i] = uint16(d[0])<<8 | uint16(d[1]) + d = d[2:] + } case extensionRenegotiationInfo: if length < 1 || length != int(data[0])+1 { return false @@ -705,6 +758,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.customExtension = string(data[:length]) } data = data[length:] + + if isGREASEValue(extension) { + m.hasGREASEExtension = true + } } return true @@ -714,6 +771,7 @@ type serverHelloMsg struct { raw []byte isDTLS bool vers uint16 + versOverride uint16 random []byte sessionId []byte cipherSuite uint16 @@ -721,6 +779,7 @@ type serverHelloMsg struct { keyShare keyShareEntry hasPSKIdentity bool pskIdentity uint16 + useCertAuth bool earlyDataIndication bool compressionMethod uint8 extensions serverExtensions @@ -734,21 +793,33 @@ func (m *serverHelloMsg) marshal() []byte { handshakeMsg := newByteBuilder() handshakeMsg.addU8(typeServerHello) hello := handshakeMsg.addU24LengthPrefixed() - vers := versionToWire(m.vers, m.isDTLS) - hello.addU16(vers) + + // m.vers is used both to determine the format of the rest of the + // ServerHello and to override the value, so include a second version + // field. + vers, ok := wireToVersion(m.vers, m.isDTLS) + if !ok { + panic("unknown version") + } + if m.versOverride != 0 { + hello.addU16(m.versOverride) + } else { + hello.addU16(m.vers) + } + hello.addBytes(m.random) - if m.vers < VersionTLS13 { + if vers < VersionTLS13 { sessionId := hello.addU8LengthPrefixed() sessionId.addBytes(m.sessionId) } hello.addU16(m.cipherSuite) - if m.vers < VersionTLS13 { + if vers < VersionTLS13 { hello.addU8(m.compressionMethod) } extensions := hello.addU16LengthPrefixed() - if m.vers >= VersionTLS13 { + if vers >= VersionTLS13 { if m.hasKeyShare { extensions.addU16(extensionKeyShare) keyShare := extensions.addU16LengthPrefixed() @@ -761,12 +832,16 @@ 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 } } else { - m.extensions.marshal(extensions, m.vers) + m.extensions.marshal(extensions, vers) if extensions.len() == 0 { hello.discardChild() } @@ -781,10 +856,14 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } m.raw = data - m.vers = wireToVersion(uint16(data[4])<<8|uint16(data[5]), m.isDTLS) + m.vers = uint16(data[4])<<8 | uint16(data[5]) + vers, ok := wireToVersion(m.vers, m.isDTLS) + if !ok { + return false + } m.random = data[6:38] data = data[38:] - if m.vers < VersionTLS13 { + if vers < VersionTLS13 { sessionIdLen := int(data[0]) if sessionIdLen > 32 || len(data) < 1+sessionIdLen { return false @@ -797,7 +876,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } m.cipherSuite = uint16(data[0])<<8 | uint16(data[1]) data = data[2:] - if m.vers < VersionTLS13 { + if vers < VersionTLS13 { if len(data) < 1 { return false } @@ -820,7 +899,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } - if m.vers >= VersionTLS13 { + if vers >= VersionTLS13 { for len(data) != 0 { if len(data) < 4 { return false @@ -854,6 +933,11 @@ 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 @@ -865,7 +949,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } } - } else if !m.extensions.unmarshal(data, m.vers) { + } else if !m.extensions.unmarshal(data, vers) { return false } @@ -1738,8 +1822,8 @@ type newSessionTicketMsg struct { raw []byte version uint16 ticketLifetime uint32 - ticketFlags uint32 - ticketAgeAdd uint32 + keModes []byte + authModes []byte ticket []byte } @@ -1754,16 +1838,20 @@ func (m *newSessionTicketMsg) marshal() []byte { body := ticketMsg.addU24LengthPrefixed() body.addU32(m.ticketLifetime) if m.version >= VersionTLS13 { - body.addU32(m.ticketFlags) - body.addU32(m.ticketAgeAdd) + body.addU8LengthPrefixed().addBytes(m.keModes) + body.addU8LengthPrefixed().addBytes(m.authModes) + } + + ticket := body.addU16LengthPrefixed() + ticket.addBytes(m.ticket) + + if m.version >= VersionTLS13 { // Send no extensions. // // TODO(davidben): Add an option to send a custom extension to // test we correctly ignore unknown ones. body.addU16(0) } - ticket := body.addU16LengthPrefixed() - ticket.addBytes(m.ticket) m.raw = ticketMsg.finish() return m.raw @@ -1779,31 +1867,58 @@ func (m *newSessionTicketMsg) unmarshal(data []byte) bool { data = data[8:] if m.version >= VersionTLS13 { - if len(data) < 10 { + if len(data) < 1 { return false } - m.ticketFlags = uint32(data[0])<<24 | uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) - m.ticketAgeAdd = uint32(data[4])<<24 | uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) - extsLength := int(data[8])<<8 + int(data[9]) - data = data[10:] - if len(data) < extsLength { + keModesLength := int(data[0]) + if len(data)-1 < keModesLength { return false } - data = data[extsLength:] + 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 { + return false + } + m.authModes = data[1 : 1+authModesLength] + data = data[1+authModesLength:] } if len(data) < 2 { return false } ticketLen := int(data[0])<<8 + int(data[1]) - if len(data)-2 != ticketLen { + data = data[2:] + if len(data) < ticketLen { return false } + if m.version >= VersionTLS13 && ticketLen == 0 { return false } - m.ticket = data[2:] + m.ticket = data[:ticketLen] + data = data[ticketLen:] + + if m.version >= VersionTLS13 { + if len(data) < 2 { + return false + } + extsLength := int(data[0])<<8 + int(data[1]) + data = data[2:] + if len(data) < extsLength { + return false + } + data = data[extsLength:] + } + + if len(data) > 0 { + return false + } return true } @@ -1867,7 +1982,7 @@ func (m *helloVerifyRequestMsg) marshal() []byte { x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) - vers := versionToWire(m.vers, true) + vers := m.vers x[4] = uint8(vers >> 8) x[5] = uint8(vers) x[6] = uint8(len(m.cookie)) @@ -1881,7 +1996,7 @@ func (m *helloVerifyRequestMsg) unmarshal(data []byte) bool { return false } m.raw = data - m.vers = wireToVersion(uint16(data[4])<<8|uint16(data[5]), true) + m.vers = uint16(data[4])<<8 | uint16(data[5]) cookieLen := int(data[6]) if cookieLen > 32 || len(data) != 7+cookieLen { return false @@ -2028,3 +2143,16 @@ func eqKeyShareEntryLists(x, y []keyShareEntry) bool { return true } + +func eqPSKIdentityLists(x, y []pskIdentity) bool { + if len(x) != len(y) { + 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) { + return false + } + } + return true + +} diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index e04075cd..7c2fd179 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -204,15 +204,77 @@ func (hs *serverHandshakeState) readClientHello() error { return fmt.Errorf("tls: client offered different version on renego") } } + c.clientVersion = hs.clientHello.vers + // Convert the ClientHello wire version to a protocol version. + var clientVersion uint16 + if c.isDTLS { + if hs.clientHello.vers <= 0xfefd { + clientVersion = VersionTLS12 + } else if hs.clientHello.vers <= 0xfeff { + clientVersion = VersionTLS10 + } + } else { + if hs.clientHello.vers >= VersionTLS12 { + clientVersion = VersionTLS12 + } else if hs.clientHello.vers >= VersionTLS11 { + clientVersion = VersionTLS11 + } else if hs.clientHello.vers >= VersionTLS10 { + clientVersion = VersionTLS10 + } else if hs.clientHello.vers >= VersionSSL30 { + clientVersion = VersionSSL30 + } + } + + if config.Bugs.NegotiateVersion != 0 { + c.vers = config.Bugs.NegotiateVersion + } else if c.haveVers && config.Bugs.NegotiateVersionOnRenego != 0 { + c.vers = config.Bugs.NegotiateVersionOnRenego + } else if len(hs.clientHello.supportedVersions) > 0 { + // Use the versions extension if supplied. + var foundVersion, foundGREASE bool + for _, extVersion := range hs.clientHello.supportedVersions { + if isGREASEValue(extVersion) { + foundGREASE = true + } + extVersion, ok = wireToVersion(extVersion, c.isDTLS) + if !ok { + continue + } + if config.isSupportedVersion(extVersion, c.isDTLS) && !foundVersion { + c.vers = extVersion + foundVersion = true + break + } + } + if !foundVersion { + c.sendAlert(alertProtocolVersion) + return errors.New("tls: client did not offer any supported protocol versions") + } + if config.Bugs.ExpectGREASE && !foundGREASE { + return errors.New("tls: no GREASE version value found") + } + } else { + // Otherwise, use the legacy ClientHello version. + version := clientVersion + if maxVersion := config.maxVersion(c.isDTLS); version > maxVersion { + version = maxVersion + } + if version == 0 || !config.isSupportedVersion(version, c.isDTLS) { + return fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers) + } + c.vers = version + } + c.haveVers = true + // Reject < 1.2 ClientHellos with signature_algorithms. - if c.clientVersion < VersionTLS12 && len(hs.clientHello.signatureAlgorithms) > 0 { + if clientVersion < VersionTLS12 && len(hs.clientHello.signatureAlgorithms) > 0 { return fmt.Errorf("tls: client included signature_algorithms before TLS 1.2") } // Check the client cipher list is consistent with the version. - if hs.clientHello.vers < VersionTLS12 { + if clientVersion < VersionTLS12 { for _, id := range hs.clientHello.cipherSuites { if isTLS12Cipher(id) { return fmt.Errorf("tls: client offered TLS 1.2 cipher before TLS 1.2") @@ -233,24 +295,13 @@ func (hs *serverHandshakeState) readClientHello() error { return fmt.Errorf("tls: client offered unexpected PSK identities") } - if config.Bugs.NegotiateVersion != 0 { - c.vers = config.Bugs.NegotiateVersion - } else if c.haveVers && config.Bugs.NegotiateVersionOnRenego != 0 { - c.vers = config.Bugs.NegotiateVersionOnRenego - } else { - c.vers, ok = config.mutualVersion(hs.clientHello.vers, c.isDTLS) - if !ok { - c.sendAlert(alertProtocolVersion) - return fmt.Errorf("tls: client offered an unsupported, maximum protocol version of %x", hs.clientHello.vers) - } - } - c.haveVers = true - - var scsvFound bool + var scsvFound, greaseFound bool for _, cipherSuite := range hs.clientHello.cipherSuites { if cipherSuite == fallbackSCSV { scsvFound = true - break + } + if isGREASEValue(cipherSuite) { + greaseFound = true } } @@ -260,6 +311,36 @@ func (hs *serverHandshakeState) readClientHello() error { return errors.New("tls: fallback SCSV found when not expected") } + if !greaseFound && config.Bugs.ExpectGREASE { + return errors.New("tls: no GREASE cipher suite value found") + } + + greaseFound = false + for _, curve := range hs.clientHello.supportedCurves { + if isGREASEValue(uint16(curve)) { + greaseFound = true + break + } + } + + if !greaseFound && config.Bugs.ExpectGREASE { + return errors.New("tls: no GREASE curve value found") + } + + if len(hs.clientHello.keyShares) > 0 { + greaseFound = false + for _, keyShare := range hs.clientHello.keyShares { + if isGREASEValue(uint16(keyShare.group)) { + greaseFound = true + break + } + } + + if !greaseFound && config.Bugs.ExpectGREASE { + return errors.New("tls: no GREASE curve value found") + } + } + if config.Bugs.IgnorePeerSignatureAlgorithmPreferences { hs.clientHello.signatureAlgorithms = config.signSignatureAlgorithms() } @@ -278,12 +359,9 @@ func (hs *serverHandshakeState) doTLS13Handshake() error { config := c.config hs.hello = &serverHelloMsg{ - isDTLS: c.isDTLS, - vers: c.vers, - } - - if config.Bugs.SendServerHelloVersion != 0 { - hs.hello.vers = config.Bugs.SendServerHelloVersion + isDTLS: c.isDTLS, + vers: versionToWire(c.vers, c.isDTLS), + versOverride: config.Bugs.SendServerHelloVersion, } hs.hello.random = make([]byte, 32) @@ -318,60 +396,89 @@ Curves: } } - _, ecdsaOk := hs.cert.PrivateKey.(*ecdsa.PrivateKey) + if !supportedCurve { + c.sendAlert(alertHandshakeFailure) + return errors.New("tls: no curve supported by both client and server") + } pskIdentities := hs.clientHello.pskIdentities if len(pskIdentities) == 0 && len(hs.clientHello.sessionTicket) > 0 && c.config.Bugs.AcceptAnySession { - pskIdentities = [][]uint8{hs.clientHello.sessionTicket} + psk := pskIdentity{ + keModes: []byte{pskDHEKEMode}, + authModes: []byte{pskAuthMode}, + ticket: hs.clientHello.sessionTicket, + } + pskIdentities = []pskIdentity{psk} } for i, pskIdentity := range pskIdentities { - sessionState, ok := c.decryptTicket(pskIdentity) + 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 { + 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.ticketFlags&ticketAllowDHEResumption == 0 { + if sessionState.ticketExpiration.Before(c.config.time()) { continue } - if sessionState.ticketExpiration.Before(c.config.time()) { + + 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 !cipherSuiteOk { continue } } - suiteId := ecdhePSKSuite(sessionState.cipherSuite) - - // Check the client offered the cipher. - clientCipherSuites := hs.clientHello.cipherSuites - if config.Bugs.AcceptAnySession { - clientCipherSuites = []uint16{suiteId} - } - suite := mutualCipherSuite(clientCipherSuites, suiteId) - - // Check the cipher is enabled by the server or is a resumption - // suite of one enabled by the server. Account for the cipher - // change on resume. - // - // TODO(davidben): The ecdhePSKSuite mess will be gone with the - // new cipher negotiation scheme. - var found bool - for _, id := range config.cipherSuites() { - if ecdhePSKSuite(id) == suiteId { - found = true - break - } + // 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 } - if suite != nil && found { - hs.sessionState = sessionState - hs.suite = suite - hs.hello.hasPSKIdentity = true - hs.hello.pskIdentity = uint16(i) - c.didResume = true - break + 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 } + c.didResume = true + break + } + + if config.Bugs.AlwaysSelectPSKIdentity { + hs.hello.hasPSKIdentity = true + hs.hello.pskIdentity = 0 } // If not resuming, select the cipher suite. @@ -386,7 +493,7 @@ Curves: } for _, id := range preferenceList { - if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, supportedCurve, ecdsaOk, false); hs.suite != nil { + if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, true, true); hs.suite != nil { break } } @@ -406,14 +513,11 @@ Curves: hs.finishedHash.discardHandshakeBuffer() hs.writeClientHash(hs.clientHello.marshal()) + hs.hello.useCertAuth = hs.sessionState == nil + // Resolve PSK and compute the early secret. var psk []byte - // The only way for hs.suite to be a PSK suite yet for there to be - // no sessionState is if config.Bugs.EnableAllCiphers is true and - // the test runner forced us to negotiated a PSK suite. It doesn't - // really matter what we do here so long as we continue the - // handshake and let the client error out. - if hs.suite.flags&suitePSK != 0 && hs.sessionState != nil { + if hs.sessionState != nil { psk = deriveResumptionPSK(hs.suite, hs.sessionState.masterSecret) hs.finishedHash.setResumptionContext(deriveResumptionContext(hs.suite, hs.sessionState.masterSecret)) } else { @@ -423,9 +527,23 @@ Curves: 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 + } + if config.Bugs.MissingKeyShare { + hs.hello.hasKeyShare = false + } + // Resolve ECDHE and compute the handshake secret. var ecdheSecret []byte - if hs.suite.flags&suiteECDHE != 0 && !config.Bugs.MissingKeyShare { + if hs.hello.hasKeyShare { // Look for the key share corresponding to our selected curve. var selectedKeyShare *keyShareEntry for i := range hs.clientHello.keyShares { @@ -451,7 +569,7 @@ Curves: ResendHelloRetryRequest: // Send HelloRetryRequest. helloRetryRequestMsg := helloRetryRequestMsg{ - vers: c.vers, + vers: versionToWire(c.vers, c.isDTLS), cipherSuite: hs.hello.cipherSuite, selectedGroup: selectedCurve, } @@ -577,13 +695,20 @@ Curves: c.out.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, serverWrite) c.in.useTrafficSecret(c.vers, hs.suite, handshakeTrafficSecret, handshakePhase, clientWrite) - if hs.suite.flags&suitePSK == 0 { + 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 + } } // Send EncryptedExtensions. @@ -595,7 +720,7 @@ Curves: c.writeRecord(recordTypeHandshake, encryptedExtensions.marshal()) } - if hs.suite.flags&suitePSK == 0 { + if hs.hello.useCertAuth { if config.ClientAuth >= RequestClientCert { // Request a client certificate certReq := &certificateRequestMsg{ @@ -656,11 +781,9 @@ Curves: hs.writeServerHash(certVerify.marshal()) c.writeRecord(recordTypeHandshake, certVerify.marshal()) - } else { + } else if hs.sessionState != nil { // Pick up certificates from the session instead. - // hs.sessionState may be nil if config.Bugs.EnableAllCiphers is - // true. - if hs.sessionState != nil && len(hs.sessionState.certificates) > 0 { + if len(hs.sessionState.certificates) > 0 { if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil { return err } @@ -784,14 +907,11 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error) hs.hello = &serverHelloMsg{ isDTLS: c.isDTLS, - vers: c.vers, + vers: versionToWire(c.vers, c.isDTLS), + versOverride: config.Bugs.SendServerHelloVersion, compressionMethod: compressionNone, } - if config.Bugs.SendServerHelloVersion != 0 { - hs.hello.vers = config.Bugs.SendServerHelloVersion - } - hs.hello.random = make([]byte, 32) _, err = io.ReadFull(config.rand(), hs.hello.random) if err != nil { @@ -872,7 +992,7 @@ Curves: } for _, id := range preferenceList { - if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk, true); hs.suite != nil { + if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil { break } } @@ -1002,6 +1122,10 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server serverExtensions.ticketSupported = true } + if !hs.clientHello.hasGREASEExtension && config.Bugs.ExpectGREASE { + return errors.New("tls: no GREASE extension found") + } + return nil } @@ -1011,7 +1135,7 @@ func (hs *serverHandshakeState) checkForResumption() bool { ticket := hs.clientHello.sessionTicket if len(ticket) == 0 && len(hs.clientHello.pskIdentities) > 0 && c.config.Bugs.AcceptAnySession { - ticket = hs.clientHello.pskIdentities[0] + ticket = hs.clientHello.pskIdentities[0].ticket } if len(ticket) > 0 { if c.config.SessionTicketsDisabled { @@ -1034,7 +1158,11 @@ func (hs *serverHandshakeState) checkForResumption() bool { } } - if !c.config.Bugs.AcceptAnySession { + if c.config.Bugs.AcceptAnySession { + // Replace the cipher suite with one known to work, to test + // cross-version resumption attempts. + hs.sessionState.cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA + } else { // Never resume a session for a different SSL version. if c.vers != hs.sessionState.vers { return false @@ -1054,7 +1182,8 @@ func (hs *serverHandshakeState) checkForResumption() bool { } // Check that we also support the ciphersuite from the session. - hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk, true) + hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), c.vers, hs.ellipticOk, hs.ecdsaOk) + if hs.suite == nil { return false } @@ -1087,6 +1216,12 @@ func (hs *serverHandshakeState) doResumeHandshake() error { hs.hello.extensions.sctList = c.config.Bugs.SendSCTListOnResume } + if c.config.Bugs.SendOCSPResponseOnResume != nil { + // There is no way, syntactically, to send an OCSP response on a + // resumption handshake. + hs.hello.extensions.ocspStapling = true + } + hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.finishedHash.discardHandshakeBuffer() hs.writeClientHash(hs.clientHello.marshal()) @@ -1620,7 +1755,7 @@ func (hs *serverHandshakeState) writeHash(msg []byte, seqno uint16) { // tryCipherSuite returns a cipherSuite with the given id if that cipher suite // is acceptable to use. -func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk, pskOk bool) *cipherSuite { +func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite { for _, supported := range supportedCipherSuites { if id == supported { var candidate *cipherSuite @@ -1634,27 +1769,26 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version if candidate == nil { continue } + // Don't select a ciphersuite which we can't // support for this client. - if !c.config.Bugs.EnableAllCiphers { - if (candidate.flags&suitePSK != 0) && !pskOk { - continue - } - if (candidate.flags&suiteECDHE != 0) && !ellipticOk { - continue - } - if (candidate.flags&suiteECDSA != 0) != ecdsaOk { - continue - } - if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { - continue - } - if version >= VersionTLS13 && candidate.flags&suiteTLS13 == 0 { - continue - } - if c.isDTLS && candidate.flags&suiteNoDTLS != 0 { + if version >= VersionTLS13 || candidate.flags&suiteTLS13 != 0 { + if version < VersionTLS13 || candidate.flags&suiteTLS13 == 0 { continue } + return candidate + } + if (candidate.flags&suiteECDHE != 0) && !ellipticOk { + continue + } + if (candidate.flags&suiteECDSA != 0) != ecdsaOk { + continue + } + if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { + continue + } + if c.isDTLS && candidate.flags&suiteNoDTLS != 0 { + continue } return candidate } @@ -1673,3 +1807,7 @@ func isTLS12Cipher(id uint16) bool { // Unknown cipher. return false } + +func isGREASEValue(val uint16) bool { + return val&0x0f0f == 0x0a0a && val&0xff == val>>8 +} diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go index 6327c134..271a9d17 100644 --- a/src/ssl/test/runner/key_agreement.go +++ b/src/ssl/test/runner/key_agreement.go @@ -40,7 +40,7 @@ type rsaKeyAgreement struct { func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { // Save the client version for comparison later. - ka.clientVersion = versionToWire(clientHello.vers, clientHello.isDTLS) + ka.clientVersion = clientHello.vers if !config.Bugs.RSAEphemeralKey { return nil, nil @@ -128,7 +128,7 @@ func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certif // RFC 4346. vers := uint16(preMasterSecret[0])<<8 | uint16(preMasterSecret[1]) if ka.clientVersion != vers { - return nil, errors.New("tls: invalid version in RSA premaster") + return nil, fmt.Errorf("tls: invalid version in RSA premaster (got %04x, wanted %04x)", vers, ka.clientVersion) } return preMasterSecret, nil } @@ -144,7 +144,6 @@ func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello if bad == RSABadValueWrongVersion { vers ^= 1 } - vers = versionToWire(vers, clientHello.isDTLS) preMasterSecret[0] = byte(vers >> 8) preMasterSecret[1] = byte(vers) _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go index 33ad75ac..5c7b3ab6 100644 --- a/src/ssl/test/runner/prf.go +++ b/src/ssl/test/runner/prf.go @@ -472,12 +472,6 @@ const ( // deriveTrafficAEAD derives traffic keys and constructs an AEAD given a traffic // secret. func deriveTrafficAEAD(version uint16, suite *cipherSuite, secret, phase []byte, side trafficDirection) interface{} { - // We may have forcibly selected a non-AEAD cipher from the - // EnableAllCiphers bug. Use the NULL cipher to avoid crashing the test. - if suite.aead == nil { - return nil - } - label := make([]byte, 0, len(phase)+2+16) label = append(label, phase...) if side == clientWrite { diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index c350ac5b..248c6eb1 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -366,7 +366,7 @@ type testCase struct { var testCases []testCase -func writeTranscript(test *testCase, isResume bool, data []byte) { +func writeTranscript(test *testCase, num int, data []byte) { if len(data) == 0 { return } @@ -387,13 +387,7 @@ func writeTranscript(test *testCase, isResume bool, data []byte) { return } - name := test.name - if isResume { - name += "-Resume" - } else { - name += "-Normal" - } - + name := fmt.Sprintf("%s-%d", test.name, num) if err := ioutil.WriteFile(path.Join(dir, name), data, 0644); err != nil { fmt.Fprintf(os.Stderr, "Error writing %s: %s\n", name, err) } @@ -419,7 +413,7 @@ func (t *timeoutConn) Write(b []byte) (int, error) { return t.Conn.Write(b) } -func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) error { +func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, num int) error { if !test.noSessionCache { if config.ClientSessionCache == nil { config.ClientSessionCache = NewLRUClientSessionCache(1) @@ -442,6 +436,9 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er if *fuzzer { config.Bugs.NullAllCiphers = true } + if *deterministic { + config.Time = func() time.Time { return time.Unix(1234, 1234) } + } conn = &timeoutConn{conn, *idleTimeout} @@ -467,7 +464,7 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er } if len(*transcriptDir) != 0 { defer func() { - writeTranscript(test, isResume, connDebug.Transcript()) + writeTranscript(test, num, connDebug.Transcript()) }() } @@ -619,7 +616,9 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool) er } for i := 0; i < test.sendKeyUpdates; i++ { - tlsConn.SendKeyUpdate() + if err := tlsConn.SendKeyUpdate(); err != nil { + return err + } } for i := 0; i < test.sendEmptyRecords; i++ { @@ -790,6 +789,14 @@ func translateExpectedError(errorStr string) string { } func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { + // Help debugging panics on the Go side. + defer func() { + if r := recover(); r != nil { + fmt.Fprintf(os.Stderr, "Test '%s' panicked.\n", test.name) + panic(r) + } + }() + if !test.shouldFail && (len(test.expectedError) > 0 || len(test.expectedLocalError) > 0) { panic("Error expected without shouldFail in " + test.name) } @@ -906,7 +913,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { conn, err := acceptOrWait(listener, waitChan) if err == nil { - err = doExchange(test, &config, conn, false /* not a resumption */) + err = doExchange(test, &config, conn, false /* not a resumption */, 0) conn.Close() } @@ -926,7 +933,7 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { var connResume net.Conn connResume, err = acceptOrWait(listener, waitChan) if err == nil { - err = doExchange(test, &resumeConfig, connResume, true /* resumption */) + err = doExchange(test, &resumeConfig, connResume, true /* resumption */, i+1) connResume.Close() } } @@ -1060,8 +1067,9 @@ var testCipherSuites = []struct { {"ECDHE-PSK-AES128-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA}, {"ECDHE-PSK-AES256-CBC-SHA", TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA}, {"ECDHE-PSK-CHACHA20-POLY1305", TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256}, - {"ECDHE-PSK-AES128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256}, - {"ECDHE-PSK-AES256-GCM-SHA384", TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384}, + {"AEAD-CHACHA20-POLY1305", TLS_CHACHA20_POLY1305_SHA256}, + {"AEAD-AES128-GCM-SHA256", TLS_AES_128_GCM_SHA256}, + {"AEAD-AES256-GCM-SHA384", TLS_AES_256_GCM_SHA384}, {"NULL-SHA", TLS_RSA_WITH_NULL_SHA}, } @@ -1077,24 +1085,7 @@ func isTLS12Only(suiteName string) bool { } func isTLS13Suite(suiteName string) bool { - // Only AEADs. - if !hasComponent(suiteName, "GCM") && !hasComponent(suiteName, "POLY1305") { - return false - } - // No old CHACHA20_POLY1305. - if hasComponent(suiteName, "CHACHA20-POLY1305-OLD") { - return false - } - // Must have ECDHE. - // TODO(davidben,svaldez): Add pure PSK support. - if !hasComponent(suiteName, "ECDHE") { - return false - } - // TODO(davidben,svaldez): Add PSK support. - if hasComponent(suiteName, "PSK") { - return false - } - return true + return strings.HasPrefix(suiteName, "AEAD-") } func isDTLSCipher(suiteName string) bool { @@ -1419,19 +1410,6 @@ func addBasicTests() { expectedError: ":WRONG_CERTIFICATE_TYPE:", }, { - name: "CertMismatchRSA-TLS13", - config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ecdsaP256Certificate}, - Bugs: ProtocolBugs{ - SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CERTIFICATE_TYPE:", - }, - { name: "CertMismatchECDSA", config: Config{ MaxVersion: VersionTLS12, @@ -1445,23 +1423,9 @@ func addBasicTests() { expectedError: ":WRONG_CERTIFICATE_TYPE:", }, { - name: "CertMismatchECDSA-TLS13", - config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{rsaCertificate}, - Bugs: ProtocolBugs{ - SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - }, - }, - shouldFail: true, - expectedError: ":WRONG_CERTIFICATE_TYPE:", - }, - { name: "EmptyCertificateList", config: Config{ - MaxVersion: VersionTLS12, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS12, Bugs: ProtocolBugs{ EmptyCertificateList: true, }, @@ -1472,8 +1436,7 @@ func addBasicTests() { { name: "EmptyCertificateList-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, Bugs: ProtocolBugs{ EmptyCertificateList: true, }, @@ -2119,19 +2082,6 @@ func addBasicTests() { expectMessageDropped: true, }, { - // In TLS 1.2 and below, empty NewSessionTicket messages - // mean the server changed its mind on sending a ticket. - name: "SendEmptySessionTicket", - config: Config{ - MaxVersion: VersionTLS12, - Bugs: ProtocolBugs{ - SendEmptySessionTicket: true, - FailIfSessionOffered: true, - }, - }, - flags: []string{"-expect-no-session"}, - }, - { name: "BadHelloRequest-1", renegotiate: 1, config: Config{ @@ -2312,8 +2262,68 @@ func addBasicTests() { expectedError: ":INVALID_COMPRESSION_LIST:", expectedLocalError: "remote error: illegal parameter", }, + { + name: "GREASE-TLS12", + config: Config{ + MaxVersion: VersionTLS12, + Bugs: ProtocolBugs{ + ExpectGREASE: true, + }, + }, + flags: []string{"-enable-grease"}, + }, + { + name: "GREASE-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExpectGREASE: true, + }, + }, + flags: []string{"-enable-grease"}, + }, } testCases = append(testCases, basicTests...) + + // Test that very large messages can be received. + cert := rsaCertificate + for i := 0; i < 50; i++ { + cert.Certificate = append(cert.Certificate, cert.Certificate[0]) + } + testCases = append(testCases, testCase{ + name: "LargeMessage", + config: Config{ + Certificates: []Certificate{cert}, + }, + }) + testCases = append(testCases, testCase{ + protocol: dtls, + name: "LargeMessage-DTLS", + config: Config{ + Certificates: []Certificate{cert}, + }, + }) + + // They are rejected if the maximum certificate chain length is capped. + testCases = append(testCases, testCase{ + name: "LargeMessage-Reject", + config: Config{ + Certificates: []Certificate{cert}, + }, + flags: []string{"-max-cert-list", "16384"}, + shouldFail: true, + expectedError: ":EXCESSIVE_MESSAGE_SIZE:", + }) + testCases = append(testCases, testCase{ + protocol: dtls, + name: "LargeMessage-Reject-DTLS", + config: Config{ + Certificates: []Certificate{cert}, + }, + flags: []string{"-max-cert-list", "16384"}, + shouldFail: true, + expectedError: ":EXCESSIVE_MESSAGE_SIZE:", + }) } func addCipherSuiteTests() { @@ -2381,17 +2391,27 @@ func addCipherSuiteTests() { shouldClientFail = true shouldServerFail = true } + if isTLS13Suite(suite.name) && ver.version < VersionTLS13 { + shouldClientFail = true + shouldServerFail = true + } if !isDTLSCipher(suite.name) && protocol == dtls { shouldClientFail = true shouldServerFail = true } + var sendCipherSuite uint16 var expectedServerError, expectedClientError string + serverCipherSuites := []uint16{suite.id} if shouldServerFail { expectedServerError = ":NO_SHARED_CIPHER:" } if shouldClientFail { expectedClientError = ":WRONG_CIPHER_RETURNED:" + // Configure the server to select ciphers as normal but + // select an incompatible cipher in ServerHello. + serverCipherSuites = nil + sendCipherSuite = suite.id } testCases = append(testCases, testCase{ @@ -2407,8 +2427,7 @@ func addCipherSuiteTests() { PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, Bugs: ProtocolBugs{ - EnableAllCiphers: shouldServerFail, - IgnorePeerCipherPreferences: shouldServerFail, + AdvertiseAllConfiguredCiphers: true, }, }, certFile: certFile, @@ -2426,13 +2445,13 @@ func addCipherSuiteTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - CipherSuites: []uint16{suite.id}, + CipherSuites: serverCipherSuites, Certificates: []Certificate{cert}, PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, Bugs: ProtocolBugs{ - EnableAllCiphers: shouldClientFail, IgnorePeerCipherPreferences: shouldClientFail, + SendCipherSuite: sendCipherSuite, }, }, flags: flags, @@ -2571,7 +2590,24 @@ func addCipherSuiteTests() { testType: serverTest, name: "UnknownCipher", config: Config{ + MaxVersion: VersionTLS12, CipherSuites: []uint16{bogusCipher, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + AdvertiseAllConfiguredCiphers: true, + }, + }, + }) + + // The server must be tolerant to bogus ciphers. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "UnknownCipher-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + CipherSuites: []uint16{bogusCipher, TLS_AES_128_GCM_SHA256}, + Bugs: ProtocolBugs{ + AdvertiseAllConfiguredCiphers: true, + }, }, }) @@ -2696,6 +2732,7 @@ func addBadECDSASignatureTests() { testCases = append(testCases, testCase{ name: fmt.Sprintf("BadECDSA-%d-%d", badR, badS), config: Config{ + MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Certificates: []Certificate{ecdsaP256Certificate}, Bugs: ProtocolBugs{ @@ -2706,6 +2743,19 @@ func addBadECDSASignatureTests() { shouldFail: true, expectedError: ":BAD_SIGNATURE:", }) + testCases = append(testCases, testCase{ + name: fmt.Sprintf("BadECDSA-%d-%d-TLS13", badR, badS), + config: Config{ + MaxVersion: VersionTLS13, + Certificates: []Certificate{ecdsaP256Certificate}, + Bugs: ProtocolBugs{ + BadECDSAR: badR, + BadECDSAS: badS, + }, + }, + shouldFail: true, + expectedError: ":BAD_SIGNATURE:", + }) } } } @@ -4067,6 +4117,7 @@ func addVersionNegotiationTests() { flags = append(flags, vers.flag) } + // Test configuring the runner's maximum version. for _, runnerVers := range tlsVersions { protocols := []protocol{tls} if runnerVers.hasDTLS && shimVers.hasDTLS { @@ -4085,14 +4136,18 @@ func addVersionNegotiationTests() { shimVersFlag := strconv.Itoa(int(versionToWire(shimVers.version, protocol == dtls))) + // Determine the expected initial record-layer versions. clientVers := shimVers.version if clientVers > VersionTLS10 { clientVers = VersionTLS10 } + clientVers = versionToWire(clientVers, protocol == dtls) serverVers := expectedVersion if expectedVersion >= VersionTLS13 { serverVers = VersionTLS10 } + serverVers = versionToWire(serverVers, protocol == dtls) + testCases = append(testCases, testCase{ protocol: protocol, testType: clientTest, @@ -4150,34 +4205,158 @@ func addVersionNegotiationTests() { } } + // Test the version extension at all versions. + for _, vers := range tlsVersions { + protocols := []protocol{tls} + if vers.hasDTLS { + protocols = append(protocols, dtls) + } + for _, protocol := range protocols { + suffix := vers.name + if protocol == dtls { + suffix += "-DTLS" + } + + wireVersion := versionToWire(vers.version, protocol == dtls) + testCases = append(testCases, testCase{ + protocol: protocol, + testType: serverTest, + name: "VersionNegotiationExtension-" + suffix, + config: Config{ + Bugs: ProtocolBugs{ + SendSupportedVersions: []uint16{0x1111, wireVersion, 0x2222}, + }, + }, + expectedVersion: vers.version, + }) + } + + } + + // If all versions are unknown, negotiation fails. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "NoSupportedVersions", + config: Config{ + Bugs: ProtocolBugs{ + SendSupportedVersions: []uint16{0x1111}, + }, + }, + shouldFail: true, + expectedError: ":UNSUPPORTED_PROTOCOL:", + }) + testCases = append(testCases, testCase{ + protocol: dtls, + testType: serverTest, + name: "NoSupportedVersions-DTLS", + config: Config{ + Bugs: ProtocolBugs{ + SendSupportedVersions: []uint16{0x1111}, + }, + }, + shouldFail: true, + expectedError: ":UNSUPPORTED_PROTOCOL:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ClientHelloVersionTooHigh", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendClientVersion: 0x0304, + OmitSupportedVersions: true, + }, + }, + expectedVersion: VersionTLS12, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ConflictingVersionNegotiation", + config: Config{ + Bugs: ProtocolBugs{ + SendClientVersion: VersionTLS12, + SendSupportedVersions: []uint16{VersionTLS11}, + }, + }, + // The extension takes precedence over the ClientHello version. + expectedVersion: VersionTLS11, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "ConflictingVersionNegotiation-2", + config: Config{ + Bugs: ProtocolBugs{ + SendClientVersion: VersionTLS11, + SendSupportedVersions: []uint16{VersionTLS12}, + }, + }, + // The extension takes precedence over the ClientHello version. + expectedVersion: VersionTLS12, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "RejectFinalTLS13", + config: Config{ + Bugs: ProtocolBugs{ + SendSupportedVersions: []uint16{VersionTLS13, VersionTLS12}, + }, + }, + // We currently implement a draft TLS 1.3 version. Ensure that + // the true TLS 1.3 value is ignored for now. + expectedVersion: VersionTLS12, + }) + // Test for version tolerance. testCases = append(testCases, testCase{ testType: serverTest, name: "MinorVersionTolerance", config: Config{ Bugs: ProtocolBugs{ - SendClientVersion: 0x03ff, + SendClientVersion: 0x03ff, + OmitSupportedVersions: true, }, }, - expectedVersion: VersionTLS13, + expectedVersion: VersionTLS12, }) testCases = append(testCases, testCase{ testType: serverTest, name: "MajorVersionTolerance", config: Config{ Bugs: ProtocolBugs{ + SendClientVersion: 0x0400, + OmitSupportedVersions: true, + }, + }, + // TLS 1.3 must be negotiated with the supported_versions + // extension, not ClientHello.version. + expectedVersion: VersionTLS12, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "VersionTolerance-TLS13", + config: Config{ + Bugs: ProtocolBugs{ + // Although TLS 1.3 does not use + // ClientHello.version, it still tolerates high + // values there. SendClientVersion: 0x0400, }, }, expectedVersion: VersionTLS13, }) + testCases = append(testCases, testCase{ protocol: dtls, testType: serverTest, name: "MinorVersionTolerance-DTLS", config: Config{ Bugs: ProtocolBugs{ - SendClientVersion: 0x03ff, + SendClientVersion: 0xfe00, + OmitSupportedVersions: true, }, }, expectedVersion: VersionTLS12, @@ -4188,7 +4367,8 @@ func addVersionNegotiationTests() { name: "MajorVersionTolerance-DTLS", config: Config{ Bugs: ProtocolBugs{ - SendClientVersion: 0x0400, + SendClientVersion: 0xfdff, + OmitSupportedVersions: true, }, }, expectedVersion: VersionTLS12, @@ -4200,7 +4380,8 @@ func addVersionNegotiationTests() { name: "VersionTooLow", config: Config{ Bugs: ProtocolBugs{ - SendClientVersion: 0x0200, + SendClientVersion: 0x0200, + OmitSupportedVersions: true, }, }, shouldFail: true, @@ -4212,9 +4393,7 @@ func addVersionNegotiationTests() { name: "VersionTooLow-DTLS", config: Config{ Bugs: ProtocolBugs{ - // 0x0201 is the lowest version expressable in - // DTLS. - SendClientVersion: 0x0201, + SendClientVersion: 0xffff, }, }, shouldFail: true, @@ -4240,6 +4419,7 @@ func addVersionNegotiationTests() { NegotiateVersion: VersionTLS12, }, }, + expectedVersion: VersionTLS12, // TODO(davidben): This test should fail once TLS 1.3 is final // and the fallback signal restored. }) @@ -4248,9 +4428,10 @@ func addVersionNegotiationTests() { name: "Downgrade-TLS12-Server", config: Config{ Bugs: ProtocolBugs{ - SendClientVersion: VersionTLS12, + SendSupportedVersions: []uint16{VersionTLS12}, }, }, + expectedVersion: VersionTLS12, // TODO(davidben): This test should fail once TLS 1.3 is final // and the fallback signal restored. }) @@ -4278,24 +4459,13 @@ func addMinimumVersionTests() { var expectedVersion uint16 var shouldFail bool - var expectedClientError, expectedServerError string - var expectedClientLocalError, expectedServerLocalError string + var expectedError, expectedLocalError string if runnerVers.version >= shimVers.version { expectedVersion = runnerVers.version } else { shouldFail = true - expectedServerError = ":UNSUPPORTED_PROTOCOL:" - expectedServerLocalError = "remote error: protocol version not supported" - if shimVers.version >= VersionTLS13 && runnerVers.version <= VersionTLS11 { - // If the client's minimum version is TLS 1.3 and the runner's - // maximum is below TLS 1.2, the runner will fail to select a - // cipher before the shim rejects the selected version. - expectedClientError = ":SSLV3_ALERT_HANDSHAKE_FAILURE:" - expectedClientLocalError = "tls: no cipher suite supported by both client and server" - } else { - expectedClientError = expectedServerError - expectedClientLocalError = expectedServerLocalError - } + expectedError = ":UNSUPPORTED_PROTOCOL:" + expectedLocalError = "remote error: protocol version not supported" } testCases = append(testCases, testCase{ @@ -4304,12 +4474,19 @@ func addMinimumVersionTests() { name: "MinimumVersion-Client-" + suffix, config: Config{ MaxVersion: runnerVers.version, + Bugs: ProtocolBugs{ + // Ensure the server does not decline to + // select a version (versions extension) or + // cipher (some ciphers depend on versions). + NegotiateVersion: runnerVers.version, + IgnorePeerCipherPreferences: shouldFail, + }, }, flags: flags, expectedVersion: expectedVersion, shouldFail: shouldFail, - expectedError: expectedClientError, - expectedLocalError: expectedClientLocalError, + expectedError: expectedError, + expectedLocalError: expectedLocalError, }) testCases = append(testCases, testCase{ protocol: protocol, @@ -4317,12 +4494,19 @@ func addMinimumVersionTests() { name: "MinimumVersion-Client2-" + suffix, config: Config{ MaxVersion: runnerVers.version, + Bugs: ProtocolBugs{ + // Ensure the server does not decline to + // select a version (versions extension) or + // cipher (some ciphers depend on versions). + NegotiateVersion: runnerVers.version, + IgnorePeerCipherPreferences: shouldFail, + }, }, flags: []string{"-min-version", shimVersFlag}, expectedVersion: expectedVersion, shouldFail: shouldFail, - expectedError: expectedClientError, - expectedLocalError: expectedClientLocalError, + expectedError: expectedError, + expectedLocalError: expectedLocalError, }) testCases = append(testCases, testCase{ @@ -4335,8 +4519,8 @@ func addMinimumVersionTests() { flags: flags, expectedVersion: expectedVersion, shouldFail: shouldFail, - expectedError: expectedServerError, - expectedLocalError: expectedServerLocalError, + expectedError: expectedError, + expectedLocalError: expectedLocalError, }) testCases = append(testCases, testCase{ protocol: protocol, @@ -4348,8 +4532,8 @@ func addMinimumVersionTests() { flags: []string{"-min-version", shimVersFlag}, expectedVersion: expectedVersion, shouldFail: shouldFail, - expectedError: expectedServerError, - expectedLocalError: expectedServerLocalError, + expectedError: expectedError, + expectedLocalError: expectedLocalError, }) } } @@ -4816,6 +5000,9 @@ func addExtensionTests() { }, resumeSession: true, }) + + // 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{ name: "SendSCTListOnResume-" + ver.name, config: Config{ @@ -4831,6 +5018,7 @@ func addExtensionTests() { }, resumeSession: true, }) + testCases = append(testCases, testCase{ name: "SignedCertificateTimestampList-Server-" + ver.name, testType: serverTest, @@ -5003,27 +5191,77 @@ func addExtensionTests() { }) testCases = append(testCases, testCase{ testType: serverTest, - name: "NPN-Server", + name: "NPN-Declined-TLS13", config: Config{ MaxVersion: VersionTLS13, NextProtos: []string{"bar"}, }, flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"}, }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "InvalidChannelIDSignature", + config: Config{ + MaxVersion: VersionTLS12, + ChannelID: channelIDKey, + Bugs: ProtocolBugs{ + InvalidChannelIDSignature: true, + }, + }, + flags: []string{"-enable-channel-id"}, + shouldFail: true, + expectedError: ":CHANNEL_ID_SIGNATURE_INVALID:", + expectedLocalError: "remote error: error decrypting message", + }) + + // OpenSSL sends the status_request extension on resumption in TLS 1.2. Test that this is + // tolerated. + testCases = append(testCases, testCase{ + 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, + }) + + // Beginning TLS 1.3, enforce this does not happen. + testCases = append(testCases, testCase{ + name: "SendOCSPResponseOnResume-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendOCSPResponseOnResume: []byte("bogus"), + }, + }, + flags: []string{ + "-enable-ocsp-stapling", + "-expect-ocsp-response", + base64.StdEncoding.EncodeToString(testOCSPResponse), + }, + resumeSession: true, + shouldFail: true, + expectedError: ":ERROR_PARSING_EXTENSION:", + }) } func addResumptionVersionTests() { for _, sessionVers := range tlsVersions { for _, resumeVers := range tlsVersions { - cipher := TLS_RSA_WITH_AES_128_CBC_SHA - if sessionVers.version >= VersionTLS13 || resumeVers.version >= VersionTLS13 { - // TLS 1.3 only shares ciphers with TLS 1.2, so - // we skip certain combinations and use a - // different cipher to test with. - cipher = TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - if sessionVers.version < VersionTLS12 || resumeVers.version < VersionTLS12 { - continue - } + // SSL 3.0 does not have tickets and TLS 1.3 does not + // have session IDs, so skip their cross-resumption + // tests. + if (sessionVers.version >= VersionTLS13 && resumeVers.version == VersionSSL30) || + (resumeVers.version >= VersionTLS13 && sessionVers.version == VersionSSL30) { + continue } protocols := []protocol{tls} @@ -5042,8 +5280,7 @@ func addResumptionVersionTests() { name: "Resume-Client" + suffix, resumeSession: true, config: Config{ - MaxVersion: sessionVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: sessionVers.version, Bugs: ProtocolBugs{ ExpectNoTLS12Session: sessionVers.version >= VersionTLS13, ExpectNoTLS13PSK: sessionVers.version < VersionTLS13, @@ -5068,13 +5305,11 @@ func addResumptionVersionTests() { name: "Resume-Client-Mismatch" + suffix, resumeSession: true, config: Config{ - MaxVersion: sessionVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: sessionVers.version, }, expectedVersion: sessionVers.version, resumeConfig: &Config{ - MaxVersion: resumeVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: resumeVers.version, Bugs: ProtocolBugs{ AcceptAnySession: true, }, @@ -5090,13 +5325,11 @@ func addResumptionVersionTests() { name: "Resume-Client-NoResume" + suffix, resumeSession: true, config: Config{ - MaxVersion: sessionVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: sessionVers.version, }, expectedVersion: sessionVers.version, resumeConfig: &Config{ - MaxVersion: resumeVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: resumeVers.version, }, newSessionsOnResume: true, expectResumeRejected: true, @@ -5109,14 +5342,12 @@ func addResumptionVersionTests() { name: "Resume-Server" + suffix, resumeSession: true, config: Config{ - MaxVersion: sessionVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: sessionVers.version, }, expectedVersion: sessionVers.version, expectResumeRejected: sessionVers.version != resumeVers.version, resumeConfig: &Config{ - MaxVersion: resumeVers.version, - CipherSuites: []uint16{cipher}, + MaxVersion: resumeVers.version, Bugs: ProtocolBugs{ SendBothTickets: true, }, @@ -5150,13 +5381,13 @@ func addResumptionVersionTests() { resumeSession: true, config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + CipherSuites: []uint16{TLS_AES_128_GCM_SHA256}, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + CipherSuites: []uint16{TLS_AES_128_GCM_SHA256}, Bugs: ProtocolBugs{ - SendCipherSuite: TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + SendCipherSuite: TLS_AES_256_GCM_SHA384, }, }, shouldFail: true, @@ -5585,6 +5816,7 @@ func addSignatureAlgorithmTests() { // Not all ciphers involve a signature. Advertise a list which gives all // versions a signing cipher. signingCiphers := []uint16{ + TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, @@ -5857,8 +6089,7 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "ServerAuth-SignatureType-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP521AndSHA512, signatureRSAPKCS1WithSHA384, @@ -5929,8 +6160,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "Verify-ServerAuth-SignatureType-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, }, @@ -6043,8 +6273,7 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "ServerAuth-NoFallback-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA1, }, @@ -6113,8 +6342,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "ServerAuth-Enforced-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithMD5, }, @@ -6276,7 +6504,6 @@ func addSignatureAlgorithmTests() { name: "CheckLeafCurve-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Certificates: []Certificate{ecdsaP256Certificate}, }, flags: []string{"-p384-only"}, @@ -6300,7 +6527,6 @@ func addSignatureAlgorithmTests() { name: "ECDSACurveMismatch-Verify-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, Certificates: []Certificate{ecdsaP256Certificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP384AndSHA384, @@ -6319,8 +6545,7 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "ECDSACurveMismatch-Sign-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, VerifySignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP384AndSHA384, signatureECDSAWithP256AndSHA256, @@ -6951,7 +7176,6 @@ func addCurveTests() { name: "CurveTest-Client-" + curve.name + "-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []CurveID{curve.id}, }, flags: []string{ @@ -6979,7 +7203,6 @@ func addCurveTests() { name: "CurveTest-Server-" + curve.name + "-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []CurveID{curve.id}, }, flags: []string{ @@ -6995,11 +7218,22 @@ func addCurveTests() { testType: serverTest, name: "UnknownCurve", config: Config{ + MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []CurveID{bogusCurve, CurveP256}, }, }) + // The server must be tolerant to bogus curves. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "UnknownCurve-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + CurvePreferences: []CurveID{bogusCurve, CurveP256}, + }, + }) + // The server must not consider ECDHE ciphers when there are no // supported curves. testCases = append(testCases, testCase{ @@ -7019,14 +7253,13 @@ func addCurveTests() { testType: serverTest, name: "NoSupportedCurves-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, Bugs: ProtocolBugs{ NoSupportedCurves: true, }, }, shouldFail: true, - expectedError: ":NO_SHARED_CIPHER:", + expectedError: ":NO_SHARED_GROUP:", }) // The server must fall back to another cipher when there are no @@ -7061,8 +7294,7 @@ func addCurveTests() { testCases = append(testCases, testCase{ name: "BadECDHECurve-TLS13", config: Config{ - MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, Bugs: ProtocolBugs{ SendCurve: bogusCurve, }, @@ -7091,8 +7323,7 @@ func addCurveTests() { // HelloRetryRequest requests an unsupported curve. name: "UnsupportedCurve-ServerHello-TLS13", config: Config{ - MaxVersion: VersionTLS12, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + MaxVersion: VersionTLS13, CurvePreferences: []CurveID{CurveP384}, Bugs: ProtocolBugs{ SendCurve: CurveP256, @@ -7121,7 +7352,6 @@ func addCurveTests() { name: "InvalidECDHPoint-Client-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []CurveID{CurveP256}, Bugs: ProtocolBugs{ InvalidECDHPoint: true, @@ -7149,7 +7379,6 @@ func addCurveTests() { name: "InvalidECDHPoint-Server-TLS13", config: Config{ MaxVersion: VersionTLS13, - CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, CurvePreferences: []CurveID{CurveP256}, Bugs: ProtocolBugs{ InvalidECDHPoint: true, @@ -7303,6 +7532,105 @@ func addTLS13RecordTests() { }) } +func addSessionTicketTests() { + testCases = append(testCases, testCase{ + // In TLS 1.2 and below, empty NewSessionTicket messages + // mean the server changed its mind on sending a ticket. + name: "SendEmptySessionTicket", + config: Config{ + MaxVersion: VersionTLS12, + Bugs: ProtocolBugs{ + SendEmptySessionTicket: true, + }, + }, + flags: []string{"-expect-no-session"}, + }) + + // Test that the server ignores unknown PSK modes. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TLS13-SendUnknownModeSessionTicket-Server", + config: Config{ + 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. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TLS13-SendBadKEModeSessionTicket-Server", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendPSKKeyExchangeModes: []byte{0x1a}, + }, + }, + resumeSession: true, + expectResumeRejected: true, + }) + + // Test that the server declines sessions with no matching auth mode. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TLS13-SendBadAuthModeSessionTicket-Server", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendPSKAuthModes: []byte{0x1a}, + }, + }, + resumeSession: true, + expectResumeRejected: true, + }) + + // Test that the client ignores unknown PSK modes. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13-SendUnknownModeSessionTicket-Client", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendPSKKeyExchangeModes: []byte{0x1a, pskDHEKEMode, 0x2a}, + SendPSKAuthModes: []byte{0x1a, pskAuthMode, 0x2a}, + }, + }, + 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}, + }, + }, + flags: []string{"-expect-no-session"}, + }) + + // Test that the client ignores tickets with no matching auth mode. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13-SendBadAuthModeSessionTicket-Client", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendPSKAuthModes: []byte{0x1a}, + }, + }, + flags: []string{"-expect-no-session"}, + }) +} + func addChangeCipherSpecTests() { // Test missing ChangeCipherSpecs. testCases = append(testCases, testCase{ @@ -7945,6 +8273,47 @@ func addTrailingMessageDataTests() { func addTLS13HandshakeTests() { testCases = append(testCases, testCase{ testType: clientTest, + name: "NegotiatePSKResumption-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + NegotiatePSKResumption: true, + }, + }, + resumeSession: true, + shouldFail: true, + expectedError: ":UNEXPECTED_EXTENSION:", + }) + + 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, @@ -7953,7 +8322,7 @@ func addTLS13HandshakeTests() { }, }, shouldFail: true, - expectedError: ":MISSING_KEY_SHARE:", + expectedError: ":UNEXPECTED_EXTENSION:", }) testCases = append(testCases, testCase{ @@ -8190,6 +8559,102 @@ func addTLS13HandshakeTests() { shouldFail: true, expectedError: ":DECODE_ERROR:", }) + + testCases = append(testCases, testCase{ + name: "TLS13-AlwaysSelectPSKIdentity", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + AlwaysSelectPSKIdentity: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_EXTENSION:", + }) + + testCases = append(testCases, testCase{ + name: "TLS13-InvalidPSKIdentity", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SelectPSKIdentityOnResume: 1, + }, + }, + resumeSession: true, + shouldFail: true, + expectedError: ":PSK_IDENTITY_NOT_FOUND:", + }) +} + +func addPeekTests() { + // Test SSL_peek works, including on empty records. + testCases = append(testCases, testCase{ + name: "Peek-Basic", + sendEmptyRecords: 1, + flags: []string{"-peek-then-read"}, + }) + + // Test SSL_peek can drive the initial handshake. + testCases = append(testCases, testCase{ + name: "Peek-ImplicitHandshake", + flags: []string{ + "-peek-then-read", + "-implicit-handshake", + }, + }) + + // Test SSL_peek can discover and drive a renegotiation. + testCases = append(testCases, testCase{ + name: "Peek-Renegotiate", + config: Config{ + MaxVersion: VersionTLS12, + }, + renegotiate: 1, + flags: []string{ + "-peek-then-read", + "-renegotiate-freely", + "-expect-total-renegotiations", "1", + }, + }) + + // Test SSL_peek can discover a close_notify. + testCases = append(testCases, testCase{ + name: "Peek-Shutdown", + config: Config{ + Bugs: ProtocolBugs{ + ExpectCloseNotify: true, + }, + }, + flags: []string{ + "-peek-then-read", + "-check-close-notify", + }, + }) + + // Test SSL_peek can discover an alert. + testCases = append(testCases, testCase{ + name: "Peek-Alert", + config: Config{ + Bugs: ProtocolBugs{ + SendSpuriousAlert: alertRecordOverflow, + }, + }, + flags: []string{"-peek-then-read"}, + shouldFail: true, + expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", + }) + + // Test SSL_peek can handle KeyUpdate. + testCases = append(testCases, testCase{ + name: "Peek-KeyUpdate", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendKeyUpdateBeforeEveryAppDataRecord: true, + }, + }, + flags: []string{"-peek-then-read"}, + }) } func worker(statusChan chan statusMsg, c chan *testCase, shimPath string, wg *sync.WaitGroup) { @@ -8302,12 +8767,14 @@ func main() { addCurveTests() addCECPQ1Tests() addDHEGroupSizeTests() + addSessionTicketTests() addTLS13RecordTests() addAllStateMachineCoverageTests() addChangeCipherSpecTests() addWrongMessageTypeTests() addTrailingMessageDataTests() addTLS13HandshakeTests() + addPeekTests() var wg sync.WaitGroup diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index 1f01166e..425664d4 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -104,6 +104,8 @@ const Flag<bool> kBoolFlags[] = { &TestConfig::use_old_client_cert_callback }, { "-use-null-client-ca-list", &TestConfig::use_null_client_ca_list }, { "-send-alert", &TestConfig::send_alert }, + { "-peek-then-read", &TestConfig::peek_then_read }, + { "-enable-grease", &TestConfig::enable_grease }, }; const Flag<std::string> kStringFlags[] = { @@ -153,6 +155,7 @@ const Flag<int> kIntFlags[] = { { "-expect-curve-id", &TestConfig::expect_curve_id }, { "-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 }, }; const Flag<std::vector<int>> kIntVectorFlags[] = { diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index 93c22ce4..9f742975 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -112,6 +112,9 @@ struct TestConfig { int initial_timeout_duration_ms = 0; bool use_null_client_ca_list = false; bool send_alert = false; + bool peek_then_read = false; + bool enable_grease = false; + int max_cert_list = 0; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c index ee73f73d..8f1b516e 100644 --- a/src/ssl/tls13_client.c +++ b/src/ssl/tls13_client.c @@ -145,9 +145,30 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_error; } + assert(ssl->s3->have_version); + memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); + + const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite); + if (cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + 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)) { + 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; - CBS key_share, pre_shared_key; + 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; @@ -177,6 +198,15 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { 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_DECODE_ERROR); + 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); @@ -184,8 +214,12 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { } } - assert(ssl->s3->have_version); - memcpy(ssl->s3->server_random, CBS_data(&server_random), SSL3_RANDOM_SIZE); + /* We only support PSK_AUTH and PSK_DHE_KE. */ + if (!have_key_share || have_sigalgs == have_pre_shared_key) { + 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; if (have_pre_shared_key) { @@ -207,6 +241,12 @@ 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); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return ssl_hs_error; + } + if (!ssl_session_is_context_valid(ssl, ssl->session)) { /* This is actually a client application bug. */ OPENSSL_PUT_ERROR(SSL, @@ -224,109 +264,56 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_error; } ssl_set_session(ssl, NULL); - } else { - if (!ssl_get_new_session(ssl, 0)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); - return ssl_hs_error; - } - } - - const SSL_CIPHER *cipher = SSL_get_cipher_by_value(cipher_suite); - if (cipher == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CIPHER_RETURNED); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + } else if (!ssl_get_new_session(ssl, 0)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } - if (!ssl->s3->session_reused) { - /* 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)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CIPHER_RETURNED); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return ssl_hs_error; - } - } else { - uint16_t resumption_cipher; - if (!ssl_cipher_get_ecdhe_psk_cipher(ssl->s3->new_session->cipher, - &resumption_cipher) || - resumption_cipher != ssl_cipher_get_value(cipher)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return ssl_hs_error; - } - } - ssl->s3->new_session->cipher = cipher; ssl->s3->tmp.new_cipher = cipher; /* The PRF hash is now known. Set up the key schedule. */ - static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; - size_t resumption_ctx_len = + 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) { - uint8_t resumption_ctx[EVP_MAX_MD_SIZE]; - if (!tls13_resumption_context(ssl, resumption_ctx, resumption_ctx_len, + if (!tls13_resumption_context(ssl, resumption_ctx, hash_len, ssl->s3->new_session) || - !tls13_init_key_schedule(ssl, resumption_ctx, resumption_ctx_len)) { + !tls13_resumption_psk(ssl, psk_secret, hash_len, + ssl->s3->new_session)) { return ssl_hs_error; } - } else if (!tls13_init_key_schedule(ssl, kZeroes, resumption_ctx_len)) { - return ssl_hs_error; } - /* Resolve PSK and incorporate it into the secret. */ - if (cipher->algorithm_auth == SSL_aPSK) { - if (!ssl->s3->session_reused) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return ssl_hs_error; - } - - uint8_t resumption_psk[EVP_MAX_MD_SIZE]; - if (!tls13_resumption_psk(ssl, resumption_psk, hs->hash_len, - ssl->s3->new_session) || - !tls13_advance_key_schedule(ssl, resumption_psk, hs->hash_len)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - return ssl_hs_error; - } - } else if (!tls13_advance_key_schedule(ssl, kZeroes, hs->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) || + !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) { return ssl_hs_error; } /* Resolve ECDHE and incorporate it into the secret. */ - if (cipher->algorithm_mkey == SSL_kECDHE) { - if (!have_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; - } - - uint8_t *dhe_secret; - size_t dhe_secret_len; - if (!ssl_ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len, - &alert, &key_share)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); - return ssl_hs_error; - } + uint8_t *dhe_secret; + size_t dhe_secret_len; + if (!ssl_ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len, + &alert, &key_share)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return ssl_hs_error; + } - int ok = tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len); + if (!tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len)) { OPENSSL_free(dhe_secret); - if (!ok) { - return ssl_hs_error; - } - } else { - if (have_key_share) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION); - return ssl_hs_error; - } - if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len)) { - return ssl_hs_error; - } + return ssl_hs_error; + } + 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 @@ -374,8 +361,8 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, SSL_HANDSHAKE *hs) { ssl->s3->tmp.cert_request = 0; - /* CertificateRequest may only be sent in certificate-based ciphers. */ - if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { + /* CertificateRequest may only be sent in non-resumption handshakes. */ + if (ssl->s3->session_reused) { hs->state = state_process_server_finished; return ssl_hs_ok; } @@ -436,15 +423,6 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL *ssl, return ssl_hs_error; } - /* Check the certificate matches the cipher suite. - * - * TODO(davidben): Remove this check when switching to the new TLS 1.3 cipher - * suite negotiation. */ - if (!ssl_check_leaf_certificate(ssl, ssl->s3->new_session->peer)) { - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); - return ssl_hs_error; - } - hs->state = state_process_server_certificate_verify; return ssl_hs_read_message; } @@ -464,7 +442,6 @@ static enum ssl_hs_wait_t do_process_server_certificate_verify( static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl, SSL_HANDSHAKE *hs) { 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) || @@ -645,14 +622,16 @@ int tls13_process_new_session_ticket(SSL *ssl) { return 0; } - CBS cbs, extensions, ticket; + CBS cbs, ke_modes, auth_modes, ticket, extensions; CBS_init(&cbs, ssl->init_msg, ssl->init_num); if (!CBS_get_u32(&cbs, &session->tlsext_tick_lifetime_hint) || - !CBS_get_u32(&cbs, &session->ticket_flags) || - !CBS_get_u32(&cbs, &session->ticket_age_add) || - !CBS_get_u16_length_prefixed(&cbs, &extensions) || + !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_u16_length_prefixed(&cbs, &ticket) || !CBS_stow(&ticket, &session->tlsext_tick, &session->tlsext_ticklen) || + !CBS_get_u16_length_prefixed(&cbs, &extensions) || CBS_len(&cbs) != 0) { SSL_SESSION_free(session); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); @@ -660,10 +639,13 @@ int tls13_process_new_session_ticket(SSL *ssl) { return 0; } - session->ticket_age_add_valid = 1; session->not_resumable = 0; - if (ssl->ctx->new_session_cb != NULL && + /* 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 && 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_server.c b/src/ssl/tls13_server.c index 53e53638..984cc5ca 100644 --- a/src/ssl/tls13_server.c +++ b/src/ssl/tls13_server.c @@ -51,32 +51,11 @@ enum server_hs_state_t { static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; -static int resolve_psk_secret(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - - if (ssl->s3->tmp.new_cipher->algorithm_auth != SSL_aPSK) { - return tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len); - } - - uint8_t resumption_psk[EVP_MAX_MD_SIZE]; - if (!tls13_resumption_psk(ssl, resumption_psk, hs->hash_len, - ssl->s3->new_session) || - !tls13_advance_key_schedule(ssl, resumption_psk, hs->hash_len)) { - return 0; - } - - return 1; -} - static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry, struct ssl_early_callback_ctx *early_ctx) { *out_need_retry = 0; - SSL_HANDSHAKE *hs = ssl->s3->hs; - - if (ssl->s3->tmp.new_cipher->algorithm_mkey != SSL_kECDHE) { - return tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len); - } + /* We only support connections that include an ECDHE key exchange. */ CBS key_share; if (!ssl_early_callback_get_extension(early_ctx, &key_share, TLSEXT_TYPE_key_share)) { @@ -139,15 +118,11 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return 0; } - uint16_t resumption_cipher; if (session != NULL && - /* We currently only support ECDHE-PSK resumption. */ - ((session->ticket_flags & SSL_TICKET_ALLOW_DHE_RESUMPTION) == 0 || - /* Only resume if the session's version matches. */ - session->ssl_version != ssl->version || - !ssl_cipher_get_ecdhe_psk_cipher(session->cipher, &resumption_cipher) || - !ssl_client_cipher_list_contains_cipher(&client_hello, - resumption_cipher))) { + /* 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; } @@ -229,39 +204,32 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { } ssl->s3->new_session->cipher = cipher; - ssl->s3->tmp.new_cipher = cipher; - } else { - uint16_t resumption_cipher; - if (!ssl_cipher_get_ecdhe_psk_cipher(ssl->s3->new_session->cipher, - &resumption_cipher)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); - ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); - return ssl_hs_error; - } - ssl->s3->tmp.new_cipher = SSL_get_cipher_by_value(resumption_cipher); } + ssl->s3->tmp.new_cipher = ssl->s3->new_session->cipher; ssl->method->received_flight(ssl); - /* The PRF hash is now known. Set up the key schedule and hash the - * ClientHello. */ - size_t resumption_ctx_len = + + /* 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) { - uint8_t resumption_ctx[EVP_MAX_MD_SIZE]; - if (!tls13_resumption_context(ssl, resumption_ctx, resumption_ctx_len, + if (!tls13_resumption_context(ssl, resumption_ctx, hash_len, ssl->s3->new_session) || - !tls13_init_key_schedule(ssl, resumption_ctx, resumption_ctx_len)) { - return ssl_hs_error; - } - } else { - if (!tls13_init_key_schedule(ssl, kZeroes, resumption_ctx_len)) { + !tls13_resumption_psk(ssl, psk_secret, hash_len, + ssl->s3->new_session)) { return ssl_hs_error; } } - /* Resolve PSK and incorporate it into the secret. */ - if (!resolve_psk_secret(ssl)) { + /* 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) || + !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) { return ssl_hs_error; } @@ -347,14 +315,27 @@ 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) || - !ssl->method->finish_message(ssl, &cbb)) { - CBB_cleanup(&cbb); - return ssl_hs_error; + !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)) { + goto err; } hs->state = state_send_encrypted_extensions; return ssl_hs_write_message; + +err: + CBB_cleanup(&cbb); + return ssl_hs_error; } static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl, @@ -380,8 +361,8 @@ static enum ssl_hs_wait_t do_send_certificate_request(SSL *ssl, SSL_HANDSHAKE *hs) { /* Determine whether to request a client certificate. */ ssl->s3->tmp.cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); - /* CertificateRequest may only be sent in certificate-based ciphers. */ - if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { + /* CertificateRequest may only be sent in non-resumption handshakes. */ + if (ssl->s3->session_reused) { ssl->s3->tmp.cert_request = 0; } @@ -426,7 +407,7 @@ err: static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl, SSL_HANDSHAKE *hs) { - if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { + if (ssl->s3->session_reused) { hs->state = state_send_server_finished; return ssl_hs_ok; } @@ -556,22 +537,21 @@ static enum ssl_hs_wait_t do_send_new_session_ticket(SSL *ssl, SSL_HANDSHAKE *hs) { SSL_SESSION *session = ssl->s3->new_session; session->tlsext_tick_lifetime_hint = session->timeout; - session->ticket_flags = SSL_TICKET_ALLOW_DHE_RESUMPTION; - if (!RAND_bytes((uint8_t *)&session->ticket_age_add, - sizeof(session->ticket_age_add))) { - return 0; - } - session->ticket_age_add_valid = 1; - CBB cbb, body, ticket; + /* TODO(svaldez): Add support for sending 0RTT through TicketEarlyDataInfo + * extension. */ + + CBB cbb, body, ke_modes, auth_modes, ticket; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_NEW_SESSION_TICKET) || !CBB_add_u32(&body, session->tlsext_tick_lifetime_hint) || - !CBB_add_u32(&body, session->ticket_flags) || - !CBB_add_u32(&body, session->ticket_age_add) || - !CBB_add_u16(&body, 0 /* no ticket extensions */) || + !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_u16_length_prefixed(&body, &ticket) || !ssl_encrypt_ticket(ssl, &ticket, session) || + !CBB_add_u16(&body, 0 /* no ticket extensions */) || !ssl->method->finish_message(ssl, &cbb)) { CBB_cleanup(&cbb); return ssl_hs_error; diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c index 155d09a2..8bcdf8f6 100644 --- a/src/ssl/tls_method.c +++ b/src/ssl/tls_method.c @@ -71,9 +71,11 @@ static int ssl3_version_from_wire(uint16_t *out_version, case TLS1_VERSION: case TLS1_1_VERSION: case TLS1_2_VERSION: - case TLS1_3_VERSION: *out_version = wire_version; return 1; + case TLS1_3_DRAFT_VERSION: + *out_version = TLS1_3_VERSION; + return 1; } return 0; @@ -85,8 +87,9 @@ static uint16_t ssl3_version_to_wire(uint16_t version) { case TLS1_VERSION: case TLS1_1_VERSION: case TLS1_2_VERSION: - case TLS1_3_VERSION: return version; + case TLS1_3_VERSION: + return TLS1_3_DRAFT_VERSION; } /* It is an error to use this function with an invalid version. */ diff --git a/src/tool/client.cc b/src/tool/client.cc index 04a217a7..b9f1c13b 100644 --- a/src/tool/client.cc +++ b/src/tool/client.cc @@ -89,6 +89,10 @@ static const struct argument kArguments[] = { " values: 'smtp'", }, { + "-grease", kBooleanArgument, + "Enable GREASE", + }, + { "", kOptionalArgument, "", }, }; @@ -269,6 +273,10 @@ bool Client(const std::vector<std::string> &args) { SSL_CTX_sess_set_new_cb(ctx.get(), NewSessionCallback); } + if (args_map.count("-grease") != 0) { + SSL_CTX_set_grease_enabled(ctx.get(), 1); + } + int sock = -1; if (!Connect(&sock, args_map["-connect"])) { return false; diff --git a/src/util/all_tests.json b/src/util/all_tests.json index f95a21e8..ac4b3c7a 100644 --- a/src/util/all_tests.json +++ b/src/util/all_tests.json @@ -1,5 +1,5 @@ [ - ["crypto/aes/aes_test"], + ["crypto/aes/aes_test", "crypto/aes/aes_tests.txt"], ["crypto/asn1/asn1_test"], ["crypto/base64/base64_test"], ["crypto/bio/bio_test"], @@ -7,9 +7,7 @@ ["crypto/bytestring/bytestring_test"], ["crypto/chacha/chacha_test"], ["crypto/cipher/aead_test", "aes-128-gcm", "crypto/cipher/test/aes_128_gcm_tests.txt"], - ["crypto/cipher/aead_test", "aes-128-key-wrap", "crypto/cipher/test/aes_128_key_wrap_tests.txt"], ["crypto/cipher/aead_test", "aes-256-gcm", "crypto/cipher/test/aes_256_gcm_tests.txt"], - ["crypto/cipher/aead_test", "aes-256-key-wrap", "crypto/cipher/test/aes_256_key_wrap_tests.txt"], ["crypto/cipher/aead_test", "chacha20-poly1305", "crypto/cipher/test/chacha20_poly1305_tests.txt"], ["crypto/cipher/aead_test", "chacha20-poly1305-old", "crypto/cipher/test/chacha20_poly1305_old_tests.txt"], ["crypto/cipher/aead_test", "aes-128-cbc-sha1-tls", "crypto/cipher/test/aes_128_cbc_sha1_tls_tests.txt"], diff --git a/src/util/generate_build_files.py b/src/util/generate_build_files.py index 92a15074..0b84bfd8 100644 --- a/src/util/generate_build_files.py +++ b/src/util/generate_build_files.py @@ -26,6 +26,7 @@ import json OS_ARCH_COMBOS = [ ('linux', 'arm', 'linux32', [], 'S'), ('linux', 'aarch64', 'linux64', [], 'S'), + ('linux', 'ppc64le', 'ppc64le', [], 'S'), ('linux', 'x86', 'elf', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), ('linux', 'x86_64', 'elf', [], 'S'), ('mac', 'x86', 'macosx', ['-fPIC', '-DOPENSSL_IA32_SSE2'], 'S'), @@ -78,9 +79,6 @@ class Android(object): """ - def ExtraFiles(self): - return ['android_compat_keywrap.c'] - def PrintVariableSection(self, out, name, files): out.write('%s := \\\n' % name) for f in sorted(files): @@ -95,13 +93,13 @@ class Android(object): blueprint.write('cc_defaults {\n') blueprint.write(' name: "libcrypto_sources",\n') blueprint.write(' srcs: [\n') - for f in sorted(files['crypto'] + self.ExtraFiles()): + for f in sorted(files['crypto']): blueprint.write(' "%s",\n' % f) blueprint.write(' ],\n') blueprint.write(' target: {\n') for ((osname, arch), asm_files) in asm_outputs: - if osname != 'linux': + if osname != 'linux' or arch == 'ppc64le': continue if arch == 'aarch64': arch = 'arm64' @@ -160,8 +158,7 @@ class Android(object): with open('sources.mk', 'w+') as makefile: makefile.write(self.header) - crypto_files = files['crypto'] + self.ExtraFiles() - self.PrintVariableSection(makefile, 'crypto_sources', crypto_files) + self.PrintVariableSection(makefile, 'crypto_sources', files['crypto']) for ((osname, arch), asm_files) in asm_outputs: if osname != 'linux': @@ -170,16 +167,6 @@ class Android(object): makefile, '%s_%s_sources' % (osname, arch), asm_files) -class AndroidStandalone(Android): - """AndroidStandalone is for Android builds outside of the Android-system, i.e. - - for applications that wish wish to ship BoringSSL. - """ - - def ExtraFiles(self): - return [] - - class Bazel(object): """Bazel outputs files suitable for including in Bazel files.""" @@ -586,6 +573,8 @@ def ArchForAsmFilename(filename): return ['aarch64'] elif 'arm' in filename: return ['arm'] + elif 'ppc' in filename: + return ['ppc64le'] else: raise ValueError('Unknown arch for asm filename: ' + filename) @@ -707,7 +696,7 @@ def main(platforms): if __name__ == '__main__': parser = optparse.OptionParser(usage='Usage: %prog [--prefix=<path>]' - ' [android|android-standalone|bazel|gn|gyp]') + ' [android|bazel|gn|gyp]') parser.add_option('--prefix', dest='prefix', help='For Bazel, prepend argument to all source files') options, args = parser.parse_args(sys.argv[1:]) @@ -721,8 +710,6 @@ if __name__ == '__main__': for s in args: if s == 'android': platforms.append(Android()) - elif s == 'android-standalone': - platforms.append(AndroidStandalone()) elif s == 'bazel': platforms.append(Bazel()) elif s == 'gn': |