summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSteven Valdez <svaldez@google.com>2016-10-07 10:34:51 -0400
committerSteven Valdez <svaldez@google.com>2016-10-10 10:12:47 -0400
commitbb1ceac29bc7a18b94e3da78057dc41aa7071784 (patch)
treed2c33595946806d8cbc75201ada3e044382727ce /src
parent7c0d06c221ce9edf44bbf978b909b38a0aee2084 (diff)
downloadboringssl-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')
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/FUZZING.md46
-rw-r--r--src/crypto/CMakeLists.txt4
-rw-r--r--src/crypto/aes/CMakeLists.txt10
-rw-r--r--src/crypto/aes/aes.c24
-rw-r--r--src/crypto/aes/aes_test.cc180
-rw-r--r--src/crypto/aes/aes_tests.txt50
-rw-r--r--src/crypto/aes/asm/aesp8-ppc.pl3805
-rw-r--r--src/crypto/aes/asm/aesv8-armx.pl2
-rw-r--r--src/crypto/aes/key_wrap.c134
-rw-r--r--src/crypto/bn/bn_test.cc6
-rw-r--r--src/crypto/bytestring/bytestring_test.cc19
-rw-r--r--src/crypto/bytestring/cbs.c14
-rw-r--r--src/crypto/cipher/aead_test.cc2
-rw-r--r--src/crypto/cipher/e_aes.c326
-rw-r--r--src/crypto/cipher/test/aes_128_key_wrap_tests.txt9
-rw-r--r--src/crypto/cipher/test/aes_256_key_wrap_tests.txt23
-rw-r--r--src/crypto/cpu-ppc64le.c40
-rw-r--r--src/crypto/crypto.c8
-rwxr-xr-xsrc/crypto/ec/asm/p256-x86_64-asm.pl14
-rw-r--r--src/crypto/err/ssl.errordata1
-rw-r--r--src/crypto/internal.h4
-rw-r--r--src/crypto/modes/CMakeLists.txt9
-rw-r--r--src/crypto/modes/asm/ghashp8-ppc.pl670
-rw-r--r--src/crypto/modes/gcm.c22
-rw-r--r--src/crypto/perlasm/ppc-xlate.pl299
-rw-r--r--src/crypto/test/malloc.cc38
-rw-r--r--src/crypto/x509/x509_test.cc226
-rw-r--r--src/crypto/x509/x509_vfy.c4
-rw-r--r--src/crypto/x509/x509_vpm.c47
-rw-r--r--src/crypto/x509/x_crl.c4
-rw-r--r--src/decrepit/ssl/ssl_decrepit.c112
-rw-r--r--src/include/openssl/aead.h14
-rw-r--r--src/include/openssl/aes.h30
-rw-r--r--src/include/openssl/base.h8
-rw-r--r--src/include/openssl/bytestring.h14
-rw-r--r--src/include/openssl/cpu.h8
-rw-r--r--src/include/openssl/ec.h2
-rw-r--r--src/include/openssl/ssl.h37
-rw-r--r--src/include/openssl/tls1.h25
-rw-r--r--src/include/openssl/x509.h1
-rw-r--r--src/include/openssl/x509v3.h6
-rw-r--r--src/ssl/d1_srtp.c31
-rw-r--r--src/ssl/handshake_client.c42
-rw-r--r--src/ssl/handshake_server.c101
-rw-r--r--src/ssl/internal.h46
-rw-r--r--src/ssl/ssl_asn1.c25
-rw-r--r--src/ssl/ssl_cipher.c170
-rw-r--r--src/ssl/ssl_ecdh.c19
-rw-r--r--src/ssl/ssl_file.c41
-rw-r--r--src/ssl/ssl_lib.c50
-rw-r--r--src/ssl/ssl_rsa.c3
-rw-r--r--src/ssl/ssl_session.c13
-rw-r--r--src/ssl/ssl_test.cc204
-rw-r--r--src/ssl/t1_lib.c258
-rw-r--r--src/ssl/test/PORTING.md3
-rw-r--r--src/ssl/test/bssl_shim.cc31
-rw-r--r--src/ssl/test/runner/cipher_suites.go45
-rw-r--r--src/ssl/test/runner/common.go108
-rw-r--r--src/ssl/test/runner/conn.go45
-rw-r--r--src/ssl/test/runner/dtls.go42
-rw-r--r--src/ssl/test/runner/fuzzer_mode.json26
-rw-r--r--src/ssl/test/runner/handshake_client.go136
-rw-r--r--src/ssl/test/runner/handshake_messages.go212
-rw-r--r--src/ssl/test/runner/handshake_server.go336
-rw-r--r--src/ssl/test/runner/key_agreement.go5
-rw-r--r--src/ssl/test/runner/prf.go6
-rw-r--r--src/ssl/test/runner/runner.go791
-rw-r--r--src/ssl/test/test_config.cc3
-rw-r--r--src/ssl/test/test_config.h3
-rw-r--r--src/ssl/tls13_client.c192
-rw-r--r--src/ssl/tls13_server.c118
-rw-r--r--src/ssl/tls_method.c7
-rw-r--r--src/tool/client.cc8
-rw-r--r--src/util/all_tests.json4
-rw-r--r--src/util/generate_build_files.py27
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':