diff options
79 files changed, 3804 insertions, 2769 deletions
@@ -44,7 +44,6 @@ cc_defaults { libcrypto_sources_no_clang = [ "linux-arm/crypto/aes/aes-armv4.S", "linux-arm/crypto/aes/bsaes-armv7.S", - "linux-arm/crypto/sha/sha256-armv4.S", ] cc_defaults { diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION index aefa36f2..bb850603 100644 --- a/BORINGSSL_REVISION +++ b/BORINGSSL_REVISION @@ -1 +1 @@ -68f37b7a3f451aa1ca8c93669c024d01f6270ae8 +7c5728649affe20e2952b11a0aeaf0e7b114aad9 @@ -178,42 +178,42 @@ const uint32_t kOpenSSLReasonValues[] = { 0x28340c19, 0x283480ac, 0x283500ea, - 0x2c32295b, - 0x2c32a969, - 0x2c33297b, - 0x2c33a98d, - 0x2c3429a1, - 0x2c34a9b3, - 0x2c3529ce, - 0x2c35a9e0, - 0x2c3629f3, + 0x2c32299a, + 0x2c32a9a8, + 0x2c3329ba, + 0x2c33a9cc, + 0x2c3429e0, + 0x2c34a9f2, + 0x2c352a0d, + 0x2c35aa1f, + 0x2c362a32, 0x2c36832d, - 0x2c372a00, - 0x2c37aa12, - 0x2c382a25, - 0x2c38aa3c, - 0x2c392a4a, - 0x2c39aa5a, - 0x2c3a2a6c, - 0x2c3aaa80, - 0x2c3b2a91, - 0x2c3baab0, - 0x2c3c2ac4, - 0x2c3caada, - 0x2c3d2af3, - 0x2c3dab10, - 0x2c3e2b21, - 0x2c3eab2f, - 0x2c3f2b47, - 0x2c3fab5f, - 0x2c402b6c, + 0x2c372a3f, + 0x2c37aa51, + 0x2c382a64, + 0x2c38aa7b, + 0x2c392a89, + 0x2c39aa99, + 0x2c3a2aab, + 0x2c3aaabf, + 0x2c3b2ad0, + 0x2c3baaef, + 0x2c3c2b03, + 0x2c3cab19, + 0x2c3d2b32, + 0x2c3dab4f, + 0x2c3e2b60, + 0x2c3eab6e, + 0x2c3f2b86, + 0x2c3fab9e, + 0x2c402bab, 0x2c4090e7, - 0x2c412b7d, - 0x2c41ab90, + 0x2c412bbc, + 0x2c41abcf, 0x2c4210c0, - 0x2c42aba1, + 0x2c42abe0, 0x2c430720, - 0x2c43aaa2, + 0x2c43aae1, 0x30320000, 0x30328015, 0x3033001f, @@ -439,64 +439,64 @@ const uint32_t kOpenSSLReasonValues[] = { 0x40601f92, 0x40609fb4, 0x40611ff8, - 0x4061a00d, - 0x40622024, - 0x4062a035, - 0x40632046, - 0x4063a05b, - 0x40642072, - 0x4064a09e, - 0x406520b9, - 0x4065a0d0, - 0x406620e8, - 0x4066a112, - 0x4067213d, - 0x4067a15e, - 0x40682171, - 0x4068a192, - 0x406921c4, - 0x4069a1f2, - 0x406a2213, - 0x406aa233, - 0x406b23bb, - 0x406ba3de, - 0x406c23f4, - 0x406ca656, - 0x406d2685, - 0x406da6ad, - 0x406e26db, - 0x406ea6f3, - 0x406f2712, - 0x406fa727, - 0x4070273a, - 0x4070a757, + 0x4061a030, + 0x40622047, + 0x4062a058, + 0x40632069, + 0x4063a07e, + 0x40642095, + 0x4064a0c1, + 0x406520dc, + 0x4065a0f3, + 0x4066210b, + 0x4066a135, + 0x40672160, + 0x4067a181, + 0x40682194, + 0x4068a1b5, + 0x406921e7, + 0x4069a215, + 0x406a2236, + 0x406aa256, + 0x406b23de, + 0x406ba401, + 0x406c2417, + 0x406ca679, + 0x406d26a8, + 0x406da6d0, + 0x406e26fe, + 0x406ea732, + 0x406f2751, + 0x406fa766, + 0x40702779, + 0x4070a796, 0x40710800, - 0x4071a769, - 0x4072277c, - 0x4072a795, - 0x407327ad, + 0x4071a7a8, + 0x407227bb, + 0x4072a7d4, + 0x407327ec, 0x4073936d, - 0x407427c1, - 0x4074a7db, - 0x407527ec, - 0x4075a800, - 0x4076280e, + 0x40742800, + 0x4074a81a, + 0x4075282b, + 0x4075a83f, + 0x4076284d, 0x407691aa, - 0x40772833, - 0x4077a855, - 0x40782870, - 0x4078a8a9, - 0x407928c0, - 0x4079a8d6, - 0x407a28e2, - 0x407aa8f5, - 0x407b290a, - 0x407ba91c, - 0x407c2931, - 0x407ca93a, - 0x407d21ad, + 0x40772872, + 0x4077a894, + 0x407828af, + 0x4078a8e8, + 0x407928ff, + 0x4079a915, + 0x407a2921, + 0x407aa934, + 0x407b2949, + 0x407ba95b, + 0x407c2970, + 0x407ca979, + 0x407d21d0, 0x407d9c57, - 0x407e2885, + 0x407e28c4, 0x407e9e27, 0x407f1a67, 0x407f9887, @@ -504,48 +504,50 @@ const uint32_t kOpenSSLReasonValues[] = { 0x40809a8f, 0x40811cea, 0x40819c08, - 0x408226c6, + 0x408226e9, 0x4082986d, 0x40831e02, - 0x4083a083, + 0x4083a0a6, 0x40841aa3, 0x40849e5f, 0x40851ee4, 0x40859fdc, 0x40861f38, 0x40869c71, - 0x41f422e6, - 0x41f92378, - 0x41fe226b, - 0x41fea447, - 0x41ff2538, - 0x420322ff, - 0x42082321, - 0x4208a35d, - 0x4209224f, - 0x4209a397, - 0x420a22a6, - 0x420aa286, - 0x420b22c6, - 0x420ba33f, - 0x420c2554, - 0x420ca414, - 0x420d242e, - 0x420da465, - 0x4212247f, - 0x4217251b, - 0x4217a4c1, - 0x421c24e3, - 0x421f249e, - 0x4221256b, - 0x422624fe, - 0x422b263a, - 0x422ba5e8, - 0x422c2622, - 0x422ca5a7, - 0x422d2586, - 0x422da607, - 0x422e25cd, + 0x40872716, + 0x4087a00d, + 0x41f42309, + 0x41f9239b, + 0x41fe228e, + 0x41fea46a, + 0x41ff255b, + 0x42032322, + 0x42082344, + 0x4208a380, + 0x42092272, + 0x4209a3ba, + 0x420a22c9, + 0x420aa2a9, + 0x420b22e9, + 0x420ba362, + 0x420c2577, + 0x420ca437, + 0x420d2451, + 0x420da488, + 0x421224a2, + 0x4217253e, + 0x4217a4e4, + 0x421c2506, + 0x421f24c1, + 0x4221258e, + 0x42262521, + 0x422b265d, + 0x422ba60b, + 0x422c2645, + 0x422ca5ca, + 0x422d25a9, + 0x422da62a, + 0x422e25f0, 0x4432072b, 0x4432873a, 0x44330746, @@ -588,69 +590,69 @@ const uint32_t kOpenSSLReasonValues[] = { 0x4c3d136d, 0x4c3d937c, 0x4c3e1389, - 0x50322bb3, - 0x5032abc2, - 0x50332bcd, - 0x5033abdd, - 0x50342bf6, - 0x5034ac10, - 0x50352c1e, - 0x5035ac34, - 0x50362c46, - 0x5036ac5c, - 0x50372c75, - 0x5037ac88, - 0x50382ca0, - 0x5038acb1, - 0x50392cc6, - 0x5039acda, - 0x503a2cfa, - 0x503aad10, - 0x503b2d28, - 0x503bad3a, - 0x503c2d56, - 0x503cad6d, - 0x503d2d86, - 0x503dad9c, - 0x503e2da9, - 0x503eadbf, - 0x503f2dd1, + 0x50322bf2, + 0x5032ac01, + 0x50332c0c, + 0x5033ac1c, + 0x50342c35, + 0x5034ac4f, + 0x50352c5d, + 0x5035ac73, + 0x50362c85, + 0x5036ac9b, + 0x50372cb4, + 0x5037acc7, + 0x50382cdf, + 0x5038acf0, + 0x50392d05, + 0x5039ad19, + 0x503a2d39, + 0x503aad4f, + 0x503b2d67, + 0x503bad79, + 0x503c2d95, + 0x503cadac, + 0x503d2dc5, + 0x503daddb, + 0x503e2de8, + 0x503eadfe, + 0x503f2e10, 0x503f8382, - 0x50402de4, - 0x5040adf4, - 0x50412e0e, - 0x5041ae1d, - 0x50422e37, - 0x5042ae54, - 0x50432e64, - 0x5043ae74, - 0x50442e83, + 0x50402e23, + 0x5040ae33, + 0x50412e4d, + 0x5041ae5c, + 0x50422e76, + 0x5042ae93, + 0x50432ea3, + 0x5043aeb3, + 0x50442ec2, 0x5044843f, - 0x50452e97, - 0x5045aeb5, - 0x50462ec8, - 0x5046aede, - 0x50472ef0, - 0x5047af05, - 0x50482f2b, - 0x5048af39, - 0x50492f4c, - 0x5049af61, - 0x504a2f77, - 0x504aaf87, - 0x504b2fa7, - 0x504bafba, - 0x504c2fdd, - 0x504cb00b, - 0x504d301d, - 0x504db03a, - 0x504e3055, - 0x504eb071, - 0x504f3083, - 0x504fb09a, - 0x505030a9, + 0x50452ed6, + 0x5045aef4, + 0x50462f07, + 0x5046af1d, + 0x50472f2f, + 0x5047af44, + 0x50482f6a, + 0x5048af78, + 0x50492f8b, + 0x5049afa0, + 0x504a2fb6, + 0x504aafc6, + 0x504b2fe6, + 0x504baff9, + 0x504c301c, + 0x504cb04a, + 0x504d305c, + 0x504db079, + 0x504e3094, + 0x504eb0b0, + 0x504f30c2, + 0x504fb0d9, + 0x505030e8, 0x505086ef, - 0x505130bc, + 0x505130fb, 0x58320ec9, 0x68320e8b, 0x68328c25, @@ -1098,6 +1100,7 @@ const char kOpenSSLReasonStringData[] = "PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE\0" "PRE_SHARED_KEY_MUST_BE_LAST\0" "PROTOCOL_IS_SHUTDOWN\0" + "PSK_IDENTITY_BINDER_COUNT_MISMATCH\0" "PSK_IDENTITY_NOT_FOUND\0" "PSK_NO_CLIENT_CB\0" "PSK_NO_SERVER_CB\0" @@ -1159,6 +1162,7 @@ const char kOpenSSLReasonStringData[] = "TOO_MANY_EMPTY_FRAGMENTS\0" "TOO_MANY_KEY_UPDATES\0" "TOO_MANY_WARNING_ALERTS\0" + "TOO_MUCH_SKIPPED_EARLY_DATA\0" "UNABLE_TO_FIND_ECDH_PARAMETERS\0" "UNEXPECTED_EXTENSION\0" "UNEXPECTED_MESSAGE\0" diff --git a/linux-arm/crypto/sha/sha256-armv4.S b/linux-arm/crypto/sha/sha256-armv4.S index 60400413..f37fd7c7 100644 --- a/linux-arm/crypto/sha/sha256-armv4.S +++ b/linux-arm/crypto/sha/sha256-armv4.S @@ -1,4 +1,11 @@ #if defined(__arm__) +@ Copyright 2007-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 @@ -45,16 +52,11 @@ #endif .text -#if __ARM_ARCH__<7 -.code 32 -#else +#if defined(__thumb2__) .syntax unified -# if defined(__thumb2__) && !defined(__APPLE__) -# define adrl adr .thumb -# else +#else .code 32 -# endif #endif .type K256,%object @@ -89,10 +91,10 @@ K256: .type sha256_block_data_order,%function sha256_block_data_order: .Lsha256_block_data_order: -#if __ARM_ARCH__<7 +#if __ARM_ARCH__<7 && !defined(__thumb2__) sub r3,pc,#8 @ sha256_block_data_order #else - adr r3,sha256_block_data_order + adr r3,.Lsha256_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap @@ -1878,13 +1880,14 @@ sha256_block_data_order: .globl sha256_block_data_order_neon .hidden sha256_block_data_order_neon .type sha256_block_data_order_neon,%function -.align 4 +.align 5 +.skip 16 sha256_block_data_order_neon: .LNEON: stmdb sp!,{r4,r5,r6,r7,r8,r9,r10,r11,r12,lr} sub r11,sp,#16*4+16 - adrl r14,K256 + adr r14,K256 bic r11,r11,#15 @ align for 128-bit stores mov r12,sp mov sp,r11 @ alloca @@ -2660,7 +2663,7 @@ sha256_block_data_order_neon: #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) -# if defined(__thumb2__) && !defined(__APPLE__) +# if defined(__thumb2__) # define INST(a,b,c,d) .byte c,d|0xc,a,b # else # define INST(a,b,c,d) .byte a,b,c,d @@ -2671,16 +2674,11 @@ sha256_block_data_order_neon: sha256_block_data_order_armv8: .LARMv8: vld1.32 {q0,q1},[r0] -# ifdef __APPLE__ sub r3,r3,#256+32 -# elif defined(__thumb2__) - adr r3,.LARMv8 - sub r3,r3,#.LARMv8-K256 -# else - adrl r3,K256 -# endif add r2,r1,r2,lsl#6 @ len to point at the end of inp + b .Loop_v8 +.align 4 .Loop_v8: vld1.8 {q8,q9},[r1]! vld1.8 {q10,q11},[r1]! @@ -163,6 +163,7 @@ cc_defaults { "src/crypto/modes/ctr.c", "src/crypto/modes/gcm.c", "src/crypto/modes/ofb.c", + "src/crypto/modes/polyval.c", "src/crypto/newhope/error_correction.c", "src/crypto/newhope/newhope.c", "src/crypto/newhope/ntt.c", @@ -161,6 +161,7 @@ crypto_sources := \ src/crypto/modes/ctr.c\ src/crypto/modes/gcm.c\ src/crypto/modes/ofb.c\ + src/crypto/modes/polyval.c\ src/crypto/newhope/error_correction.c\ src/crypto/newhope/newhope.c\ src/crypto/newhope/ntt.c\ diff --git a/src/.gitignore b/src/.gitignore index a2e3ed2a..9f396f67 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -4,3 +4,18 @@ ssl/test/runner/runner *.swo doc/*.html doc/doc.css + +util/bot/android_tools +util/bot/cmake-linux64 +util/bot/cmake-linux64.tar.gz +util/bot/cmake-mac +util/bot/cmake-mac.tar.gz +util/bot/cmake-win32 +util/bot/cmake-win32.zip +util/bot/golang +util/bot/gyp +util/bot/llvm-build +util/bot/perl-win32 +util/bot/perl-win32.zip +util/bot/win_toolchain.json +util/bot/yasm-win32.exe diff --git a/src/FUZZING.md b/src/FUZZING.md index f004c27d..77c50c17 100644 --- a/src/FUZZING.md +++ b/src/FUZZING.md @@ -37,6 +37,7 @@ The recommended values of `max_len` for each test are: | `pkcs8` | 2048 | | `privkey` | 2048 | | `server` | 4096 | +| `session` | 8192 | | `spki` | 1024 | | `read_pem` | 512 | | `ssl_ctx_api` | 256 | diff --git a/src/crypto/bio/bio_test.cc b/src/crypto/bio/bio_test.cc index 01b93f60..4ae6c6e1 100644 --- a/src/crypto/bio/bio_test.cc +++ b/src/crypto/bio/bio_test.cc @@ -135,152 +135,6 @@ static bool TestSocketConnect() { return true; } - -// BioReadZeroCopyWrapper is a wrapper around the zero-copy APIs to make -// testing easier. -static size_t BioReadZeroCopyWrapper(BIO *bio, uint8_t *data, size_t len) { - uint8_t *read_buf; - size_t read_buf_offset; - size_t available_bytes; - size_t len_read = 0; - - do { - if (!BIO_zero_copy_get_read_buf(bio, &read_buf, &read_buf_offset, - &available_bytes)) { - return 0; - } - - available_bytes = std::min(available_bytes, len - len_read); - memmove(data + len_read, read_buf + read_buf_offset, available_bytes); - - BIO_zero_copy_get_read_buf_done(bio, available_bytes); - - len_read += available_bytes; - } while (len - len_read > 0 && available_bytes > 0); - - return len_read; -} - -// BioWriteZeroCopyWrapper is a wrapper around the zero-copy APIs to make -// testing easier. -static size_t BioWriteZeroCopyWrapper(BIO *bio, const uint8_t *data, - size_t len) { - uint8_t *write_buf; - size_t write_buf_offset; - size_t available_bytes; - size_t len_written = 0; - - do { - if (!BIO_zero_copy_get_write_buf(bio, &write_buf, &write_buf_offset, - &available_bytes)) { - return 0; - } - - available_bytes = std::min(available_bytes, len - len_written); - memmove(write_buf + write_buf_offset, data + len_written, available_bytes); - - BIO_zero_copy_get_write_buf_done(bio, available_bytes); - - len_written += available_bytes; - } while (len - len_written > 0 && available_bytes > 0); - - return len_written; -} - -static bool TestZeroCopyBioPairs() { - // Test read and write, especially triggering the ring buffer wrap-around. - uint8_t bio1_application_send_buffer[1024]; - uint8_t bio2_application_recv_buffer[1024]; - - const size_t kLengths[] = {254, 255, 256, 257, 510, 511, 512, 513}; - - // These trigger ring buffer wrap around. - const size_t kPartialLengths[] = {0, 1, 2, 3, 128, 255, 256, 257, 511, 512}; - - static const size_t kBufferSize = 512; - - srand(1); - for (size_t i = 0; i < sizeof(bio1_application_send_buffer); i++) { - bio1_application_send_buffer[i] = rand() & 255; - } - - // Transfer bytes from bio1_application_send_buffer to - // bio2_application_recv_buffer in various ways. - for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kLengths); i++) { - for (size_t j = 0; j < OPENSSL_ARRAY_SIZE(kPartialLengths); j++) { - size_t total_write = 0; - size_t total_read = 0; - - BIO *bio1, *bio2; - if (!BIO_new_bio_pair(&bio1, kBufferSize, &bio2, kBufferSize)) { - return false; - } - bssl::UniquePtr<BIO> bio1_scoper(bio1); - bssl::UniquePtr<BIO> bio2_scoper(bio2); - - total_write += BioWriteZeroCopyWrapper( - bio1, bio1_application_send_buffer, kLengths[i]); - - // This tests interleaved read/write calls. Do a read between zero copy - // write calls. - uint8_t *write_buf; - size_t write_buf_offset; - size_t available_bytes; - if (!BIO_zero_copy_get_write_buf(bio1, &write_buf, &write_buf_offset, - &available_bytes)) { - return false; - } - - // Free kPartialLengths[j] bytes in the beginning of bio1 write buffer. - // This enables ring buffer wrap around for the next write. - total_read += BIO_read(bio2, bio2_application_recv_buffer + total_read, - kPartialLengths[j]); - - size_t interleaved_write_len = std::min(kPartialLengths[j], - available_bytes); - - // Write the data for the interleaved write call. If the buffer becomes - // empty after a read, the write offset is normally set to 0. Check that - // this does not happen for interleaved read/write and that - // |write_buf_offset| is still valid. - memcpy(write_buf + write_buf_offset, - bio1_application_send_buffer + total_write, interleaved_write_len); - if (BIO_zero_copy_get_write_buf_done(bio1, interleaved_write_len)) { - total_write += interleaved_write_len; - } - - // Do another write in case |write_buf_offset| was wrapped. - total_write += BioWriteZeroCopyWrapper( - bio1, bio1_application_send_buffer + total_write, - kPartialLengths[j] - interleaved_write_len); - - // Drain the rest. - size_t bytes_left = BIO_pending(bio2); - total_read += BioReadZeroCopyWrapper( - bio2, bio2_application_recv_buffer + total_read, bytes_left); - - if (total_read != total_write) { - fprintf(stderr, "Lengths not equal in round (%u, %u)\n", (unsigned)i, - (unsigned)j); - return false; - } - if (total_read > kLengths[i] + kPartialLengths[j]) { - fprintf(stderr, "Bad lengths in round (%u, %u)\n", (unsigned)i, - (unsigned)j); - return false; - } - if (memcmp(bio1_application_send_buffer, bio2_application_recv_buffer, - total_read) != 0) { - fprintf(stderr, "Buffers not equal in round (%u, %u)\n", (unsigned)i, - (unsigned)j); - return false; - } - } - } - - return true; -} - static bool TestPrintf() { // Test a short output, a very long one, and various sizes around // 256 (the size of the buffer) to ensure edge cases are correct. @@ -409,7 +263,137 @@ static bool TestASN1() { return true; } -int main(void) { +static bool TestPair() { + // Run through the tests twice, swapping |bio1| and |bio2|, for symmetry. + for (int i = 0; i < 2; i++) { + BIO *bio1, *bio2; + if (!BIO_new_bio_pair(&bio1, 10, &bio2, 10)) { + return false; + } + bssl::UniquePtr<BIO> free_bio1(bio1), free_bio2(bio2); + + if (i == 1) { + std::swap(bio1, bio2); + } + + // Check initial states. + if (BIO_ctrl_get_write_guarantee(bio1) != 10 || + BIO_ctrl_get_read_request(bio1) != 0) { + return false; + } + + // Data written in one end may be read out the other. + char buf[20]; + if (BIO_write(bio1, "12345", 5) != 5 || + BIO_ctrl_get_write_guarantee(bio1) != 5 || + BIO_read(bio2, buf, sizeof(buf)) != 5 || + memcmp(buf, "12345", 5) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 10) { + return false; + } + + // Attempting to write more than 10 bytes will write partially. + if (BIO_write(bio1, "1234567890___", 13) != 10 || + BIO_ctrl_get_write_guarantee(bio1) != 0 || + BIO_write(bio1, "z", 1) != -1 || + !BIO_should_write(bio1) || + BIO_read(bio2, buf, sizeof(buf)) != 10 || + memcmp(buf, "1234567890", 10) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 10) { + return false; + } + + // Unsuccessful reads update the read request. + if (BIO_read(bio2, buf, 5) != -1 || + !BIO_should_read(bio2) || + BIO_ctrl_get_read_request(bio1) != 5) { + return false; + } + + // The read request is clamped to the size of the buffer. + if (BIO_read(bio2, buf, 20) != -1 || + !BIO_should_read(bio2) || + BIO_ctrl_get_read_request(bio1) != 10) { + return false; + } + + // Data may be written and read in chunks. + if (BIO_write(bio1, "12345", 5) != 5 || + BIO_ctrl_get_write_guarantee(bio1) != 5 || + BIO_write(bio1, "67890___", 8) != 5 || + BIO_ctrl_get_write_guarantee(bio1) != 0 || + BIO_read(bio2, buf, 3) != 3 || + memcmp(buf, "123", 3) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 3 || + BIO_read(bio2, buf, sizeof(buf)) != 7 || + memcmp(buf, "4567890", 7) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 10) { + return false; + } + + // Successful reads reset the read request. + if (BIO_ctrl_get_read_request(bio1) != 0) { + return false; + } + + // Test writes and reads starting in the middle of the ring buffer and + // wrapping to front. + if (BIO_write(bio1, "abcdefgh", 8) != 8 || + BIO_ctrl_get_write_guarantee(bio1) != 2 || + BIO_read(bio2, buf, 3) != 3 || + memcmp(buf, "abc", 3) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 5 || + BIO_write(bio1, "ijklm___", 8) != 5 || + BIO_ctrl_get_write_guarantee(bio1) != 0 || + BIO_read(bio2, buf, sizeof(buf)) != 10 || + memcmp(buf, "defghijklm", 10) != 0 || + BIO_ctrl_get_write_guarantee(bio1) != 10) { + return false; + } + + // Data may flow from both ends in parallel. + if (BIO_write(bio1, "12345", 5) != 5 || + BIO_write(bio2, "67890", 5) != 5 || + BIO_read(bio2, buf, sizeof(buf)) != 5 || + memcmp(buf, "12345", 5) != 0 || + BIO_read(bio1, buf, sizeof(buf)) != 5 || + memcmp(buf, "67890", 5) != 0) { + return false; + } + + // Closing the write end causes an EOF on the read half, after draining. + if (BIO_write(bio1, "12345", 5) != 5 || + !BIO_shutdown_wr(bio1) || + BIO_read(bio2, buf, sizeof(buf)) != 5 || + memcmp(buf, "12345", 5) != 0 || + BIO_read(bio2, buf, sizeof(buf)) != 0) { + return false; + } + + // A closed write end may not be written to. + if (BIO_ctrl_get_write_guarantee(bio1) != 0 || + BIO_write(bio1, "_____", 5) != -1) { + return false; + } + + uint32_t err = ERR_get_error(); + if (ERR_GET_LIB(err) != ERR_LIB_BIO || + ERR_GET_REASON(err) != BIO_R_BROKEN_PIPE) { + return false; + } + + // The other end is still functional. + if (BIO_write(bio2, "12345", 5) != 5 || + BIO_read(bio1, buf, sizeof(buf)) != 5 || + memcmp(buf, "12345", 5) != 0) { + return false; + } + } + + return true; +} + +int main() { CRYPTO_library_init(); #if defined(OPENSSL_WINDOWS) @@ -429,8 +413,8 @@ int main(void) { if (!TestSocketConnect() || !TestPrintf() || - !TestZeroCopyBioPairs() || - !TestASN1()) { + !TestASN1() || + !TestPair()) { return 1; } diff --git a/src/crypto/bio/pair.c b/src/crypto/bio/pair.c index 2da2d203..df36343a 100644 --- a/src/crypto/bio/pair.c +++ b/src/crypto/bio/pair.c @@ -72,12 +72,6 @@ struct bio_bio_st { size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ size_t size; uint8_t *buf; /* "size" elements (if != NULL) */ - char buf_externally_allocated; /* true iff buf was externally allocated. */ - - char zero_copy_read_lock; /* true iff a zero copy read operation - * is in progress. */ - char zero_copy_write_lock; /* true iff a zero copy write operation - * is in progress. */ size_t request; /* valid iff peer != NULL; 0 if len != 0, * otherwise set by peer to number of bytes @@ -145,263 +139,12 @@ static int bio_free(BIO *bio) { bio_destroy_pair(bio); } - if (!b->buf_externally_allocated) { - OPENSSL_free(b->buf); - } - + OPENSSL_free(b->buf); OPENSSL_free(b); return 1; } -static size_t bio_zero_copy_get_read_buf(struct bio_bio_st* peer_b, - uint8_t** out_read_buf, - size_t* out_buf_offset) { - size_t max_available; - if (peer_b->len > peer_b->size - peer_b->offset) { - /* Only the first half of the ring buffer can be read. */ - max_available = peer_b->size - peer_b->offset; - } else { - max_available = peer_b->len; - } - - *out_read_buf = peer_b->buf; - *out_buf_offset = peer_b->offset; - return max_available; -} - -int BIO_zero_copy_get_read_buf(BIO* bio, uint8_t** out_read_buf, - size_t* out_buf_offset, - size_t* out_available_bytes) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - *out_available_bytes = 0; - - BIO_clear_retry_flags(bio); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - if (peer_b->zero_copy_read_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - peer_b->request = 0; /* Is not used by zero-copy API. */ - - max_available = - bio_zero_copy_get_read_buf(peer_b, out_read_buf, out_buf_offset); - - assert(peer_b->buf != NULL); - if (max_available > 0) { - peer_b->zero_copy_read_lock = 1; - } - - *out_available_bytes = max_available; - return 1; -} - -int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - size_t dummy_read_offset; - uint8_t* dummy_read_buf; - - assert(BIO_get_retry_flags(bio) == 0); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - if (!peer_b->zero_copy_read_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - max_available = - bio_zero_copy_get_read_buf(peer_b, &dummy_read_buf, &dummy_read_offset); - if (bytes_read > max_available) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - assert(peer_b->len >= bytes_read); - peer_b->len -= bytes_read; - assert(peer_b->offset + bytes_read <= peer_b->size); - - /* Move read offset. If zero_copy_write_lock == 1 we must advance the - * offset even if buffer becomes empty, to make sure - * write_offset = (offset + len) mod size does not change. */ - if (peer_b->offset + bytes_read == peer_b->size || - (!peer_b->zero_copy_write_lock && peer_b->len == 0)) { - peer_b->offset = 0; - } else { - peer_b->offset += bytes_read; - } - - bio->num_read += bytes_read; - peer_b->zero_copy_read_lock = 0; - return 1; -} - -static size_t bio_zero_copy_get_write_buf(struct bio_bio_st* b, - uint8_t** out_write_buf, - size_t* out_buf_offset) { - size_t write_offset; - size_t max_available; - - assert(b->len <= b->size); - - write_offset = b->offset + b->len; - - if (write_offset >= b->size) { - /* Only the first half of the ring buffer can be written to. */ - write_offset -= b->size; - /* write up to the start of the ring buffer. */ - max_available = b->offset - write_offset; - } else { - /* write up to the end the buffer. */ - max_available = b->size - write_offset; - } - - *out_write_buf = b->buf; - *out_buf_offset = write_offset; - return max_available; -} - -int BIO_zero_copy_get_write_buf(BIO* bio, uint8_t** out_write_buf, - size_t* out_buf_offset, - size_t* out_available_bytes) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - size_t max_available; - - *out_available_bytes = 0; - BIO_clear_retry_flags(bio); - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->buf || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - assert(b->buf != NULL); - - if (b->zero_copy_write_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - b->request = 0; - if (b->closed) { - /* Bio is already closed. */ - OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); - return 0; - } - - max_available = bio_zero_copy_get_write_buf(b, out_write_buf, out_buf_offset); - - if (max_available > 0) { - b->zero_copy_write_lock = 1; - } - - *out_available_bytes = max_available; - return 1; -} - -int BIO_zero_copy_get_write_buf_done(BIO* bio, size_t bytes_written) { - struct bio_bio_st* b; - struct bio_bio_st* peer_b; - - size_t rest; - size_t dummy_write_offset; - uint8_t* dummy_write_buf; - - if (!bio->init) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNINITIALIZED); - return 0; - } - - b = bio->ptr; - - if (!b || !b->buf || !b->peer) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - peer_b = b->peer->ptr; - if (!peer_b || !peer_b->peer || peer_b->peer->ptr != b) { - OPENSSL_PUT_ERROR(BIO, BIO_R_UNSUPPORTED_METHOD); - return 0; - } - - b->request = 0; - if (b->closed) { - /* BIO is already closed. */ - OPENSSL_PUT_ERROR(BIO, BIO_R_BROKEN_PIPE); - return 0; - } - - if (!b->zero_copy_write_lock) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - rest = bio_zero_copy_get_write_buf(b, &dummy_write_buf, &dummy_write_offset); - - if (bytes_written > rest) { - OPENSSL_PUT_ERROR(BIO, BIO_R_INVALID_ARGUMENT); - return 0; - } - - bio->num_write += bytes_written; - /* Move write offset. */ - b->len += bytes_written; - b->zero_copy_write_lock = 0; - return 1; -} - static int bio_read(BIO *bio, char *buf, int size_) { size_t size = size_; size_t rest; @@ -422,7 +165,7 @@ static int bio_read(BIO *bio, char *buf, int size_) { peer_b->request = 0; /* will be set in "retry_read" situation */ - if (buf == NULL || size == 0 || peer_b->zero_copy_read_lock) { + if (buf == NULL || size == 0) { return 0; } @@ -467,10 +210,7 @@ static int bio_read(BIO *bio, char *buf, int size_) { memcpy(buf, peer_b->buf + peer_b->offset, chunk); peer_b->len -= chunk; - /* If zero_copy_write_lock == 1 we must advance the offset even if buffer - * becomes empty, to make sure write_offset = (offset + len) % size - * does not change. */ - if (peer_b->len || peer_b->zero_copy_write_lock) { + if (peer_b->len) { peer_b->offset += chunk; assert(peer_b->offset <= peer_b->size); if (peer_b->offset == peer_b->size) { @@ -504,10 +244,6 @@ static int bio_write(BIO *bio, const char *buf, int num_) { assert(b->peer != NULL); assert(b->buf != NULL); - if (b->zero_copy_write_lock) { - return 0; - } - b->request = 0; if (b->closed) { /* we already closed */ @@ -564,9 +300,8 @@ static int bio_write(BIO *bio, const char *buf, int num_) { return num; } -static int bio_make_pair(BIO* bio1, BIO* bio2, - size_t writebuf1_len, uint8_t* ext_writebuf1, - size_t writebuf2_len, uint8_t* ext_writebuf2) { +static int bio_make_pair(BIO *bio1, BIO *bio2, size_t writebuf1_len, + size_t writebuf2_len) { struct bio_bio_st *b1, *b2; assert(bio1 != NULL); @@ -580,23 +315,14 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, return 0; } - assert(b1->buf_externally_allocated == 0); - assert(b2->buf_externally_allocated == 0); - if (b1->buf == NULL) { if (writebuf1_len) { b1->size = writebuf1_len; } - if (!ext_writebuf1) { - b1->buf_externally_allocated = 0; - b1->buf = OPENSSL_malloc(b1->size); - if (b1->buf == NULL) { - OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); - return 0; - } - } else { - b1->buf = ext_writebuf1; - b1->buf_externally_allocated = 1; + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; } b1->len = 0; b1->offset = 0; @@ -606,16 +332,10 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, if (writebuf2_len) { b2->size = writebuf2_len; } - if (!ext_writebuf2) { - b2->buf_externally_allocated = 0; - b2->buf = OPENSSL_malloc(b2->size); - if (b2->buf == NULL) { - OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); - return 0; - } - } else { - b2->buf = ext_writebuf2; - b2->buf_externally_allocated = 1; + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + OPENSSL_PUT_ERROR(BIO, ERR_R_MALLOC_FAILURE); + return 0; } b2->len = 0; b2->offset = 0; @@ -624,13 +344,9 @@ static int bio_make_pair(BIO* bio1, BIO* bio2, b1->peer = bio2; b1->closed = 0; b1->request = 0; - b1->zero_copy_read_lock = 0; - b1->zero_copy_write_lock = 0; b2->peer = bio1; b2->closed = 0; b2->request = 0; - b2->zero_copy_read_lock = 0; - b2->zero_copy_write_lock = 0; bio1->init = 1; bio2->init = 1; @@ -744,50 +460,22 @@ static const BIO_METHOD methods_biop = { static const BIO_METHOD *bio_s_bio(void) { return &methods_biop; } -int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1, - BIO** bio2_p, size_t writebuf2) { - return BIO_new_bio_pair_external_buf(bio1_p, writebuf1, NULL, bio2_p, - writebuf2, NULL); -} - -int BIO_new_bio_pair_external_buf(BIO** bio1_p, size_t writebuf1_len, - uint8_t* ext_writebuf1, - BIO** bio2_p, size_t writebuf2_len, - uint8_t* ext_writebuf2) { - BIO *bio1 = NULL, *bio2 = NULL; - int ret = 0; - - /* External buffers must have sizes greater than 0. */ - if ((ext_writebuf1 && !writebuf1_len) || (ext_writebuf2 && !writebuf2_len)) { - goto err; - } - - bio1 = BIO_new(bio_s_bio()); - if (bio1 == NULL) { - goto err; - } - bio2 = BIO_new(bio_s_bio()); - if (bio2 == NULL) { - goto err; - } - - if (!bio_make_pair(bio1, bio2, writebuf1_len, ext_writebuf1, writebuf2_len, - ext_writebuf2)) { - goto err; - } - ret = 1; - -err: - if (ret == 0) { +int BIO_new_bio_pair(BIO** bio1_p, size_t writebuf1_len, + BIO** bio2_p, size_t writebuf2_len) { + BIO *bio1 = BIO_new(bio_s_bio()); + BIO *bio2 = BIO_new(bio_s_bio()); + if (bio1 == NULL || bio2 == NULL || + !bio_make_pair(bio1, bio2, writebuf1_len, writebuf2_len)) { BIO_free(bio1); - bio1 = NULL; BIO_free(bio2); - bio2 = NULL; + *bio1_p = NULL; + *bio2_p = NULL; + return 0; } *bio1_p = bio1; *bio2_p = bio2; - return ret; + return 1; } size_t BIO_ctrl_get_read_request(BIO *bio) { diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc index 672d83f1..044af5fe 100644 --- a/src/crypto/bn/bn_test.cc +++ b/src/crypto/bn/bn_test.cc @@ -568,21 +568,25 @@ static bool TestModSqrt(FileTest *t, BN_CTX *ctx) { bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A"); bssl::UniquePtr<BIGNUM> p = GetBIGNUM(t, "P"); bssl::UniquePtr<BIGNUM> mod_sqrt = GetBIGNUM(t, "ModSqrt"); - if (!a || !p || !mod_sqrt) { + bssl::UniquePtr<BIGNUM> mod_sqrt2(BN_new()); + if (!a || !p || !mod_sqrt || !mod_sqrt2 || + // There are two possible answers. + !BN_sub(mod_sqrt2.get(), p.get(), mod_sqrt.get())) { return false; } + // -0 is 0, not P. + if (BN_is_zero(mod_sqrt.get())) { + BN_zero(mod_sqrt2.get()); + } + bssl::UniquePtr<BIGNUM> ret(BN_new()); - bssl::UniquePtr<BIGNUM> ret2(BN_new()); if (!ret || - !ret2 || - !BN_mod_sqrt(ret.get(), a.get(), p.get(), ctx) || - // There are two possible answers. - !BN_sub(ret2.get(), p.get(), ret.get())) { + !BN_mod_sqrt(ret.get(), a.get(), p.get(), ctx)) { return false; } - if (BN_cmp(ret2.get(), mod_sqrt.get()) != 0 && + if (BN_cmp(ret.get(), mod_sqrt2.get()) != 0 && !ExpectBIGNUMsEqual(t, "sqrt(A) (mod P)", mod_sqrt.get(), ret.get())) { return false; } @@ -590,6 +594,29 @@ static bool TestModSqrt(FileTest *t, BN_CTX *ctx) { return true; } +static bool TestNotModSquare(FileTest *t, BN_CTX *ctx) { + bssl::UniquePtr<BIGNUM> not_mod_square = GetBIGNUM(t, "NotModSquare"); + bssl::UniquePtr<BIGNUM> p = GetBIGNUM(t, "P"); + bssl::UniquePtr<BIGNUM> ret(BN_new()); + if (!not_mod_square || !p || !ret) { + return false; + } + + if (BN_mod_sqrt(ret.get(), not_mod_square.get(), p.get(), ctx)) { + t->PrintLine("BN_mod_sqrt unexpectedly succeeded."); + return false; + } + + uint32_t err = ERR_peek_error(); + if (ERR_GET_LIB(err) == ERR_LIB_BN && + ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) { + ERR_clear_error(); + return true; + } + + return false; +} + static bool TestModInv(FileTest *t, BN_CTX *ctx) { bssl::UniquePtr<BIGNUM> a = GetBIGNUM(t, "A"); bssl::UniquePtr<BIGNUM> m = GetBIGNUM(t, "M"); @@ -634,6 +661,7 @@ static const Test kTests[] = { {"ModExp", TestModExp}, {"Exp", TestExp}, {"ModSqrt", TestModSqrt}, + {"NotModSquare", TestNotModSquare}, {"ModInv", TestModInv}, }; diff --git a/src/crypto/bn/bn_tests.txt b/src/crypto/bn/bn_tests.txt index 692a6429..ec89b8e4 100644 --- a/src/crypto/bn/bn_tests.txt +++ b/src/crypto/bn/bn_tests.txt @@ -10737,6 +10737,28 @@ ModSqrt = a1d52989f12f204d3d2167d9b1e6c8a6174c0c786a979a5952383b7b8bd186 A = 2eee37cf06228a387788188e650bc6d8a2ff402931443f69156a29155eca07dcb45f3aac238d92943c0c25c896098716baa433f25bd696a142f5a69d5d937e81 P = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f + +# NotModSquare tests. +# +# These test vectors are such that NotModSquare is not a square modulo P. + +NotModSquare = 03 +P = 07 + +NotModSquare = 05 +P = 07 + +NotModSquare = 06 +P = 07 + +NotModSquare = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951e +P = 9df9d6cc20b8540411af4e5357ef2b0353cb1f2ab5ffc3e246b41c32f71e951f + + +# ModInv tests. +# +# These test vectors satisfy ModInv * A = 1 (mod M) and 0 <= ModInv < M. + ModInv = 00 A = 00 M = 01 diff --git a/src/crypto/bn/sqrt.c b/src/crypto/bn/sqrt.c index e3a7b9ac..fb962a98 100644 --- a/src/crypto/bn/sqrt.c +++ b/src/crypto/bn/sqrt.c @@ -456,7 +456,9 @@ int BN_sqrt(BIGNUM *out_sqrt, const BIGNUM *in, BN_CTX *ctx) { } /* We estimate that the square root of an n-bit number is 2^{n/2}. */ - BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2); + if (!BN_lshift(estimate, BN_value_one(), BN_num_bits(in)/2)) { + goto err; + } /* This is Newton's method for finding a root of the equation |estimate|^2 - * |in| = 0. */ diff --git a/src/crypto/bytestring/bytestring_test.cc b/src/crypto/bytestring/bytestring_test.cc index 563c6b0e..6ce071a4 100644 --- a/src/crypto/bytestring/bytestring_test.cc +++ b/src/crypto/bytestring/bytestring_test.cc @@ -28,7 +28,6 @@ #include "internal.h" #include "../internal.h" -namespace bssl { static bool TestSkip() { static const uint8_t kData[] = {1, 2, 3}; @@ -317,7 +316,7 @@ static bool TestCBBBasic() { } static bool TestCBBFixed() { - ScopedCBB cbb; + bssl::ScopedCBB cbb; uint8_t buf[1]; uint8_t *out_buf; size_t out_size; @@ -401,7 +400,7 @@ static bool TestCBBPrefixed() { } static bool TestCBBDiscardChild() { - ScopedCBB cbb; + bssl::ScopedCBB cbb; CBB contents, inner_contents, inner_inner_contents; if (!CBB_init(cbb.get(), 0) || @@ -804,7 +803,7 @@ static bool TestCBBReserve() { uint8_t buf[10]; uint8_t *ptr; size_t len; - ScopedCBB cbb; + bssl::ScopedCBB cbb; if (!CBB_init_fixed(cbb.get(), buf, sizeof(buf)) || // Too large. CBB_reserve(cbb.get(), &ptr, 11)) { @@ -827,7 +826,7 @@ static bool TestCBBReserve() { static bool TestStickyError() { // Write an input that exceeds the limit for its length prefix. - ScopedCBB cbb; + bssl::ScopedCBB cbb; CBB child; static const uint8_t kZeros[256] = {0}; if (!CBB_init(cbb.get(), 0) || @@ -890,7 +889,7 @@ static bool TestStickyError() { return true; } -static int Main() { +int main() { CRYPTO_library_init(); if (!TestSkip() || @@ -918,9 +917,3 @@ static int Main() { printf("PASS\n"); return 0; } - -} // namespace bssl - -int main() { - return bssl::Main(); -} diff --git a/src/crypto/cipher/aead_test.cc b/src/crypto/cipher/aead_test.cc index b33a36df..313f0411 100644 --- a/src/crypto/cipher/aead_test.cc +++ b/src/crypto/cipher/aead_test.cc @@ -23,7 +23,15 @@ #include "../test/file_test.h" -namespace bssl { + +#if defined(OPENSSL_SMALL) +const EVP_AEAD* EVP_aead_aes_128_gcm_siv(void) { + return nullptr; +} +const EVP_AEAD* EVP_aead_aes_256_gcm_siv(void) { + return nullptr; +} +#endif // This program tests an AEAD against a series of test vectors from a file, // using the FileTest format. As an example, here's a valid test case: @@ -48,7 +56,7 @@ static bool TestAEAD(FileTest *t, void *arg) { return false; } - ScopedEVP_AEAD_CTX ctx; + bssl::ScopedEVP_AEAD_CTX ctx; if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), aead, key.data(), key.size(), tag.size(), evp_aead_seal)) { t->PrintLine("Failed to init AEAD."); @@ -198,7 +206,7 @@ static bool TestWithAliasedBuffers(const EVP_AEAD *aead) { const size_t max_overhead = EVP_AEAD_max_overhead(aead); std::vector<uint8_t> key(key_len, 'a'); - ScopedEVP_AEAD_CTX ctx; + bssl::ScopedEVP_AEAD_CTX ctx; if (!EVP_AEAD_CTX_init(ctx.get(), aead, key.data(), key_len, EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { return false; @@ -302,6 +310,8 @@ struct KnownAEAD { static const struct KnownAEAD kAEADs[] = { { "aes-128-gcm", EVP_aead_aes_128_gcm, false }, { "aes-256-gcm", EVP_aead_aes_256_gcm, false }, + { "aes-128-gcm-siv", EVP_aead_aes_128_gcm_siv, false }, + { "aes-256-gcm-siv", EVP_aead_aes_256_gcm_siv, false }, { "chacha20-poly1305", EVP_aead_chacha20_poly1305, false }, { "chacha20-poly1305-old", EVP_aead_chacha20_poly1305_old, false }, { "aes-128-cbc-sha1-tls", EVP_aead_aes_128_cbc_sha1_tls, true }, @@ -321,7 +331,7 @@ static const struct KnownAEAD kAEADs[] = { { "", NULL, false }, }; -static int Main(int argc, char **argv) { +int main(int argc, char **argv) { CRYPTO_library_init(); if (argc != 3) { @@ -342,6 +352,11 @@ static int Main(int argc, char **argv) { } const EVP_AEAD *const aead = known_aead->func(); + if (aead == NULL) { + // AEAD is not compiled in this configuration. + printf("PASS\n"); + return 0; + } if (!TestCleanupAfterInitFailure(aead)) { return 1; @@ -354,9 +369,3 @@ static int Main(int argc, char **argv) { return FileTestMain(TestAEAD, const_cast<EVP_AEAD*>(aead), argv[2]); } - -} // namespace bssl - -int main(int argc, char **argv) { - return bssl::Main(argc, argv); -} diff --git a/src/crypto/cipher/cipher_test.cc b/src/crypto/cipher/cipher_test.cc index cb42fc51..09802c2c 100644 --- a/src/crypto/cipher/cipher_test.cc +++ b/src/crypto/cipher/cipher_test.cc @@ -63,7 +63,6 @@ #include "../test/file_test.h" -namespace bssl { static const EVP_CIPHER *GetCipher(const std::string &name) { if (name == "DES-CBC") { @@ -127,7 +126,7 @@ static bool TestOperation(FileTest *t, bool is_aead = EVP_CIPHER_mode(cipher) == EVP_CIPH_GCM_MODE; - ScopedEVP_CIPHER_CTX ctx; + bssl::ScopedEVP_CIPHER_CTX ctx; if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr, nullptr, nullptr, encrypt ? 1 : 0)) { return false; @@ -284,7 +283,7 @@ static bool TestCipher(FileTest *t, void *arg) { return true; } -static int Main(int argc, char **argv) { +int main(int argc, char **argv) { CRYPTO_library_init(); if (argc != 2) { @@ -294,9 +293,3 @@ static int Main(int argc, char **argv) { return FileTestMain(TestCipher, nullptr, argv[1]); } - -} // namespace bssl - -int main(int argc, char **argv) { - return bssl::Main(argc, argv); -} diff --git a/src/crypto/cipher/e_aes.c b/src/crypto/cipher/e_aes.c index 9225d6a7..f99022ff 100644 --- a/src/crypto/cipher/e_aes.c +++ b/src/crypto/cipher/e_aes.c @@ -1446,6 +1446,305 @@ const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void) { return &aead_aes_256_ctr_hmac_sha256; } +#if !defined(OPENSSL_SMALL) + +#define EVP_AEAD_AES_GCM_SIV_TAG_LEN 16 + +struct aead_aes_gcm_siv_ctx { + union { + double align; + AES_KEY ks; + } ks; + block128_f kgk_block; + unsigned is_256:1; +}; + +static int aead_aes_gcm_siv_init(EVP_AEAD_CTX *ctx, const uint8_t *key, + size_t key_len, size_t tag_len) { + 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 = EVP_AEAD_AES_GCM_SIV_TAG_LEN; + } + + if (tag_len != EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TAG_TOO_LARGE); + return 0; + } + + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = + OPENSSL_malloc(sizeof(struct aead_aes_gcm_siv_ctx)); + if (gcm_siv_ctx == NULL) { + return 0; + } + memset(gcm_siv_ctx, 0, sizeof(struct aead_aes_gcm_siv_ctx)); + + if (aesni_capable()) { + aesni_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aesni_encrypt; + } else if (hwaes_capable()) { + aes_hw_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)aes_hw_encrypt; + } else if (vpaes_capable()) { + vpaes_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)vpaes_encrypt; + } else { + AES_set_encrypt_key(key, key_len * 8, &gcm_siv_ctx->ks.ks); + gcm_siv_ctx->kgk_block = (block128_f)AES_encrypt; + } + + gcm_siv_ctx->is_256 = (key_len == 32); + ctx->aead_state = gcm_siv_ctx; + + return 1; +} + +static void aead_aes_gcm_siv_cleanup(EVP_AEAD_CTX *ctx) { + struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + OPENSSL_cleanse(gcm_siv_ctx, sizeof(struct aead_aes_gcm_siv_ctx)); + OPENSSL_free(gcm_siv_ctx); +} + +/* gcm_siv_crypt encrypts (or decrypts—it's the same thing) |in_len| bytes from + * |in| to |out|, using the block function |enc_block| with |key| in counter + * mode, starting at |initial_counter|. This differs from the traditional + * counter mode code in that the counter is handled little-endian, only the + * first four bytes are used and the GCM-SIV tweak to the final byte is + * applied. The |in| and |out| pointers may be equal but otherwise must not + * alias. */ +static void gcm_siv_crypt(uint8_t *out, const uint8_t *in, size_t in_len, + const uint8_t initial_counter[AES_BLOCK_SIZE], + block128_f enc_block, const AES_KEY *key) { + union { + uint32_t w[4]; + uint8_t c[16]; + } counter; + + memcpy(counter.c, initial_counter, AES_BLOCK_SIZE); + counter.c[15] |= 0x80; + + for (size_t done = 0; done < in_len;) { + uint8_t keystream[AES_BLOCK_SIZE]; + enc_block(counter.c, keystream, key); + counter.w[0]++; + + size_t todo = AES_BLOCK_SIZE; + if (in_len - done < todo) { + todo = in_len - done; + } + + for (size_t i = 0; i < todo; i++) { + out[done + i] = keystream[i] ^ in[done + i]; + } + + done += todo; + } +} + +/* gcm_siv_polyval evaluates POLYVAL at |auth_key| on the given plaintext and + * AD. The result is written to |out_tag|. */ +static void gcm_siv_polyval(uint8_t out_tag[16], const uint8_t *in, + size_t in_len, const uint8_t *ad, size_t ad_len, + const uint8_t auth_key[16]) { + struct polyval_ctx polyval_ctx; + CRYPTO_POLYVAL_init(&polyval_ctx, auth_key); + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, ad, ad_len & ~15); + + uint8_t scratch[16]; + if (ad_len & 15) { + memset(scratch, 0, sizeof(scratch)); + memcpy(scratch, &ad[ad_len & ~15], ad_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, in, in_len & ~15); + if (in_len & 15) { + memset(scratch, 0, sizeof(scratch)); + memcpy(scratch, &in[in_len & ~15], in_len & 15); + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, scratch, sizeof(scratch)); + } + + union { + uint8_t c[16]; + struct { + uint64_t ad; + uint64_t in; + } bitlens; + } length_block; + + length_block.bitlens.ad = ad_len * 8; + length_block.bitlens.in = in_len * 8; + CRYPTO_POLYVAL_update_blocks(&polyval_ctx, length_block.c, + sizeof(length_block)); + + CRYPTO_POLYVAL_finish(&polyval_ctx, out_tag); + out_tag[15] &= 0x7f; +} + +/* gcm_siv_record_keys contains the keys used for a specific GCM-SIV record. */ +struct gcm_siv_record_keys { + uint8_t auth_key[16]; + union { + double align; + AES_KEY ks; + } enc_key; + block128_f enc_block; +}; + +/* gcm_siv_keys calculates the keys for a specific GCM-SIV record with the + * given nonce and writes them to |*out_keys|. */ +static void gcm_siv_keys( + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx, + struct gcm_siv_record_keys *out_keys, + const uint8_t nonce[EVP_AEAD_AES_GCM_SIV_TAG_LEN]) { + const AES_KEY *const key = &gcm_siv_ctx->ks.ks; + gcm_siv_ctx->kgk_block(nonce, out_keys->auth_key, key); + + if (gcm_siv_ctx->is_256) { + uint8_t record_enc_key[32]; + gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key + 16, key); + gcm_siv_ctx->kgk_block(record_enc_key + 16, record_enc_key, key); + aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block, + record_enc_key, sizeof(record_enc_key)); + } else { + uint8_t record_enc_key[16]; + gcm_siv_ctx->kgk_block(out_keys->auth_key, record_enc_key, key); + aes_ctr_set_key(&out_keys->enc_key.ks, NULL, &out_keys->enc_block, + record_enc_key, sizeof(record_enc_key)); + } +} + +static int aead_aes_gcm_siv_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_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const uint64_t in_len_64 = in_len; + const uint64_t ad_len_64 = ad_len; + + if (in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN < in_len || + in_len_64 > (UINT64_C(1) << 36) || + ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + if (max_out_len < in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + if (nonce_len != AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_UNSUPPORTED_NONCE_SIZE); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + uint8_t tag[16]; + gcm_siv_polyval(tag, in, in_len, ad, ad_len, keys.auth_key); + keys.enc_block(tag, tag, &keys.enc_key.ks); + + gcm_siv_crypt(out, in, in_len, tag, keys.enc_block, &keys.enc_key.ks); + + memcpy(&out[in_len], tag, EVP_AEAD_AES_GCM_SIV_TAG_LEN); + *out_len = in_len + EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + return 1; +} + +static int aead_aes_gcm_siv_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 uint64_t ad_len_64 = ad_len; + if (ad_len_64 >= (UINT64_C(1) << 61)) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_TOO_LARGE); + return 0; + } + + const uint64_t in_len_64 = in_len; + if (in_len < EVP_AEAD_AES_GCM_SIV_TAG_LEN || + in_len_64 > (UINT64_C(1) << 36) + AES_BLOCK_SIZE) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + const struct aead_aes_gcm_siv_ctx *gcm_siv_ctx = ctx->aead_state; + const size_t plaintext_len = in_len - EVP_AEAD_AES_GCM_SIV_TAG_LEN; + + if (max_out_len < plaintext_len) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BUFFER_TOO_SMALL); + return 0; + } + + struct gcm_siv_record_keys keys; + gcm_siv_keys(gcm_siv_ctx, &keys, nonce); + + gcm_siv_crypt(out, in, plaintext_len, &in[plaintext_len], keys.enc_block, + &keys.enc_key.ks); + + uint8_t expected_tag[EVP_AEAD_AES_GCM_SIV_TAG_LEN]; + gcm_siv_polyval(expected_tag, out, plaintext_len, ad, ad_len, keys.auth_key); + keys.enc_block(expected_tag, expected_tag, &keys.enc_key.ks); + + if (CRYPTO_memcmp(expected_tag, &in[plaintext_len], sizeof(expected_tag)) != + 0) { + OPENSSL_PUT_ERROR(CIPHER, CIPHER_R_BAD_DECRYPT); + return 0; + } + + *out_len = plaintext_len; + return 1; +} + +static const EVP_AEAD aead_aes_128_gcm_siv = { + 16, /* key length */ + AES_BLOCK_SIZE, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +static const EVP_AEAD aead_aes_256_gcm_siv = { + 32, /* key length */ + AES_BLOCK_SIZE, /* nonce length */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* overhead */ + EVP_AEAD_AES_GCM_SIV_TAG_LEN, /* max tag length */ + + aead_aes_gcm_siv_init, + NULL /* init_with_direction */, + aead_aes_gcm_siv_cleanup, + aead_aes_gcm_siv_seal, + aead_aes_gcm_siv_open, + NULL /* get_iv */, +}; + +const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void) { + return &aead_aes_128_gcm_siv; +} + +const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void) { + return &aead_aes_256_gcm_siv; +} + +#endif /* !OPENSSL_SMALL */ + int EVP_has_aes_hardware(void) { #if defined(OPENSSL_X86) || defined(OPENSSL_X86_64) return aesni_capable() && crypto_gcm_clmul_enabled(); diff --git a/src/crypto/cipher/test/aes_128_gcm_siv_tests.txt b/src/crypto/cipher/test/aes_128_gcm_siv_tests.txt new file mode 100644 index 00000000..a929b593 --- /dev/null +++ b/src/crypto/cipher/test/aes_128_gcm_siv_tests.txt @@ -0,0 +1,236 @@ +# This is the example from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-8 + +KEY: ee8e1ed9ff2540ae8f2ba9f50bc2f27c +NONCE: 752abad3e0afb5f434dc4310f71f3d21 +IN: "Hello world" +AD: "example" +CT: 810649724764545b3625ff +TAG: 010a10f4942710781d2948ac0192572f + +# Test vectors from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: cb52de357fad226ae428d0ed5a575496 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: 7e139f58002d68ee +TAG: 715835541f2136f03b6dc80ae0a8ac46 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: 4a87f0cd26e5d5086e90da02 +TAG: 4dff905e48d512e9c34ae8f3be66ec43 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 048ca58c46d2368ce00132389f40b511 +TAG: 971da9aa385283522c4f67a9aedb37e5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa +TAG: 1071338b8c2930d3ec4c17cecbefa4b4 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00 +TAG: 04b1b8a9c1630ff028b14d2e57bca429 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5 +TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4919e29e9890e452 +TAG: 1433a5c0284c911163888dbd128e6874 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: db55d6da719fe0473538294e +TAG: 5a8ab948ccd205a70c78e8fdf954693b + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: aea3c54272abc1b58ed34a536743f4da +TAG: da10d98bfe23784cfdfd0af97b6d5b78 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1 +TAG: 778c5b68356a1a6a6f3c14a8f96c35ca + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e +TAG: 26c0c0d146d38787ca0fcbc3f911577a + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e +TAG: a60986309b99431a35dd8c5ebeef8375 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 47995b96 +TAG: 16b668094202cadde992e0c16205793c + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 8fe25de75089e9f849150e57ab7f7810981cd319 +TAG: 89ca91ebc560709432fe9496746404cc + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: b26d43ae158316ac37f41579ccf1d461274e +TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: cb52de357fad226ae428d0ed5a575496 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: 7e139f58002d68ee +TAG: 715835541f2136f03b6dc80ae0a8ac46 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: 4a87f0cd26e5d5086e90da02 +TAG: 4dff905e48d512e9c34ae8f3be66ec43 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 048ca58c46d2368ce00132389f40b511 +TAG: 971da9aa385283522c4f67a9aedb37e5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: e1cf1cf545d2743ec005b26bd2c836ac1a4233d646c195ffa401f28063127baa +TAG: 1071338b8c2930d3ec4c17cecbefa4b4 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: 2e7e6881a02d57b877794b2fbfbfef5484f1cf74f4ad53a751b2582c0e698466bd9a49dcab53806d8e31d864c4632d00 +TAG: 04b1b8a9c1630ff028b14d2e57bca429 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: 0ac5be860726209d9218de3e9d533743e1efe1595bc58f93f00e9bb9a7558dc1e1b14a9c0d49eb5064c7efa79842f9c7cfdd77614709f0b545d3227498e774d5 +TAG: 860b73a1ed8a5b9acd925c3f3f49c5c5 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4919e29e9890e452 +TAG: 1433a5c0284c911163888dbd128e6874 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: db55d6da719fe0473538294e +TAG: 5a8ab948ccd205a70c78e8fdf954693b + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: aea3c54272abc1b58ed34a536743f4da +TAG: da10d98bfe23784cfdfd0af97b6d5b78 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: aa694c0cfe148100cb5c6e27a77a7ff7b4233d6af251d9faa3d84f7c0d1113f1 +TAG: 778c5b68356a1a6a6f3c14a8f96c35ca + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 9ac909928bcde79c2afa885df9c035c85a9eab136f6f6ea11034456bd306ea3c5dd542f706fffe538b5f139fa9dc622e +TAG: 26c0c0d146d38787ca0fcbc3f911577a + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: c56be9d61ecf6a31a6289cddc9b91aaf84cdb53a3913b825d6eb5e157906dfb0a308c6b0b095d6fd1a5b761ca7fa0e39ca92f38ae206eec844c0c4ab0c1c165e +TAG: a60986309b99431a35dd8c5ebeef8375 + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 47995b96 +TAG: 16b668094202cadde992e0c16205793c + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 8fe25de75089e9f849150e57ab7f7810981cd319 +TAG: 89ca91ebc560709432fe9496746404cc + +KEY: 01000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: b26d43ae158316ac37f41579ccf1d461274e +TAG: 13b7c01d08dd6969d51d1bf0fbbdc4d2 diff --git a/src/crypto/cipher/test/aes_256_gcm_siv_tests.txt b/src/crypto/cipher/test/aes_256_gcm_siv_tests.txt new file mode 100644 index 00000000..cd38e238 --- /dev/null +++ b/src/crypto/cipher/test/aes_256_gcm_siv_tests.txt @@ -0,0 +1,226 @@ +# Test vectors from +# https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-B + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: eb7ccf36eeff369241379c87cc08e4f0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: ab3f382a6f0fb4c3 +TAG: a0a69e07b73281f5cdfd034f646cfa08 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: be8d81f033ca23b953da2197 +TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 46e05b7116dbe27aaeffe99892194072 +TAG: be19d78991c62130cf97f628c37c3eaa + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a +TAG: 16c5944034050657af7c0fec7efbc40f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53 +TAG: abedb4841c20f3b05e61e0fd1fcaf3d0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f +TAG: 3ced67f5e03bb476a738c1343926dc19 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4dca2c16c3b0413c +TAG: ac9b952c76a6f8b5df315f88126daa1c + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: ee0ca9068b5b85dfe115a660 +TAG: 756d6155927271077d790a05390ecb71 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: 590edb785c0cb89d19f031fa7e7d4f91 +TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c +TAG: a9b406643e190e602fb104fbb842a1ac + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de +TAG: 3ddfe9ad2c350980942638d3f954ac6d + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9 +TAG: abcb59ee31d25ee8889b70d7c36f9a41 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 9611baa0 +TAG: 53daf2bc5916f7a6750f2432068dabee + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87 +TAG: f65187d8c28adba364d659b627b16431 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: c6d3d28704bf20067d62e1a3872d40dda44b +TAG: 6ac0135a4379dbc67967ff55fd4d1f2f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: +AD: +CT: +TAG: eb7ccf36eeff369241379c87cc08e4f0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000 +AD: +CT: ab3f382a6f0fb4c3 +TAG: a0a69e07b73281f5cdfd034f646cfa08 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000 +AD: +CT: be8d81f033ca23b953da2197 +TAG: cdf3ba70da9c7cbd45f5140ba0cca9f1 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000 +AD: +CT: 46e05b7116dbe27aaeffe99892194072 +TAG: be19d78991c62130cf97f628c37c3eaa + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0100000000000000000000000000000002000000000000000000000000000000 +AD: +CT: 23ddbe9ef342b03003f56d6b4a2e8aff035c7d7cfd705e1ab4502904254bb67a +TAG: 16c5944034050657af7c0fec7efbc40f + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 010000000000000000000000000000000200000000000000000000000000000003000000000000000000000000000000 +AD: +CT: b104c8945f280e75b52c05c45a63d1872c7f0552b1501968d9913d71207d0433f978f1a3eecdf782016b77e8c9d3ff53 +TAG: abedb4841c20f3b05e61e0fd1fcaf3d0 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 01000000000000000000000000000000020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: +CT: e3f2bd14f4c80c9cea4c90c81f0e4d7eedb87eb19a7c0cf5a5a95cd3e441a71083b1191d115e9a9ff008b93feeb5a86d012a3e0adb89de2d1e3225479022292f +TAG: 3ced67f5e03bb476a738c1343926dc19 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000 +AD: 01 +CT: 4dca2c16c3b0413c +TAG: ac9b952c76a6f8b5df315f88126daa1c + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000 +AD: 01 +CT: ee0ca9068b5b85dfe115a660 +TAG: 756d6155927271077d790a05390ecb71 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000 +AD: 01 +CT: 590edb785c0cb89d19f031fa7e7d4f91 +TAG: ac2c8f711c86dbecc8c7b663c5fbc1ea + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0200000000000000000000000000000003000000000000000000000000000000 +AD: 01 +CT: dcf2024f5f98d463b82a8673c47dd82159748cac8bcc7c76b8cfa26029cb333c +TAG: a9b406643e190e602fb104fbb842a1ac + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 020000000000000000000000000000000300000000000000000000000000000004000000000000000000000000000000 +AD: 01 +CT: 79216506b1ddadfe16366e4ec886d10dc9400b995259f74c0091f9b5a6add5680a612130f6c31ab833aa76d9b2be86de +TAG: 3ddfe9ad2c350980942638d3f954ac6d + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000000000000000000000000000030000000000000000000000000000000400000000000000000000000000000005000000000000000000000000000000 +AD: 01 +CT: 9535eb67240c49f30a0de5a90670813fa615e71fcb4c522ca79d9a33459a22f8c6a56d650bf0b15eecdd706e7689cf6510a281724613fea76b5366b40574b1b9 +TAG: abcb59ee31d25ee8889b70d7c36f9a41 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 02000000 +AD: 010000000000000000000000 +CT: 9611baa0 +TAG: 53daf2bc5916f7a6750f2432068dabee + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 0300000000000000000000000000000004000000 +AD: 010000000000000000000000000000000200 +CT: 78e3a1b54daa6547f775f30c38a45e887aea5c87 +TAG: f65187d8c28adba364d659b627b16431 + +KEY: 0100000000000000000000000000000000000000000000000000000000000000 +NONCE: 03000000000000000000000000000000 +IN: 030000000000000000000000000000000400 +AD: 0100000000000000000000000000000002000000 +CT: c6d3d28704bf20067d62e1a3872d40dda44b +TAG: 6ac0135a4379dbc67967ff55fd4d1f2f diff --git a/src/crypto/cipher/tls_cbc.c b/src/crypto/cipher/tls_cbc.c index dd6ab8ce..eb56604d 100644 --- a/src/crypto/cipher/tls_cbc.c +++ b/src/crypto/cipher/tls_cbc.c @@ -133,107 +133,32 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, /* mac_end is the index of |in| just after the end of the MAC. */ unsigned mac_end = in_len; unsigned mac_start = mac_end - md_size; - /* scan_start contains the number of bytes that we can ignore because - * the MAC's position can only vary by 255 bytes. */ - unsigned scan_start = 0; - unsigned i, j; - unsigned rotate_offset; assert(orig_len >= in_len); assert(in_len >= md_size); assert(md_size <= EVP_MAX_MD_SIZE); + /* scan_start contains the number of bytes that we can ignore because + * the MAC's position can only vary by 255 bytes. */ + unsigned scan_start = 0; /* This information is public so it's safe to branch based on it. */ if (orig_len > md_size + 255 + 1) { scan_start = orig_len - (md_size + 255 + 1); } - /* Ideally the next statement would be: - * - * rotate_offset = (mac_start - scan_start) % md_size; - * - * However, division is not a constant-time operation (at least on Intel - * chips). Thus we enumerate the possible values of md_size and handle each - * separately. The value of |md_size| is public information (it's determined - * by the cipher suite in the ServerHello) so our timing can vary based on - * its value. */ - - rotate_offset = mac_start - scan_start; - /* rotate_offset can be, at most, 255 (bytes of padding) + 1 (padding length) - * + md_size = 256 + 48 (since SHA-384 is the largest hash) = 304. */ - assert(rotate_offset <= 304); - - /* Below is an SMT-LIB2 verification that the Barrett reductions below are - * correct within this range: - * - * (define-fun barrett ( - * (x (_ BitVec 32)) - * (mul (_ BitVec 32)) - * (shift (_ BitVec 32)) - * (divisor (_ BitVec 32)) ) (_ BitVec 32) - * (let ((q (bvsub x (bvmul divisor (bvlshr (bvmul x mul) shift))) )) - * (ite (bvuge q divisor) - * (bvsub q divisor) - * q))) - * - * (declare-fun x () (_ BitVec 32)) - * - * (assert (or - * (let ( - * (divisor (_ bv20 32)) - * (mul (_ bv25 32)) - * (shift (_ bv9 32)) - * (limit (_ bv853 32))) - * - * (and (bvule x limit) (not (= (bvurem x divisor) - * (barrett x mul shift divisor))))) - * - * (let ( - * (divisor (_ bv48 32)) - * (mul (_ bv10 32)) - * (shift (_ bv9 32)) - * (limit (_ bv768 32))) - * - * (and (bvule x limit) (not (= (bvurem x divisor) - * (barrett x mul shift divisor))))) - * )) - * - * (check-sat) - * (get-model) - */ - - if (md_size == 16) { - rotate_offset &= 15; - } else if (md_size == 20) { - /* 1/20 is approximated as 25/512 and then Barrett reduction is used. - * Analytically, this is correct for 0 <= rotate_offset <= 853. */ - unsigned q = (rotate_offset * 25) >> 9; - rotate_offset -= q * 20; - rotate_offset -= - constant_time_select(constant_time_ge(rotate_offset, 20), 20, 0); - } else if (md_size == 32) { - rotate_offset &= 31; - } else if (md_size == 48) { - /* 1/48 is approximated as 10/512 and then Barrett reduction is used. - * Analytically, this is correct for 0 <= rotate_offset <= 768. */ - unsigned q = (rotate_offset * 10) >> 9; - rotate_offset -= q * 48; - rotate_offset -= - constant_time_select(constant_time_ge(rotate_offset, 48), 48, 0); - } else { - /* This should be impossible therefore this path doesn't run in constant - * time. */ - assert(0); - rotate_offset = rotate_offset % md_size; - } - + unsigned rotate_offset = 0; + uint8_t mac_started = 0; memset(rotated_mac, 0, md_size); - for (i = scan_start, j = 0; i < orig_len; i++) { - uint8_t mac_started = constant_time_ge_8(i, mac_start); + for (unsigned i = scan_start, j = 0; i < orig_len; i++, j++) { + if (j >= md_size) { + j -= md_size; + } + unsigned is_mac_start = constant_time_eq(i, mac_start); + mac_started |= is_mac_start; uint8_t mac_ended = constant_time_ge_8(i, mac_end); - uint8_t b = in[i]; - rotated_mac[j++] |= b & mac_started & ~mac_ended; - j &= constant_time_lt(j, md_size); + rotated_mac[j] |= in[i] & mac_started & ~mac_ended; + /* Save the offset that |mac_start| is mapped to. */ + rotate_offset |= j & is_mac_start; } /* Now rotate the MAC. We rotate in log(md_size) steps, one for each bit @@ -243,7 +168,7 @@ void EVP_tls_cbc_copy_mac(uint8_t *out, unsigned md_size, /* Rotate by |offset| iff the corresponding bit is set in * |rotate_offset|, placing the result in |rotated_mac_tmp|. */ const uint8_t skip_rotate = (rotate_offset & 1) - 1; - for (i = 0, j = offset; i < md_size; i++, j++) { + for (unsigned i = 0, j = offset; i < md_size; i++, j++) { if (j >= md_size) { j -= md_size; } diff --git a/src/crypto/dh/dh_test.cc b/src/crypto/dh/dh_test.cc index 9a3d7803..99bb945c 100644 --- a/src/crypto/dh/dh_test.cc +++ b/src/crypto/dh/dh_test.cc @@ -68,7 +68,6 @@ #include <openssl/err.h> #include <openssl/mem.h> -namespace bssl { static bool RunBasicTests(); static bool RunRFC5114Tests(); @@ -76,7 +75,7 @@ static bool TestBadY(); static bool TestASN1(); static bool TestRFC3526(); -static int Main() { +int main() { CRYPTO_library_init(); if (!RunBasicTests() || @@ -568,7 +567,7 @@ static bool TestASN1() { return false; } - ScopedCBB cbb; + bssl::ScopedCBB cbb; uint8_t *der; size_t der_len; if (!CBB_init(cbb.get(), 0) || @@ -661,9 +660,3 @@ static bool TestRFC3526() { return true; } - -} // namespace bssl - -int main() { - return bssl::Main(); -} diff --git a/src/crypto/digest/digest_test.cc b/src/crypto/digest/digest_test.cc index ecf0308f..0d3f16e5 100644 --- a/src/crypto/digest/digest_test.cc +++ b/src/crypto/digest/digest_test.cc @@ -28,8 +28,6 @@ #include "../internal.h" -namespace bssl { - struct MD { // name is the name of the digest. const char* name; @@ -161,7 +159,7 @@ static bool CompareDigest(const TestVector *test, } static int TestDigest(const TestVector *test) { - ScopedEVP_MD_CTX ctx; + bssl::ScopedEVP_MD_CTX ctx; // Test the input provided. if (!EVP_DigestInit_ex(ctx.get(), test->md.func(), NULL)) { @@ -246,7 +244,7 @@ static int TestGetters() { return true; } -static int Main() { +int main() { CRYPTO_library_init(); for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kTestVectors); i++) { @@ -263,9 +261,3 @@ static int Main() { printf("PASS\n"); return 0; } - -} // namespace bssl - -int main() { - return bssl::Main(); -} diff --git a/src/crypto/ec/oct.c b/src/crypto/ec/oct.c index bf1957ca..4e8272da 100644 --- a/src/crypto/ec/oct.c +++ b/src/crypto/ec/oct.c @@ -284,7 +284,7 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, int y_bit, BN_CTX *ctx) { if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); return 0; } @@ -381,19 +381,7 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, if (y_bit != BN_is_odd(y)) { if (BN_is_zero(y)) { - int kron; - - kron = BN_kronecker(x, &group->field, ctx); - if (kron == -2) { - goto err; - } - - if (kron == 1) { - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); - } else { - /* BN_mod_sqrt() should have cought this error (not a square) */ - OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); - } + OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT); goto err; } if (!BN_usub(y, &group->field, y)) { diff --git a/src/crypto/ec/wnaf.c b/src/crypto/ec/wnaf.c index ba2257c4..15943548 100644 --- a/src/crypto/ec/wnaf.c +++ b/src/crypto/ec/wnaf.c @@ -90,10 +90,10 @@ * with the exception that the most significant digit may be only * w-1 zeros away from that next non-zero digit. */ -static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { +static int8_t *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { int window_val; int ok = 0; - signed char *r = NULL; + int8_t *r = NULL; int sign = 1; int bit, next_bit, mask; size_t len = 0, j; @@ -109,9 +109,8 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { return r; } - if (w <= 0 || w > 7) /* 'signed char' can represent integers with absolute - values less than 2^7 */ - { + /* 'int8_t' can represent integers with absolute values less than 2^7. */ + if (w <= 0 || w > 7) { OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); goto err; } @@ -129,20 +128,18 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { } len = BN_num_bits(scalar); - r = OPENSSL_malloc( - len + - 1); /* modified wNAF may be one digit longer than binary representation - * (*ret_len will be set to the actual length, i.e. at most - * BN_num_bits(scalar) + 1) */ + /* The modified wNAF may be one digit longer than binary representation + * (*ret_len will be set to the actual length, i.e. at most + * BN_num_bits(scalar) + 1). */ + r = OPENSSL_malloc(len + 1); if (r == NULL) { OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE); goto err; } window_val = scalar->d[0] & mask; j = 0; - while ((window_val != 0) || - (j + w + 1 < len)) /* if j+w+1 >= len, window_val will not increase */ - { + /* If j+w+1 >= len, window_val will not increase. */ + while (window_val != 0 || j + w + 1 < len) { int digit = 0; /* 0 <= window_val <= 2^(w+1) */ @@ -174,9 +171,8 @@ static signed char *compute_wNAF(const BIGNUM *scalar, int w, size_t *ret_len) { window_val -= digit; - /* now window_val is 0 or 2^(w+1) in standard wNAF generation; - * for modified window NAFs, it may also be 2^w - */ + /* Now window_val is 0 or 2^(w+1) in standard wNAF generation; + * for modified window NAFs, it may also be 2^w. */ if (window_val != 0 && window_val != next_bit && window_val != bit) { OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR); goto err; @@ -217,12 +213,29 @@ err: * sometimes smaller windows will give better performance * (thus the boundaries should be increased) */ -#define EC_window_bits_for_scalar_size(b) \ - ((size_t)((b) >= 2000 ? 6 : (b) >= 800 ? 5 : (b) >= 300 \ - ? 4 \ - : (b) >= 70 ? 3 : (b) >= 20 \ - ? 2 \ - : 1)) +static size_t window_bits_for_scalar_size(size_t b) { + if (b >= 2000) { + return 6; + } + + if (b >= 800) { + return 5; + } + + if (b >= 300) { + return 4; + } + + if (b >= 70) { + return 3; + } + + if (b >= 20) { + return 2; + } + + return 1; +} int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, const EC_POINT *p, const BIGNUM *p_scalar, BN_CTX *ctx) { @@ -235,7 +248,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, int r_is_inverted = 0; int r_is_at_infinity = 1; size_t *wsize = NULL; /* individual window sizes */ - signed char **wNAF = NULL; /* individual wNAFs */ + int8_t **wNAF = NULL; /* individual wNAFs */ size_t *wNAF_len = NULL; size_t max_len = 0; size_t num_val; @@ -294,7 +307,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, size_t bits; bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(g_scalar); - wsize[i] = EC_window_bits_for_scalar_size(bits); + wsize[i] = window_bits_for_scalar_size(bits); num_val += (size_t)1 << (wsize[i] - 1); wNAF[i + 1] = NULL; /* make sure we always have a pivot */ wNAF[i] = @@ -364,7 +377,7 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, } } -#if 1 /* optional; EC_window_bits_for_scalar_size assumes we do this step */ +#if 1 /* optional; window_bits_for_scalar_size assumes we do this step */ if (!EC_POINTs_make_affine(group, num_val, val, ctx)) { goto err; } @@ -429,7 +442,7 @@ err: OPENSSL_free(wsize); OPENSSL_free(wNAF_len); if (wNAF != NULL) { - signed char **w; + int8_t **w; for (w = wNAF; *w != NULL; w++) { OPENSSL_free(*w); diff --git a/src/crypto/err/ssl.errordata b/src/crypto/err/ssl.errordata index b50f9ab8..e9b20664 100644 --- a/src/crypto/err/ssl.errordata +++ b/src/crypto/err/ssl.errordata @@ -109,6 +109,7 @@ SSL,192,PEER_DID_NOT_RETURN_A_CERTIFICATE SSL,193,PEER_ERROR_UNSUPPORTED_CERTIFICATE_TYPE SSL,267,PRE_SHARED_KEY_MUST_BE_LAST SSL,194,PROTOCOL_IS_SHUTDOWN +SSL,271,PSK_IDENTITY_BINDER_COUNT_MISMATCH SSL,195,PSK_IDENTITY_NOT_FOUND SSL,196,PSK_NO_CLIENT_CB SSL,197,PSK_NO_SERVER_CB @@ -170,6 +171,7 @@ SSL,218,TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG SSL,219,TOO_MANY_EMPTY_FRAGMENTS SSL,260,TOO_MANY_KEY_UPDATES SSL,220,TOO_MANY_WARNING_ALERTS +SSL,270,TOO_MUCH_SKIPPED_EARLY_DATA SSL,221,UNABLE_TO_FIND_ECDH_PARAMETERS SSL,222,UNEXPECTED_EXTENSION SSL,223,UNEXPECTED_MESSAGE diff --git a/src/crypto/evp/evp_extra_test.cc b/src/crypto/evp/evp_extra_test.cc index 755fa838..4d417605 100644 --- a/src/crypto/evp/evp_extra_test.cc +++ b/src/crypto/evp/evp_extra_test.cc @@ -27,7 +27,6 @@ #include <openssl/pkcs8.h> #include <openssl/rsa.h> -namespace bssl { // kExampleRSAKeyDER is an RSA private key in ASN.1, DER format. Of course, you // should never use this key anywhere but in an example. @@ -371,7 +370,7 @@ static bssl::UniquePtr<EVP_PKEY> LoadExampleRSAKey() { static bool TestEVP_DigestSignInit(void) { bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey(); - ScopedEVP_MD_CTX md_ctx; + bssl::ScopedEVP_MD_CTX md_ctx; if (!pkey || !EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) || !EVP_DigestSignUpdate(md_ctx.get(), kMsg, sizeof(kMsg))) { @@ -409,7 +408,7 @@ static bool TestEVP_DigestSignInit(void) { static bool TestEVP_DigestVerifyInit(void) { bssl::UniquePtr<EVP_PKEY> pkey = LoadExampleRSAKey(); - ScopedEVP_MD_CTX md_ctx; + bssl::ScopedEVP_MD_CTX md_ctx; if (!pkey || !EVP_DigestVerifyInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) || @@ -591,7 +590,7 @@ static bool TestEVPMarshalEmptyPublicKey(void) { if (!empty) { return false; } - ScopedCBB cbb; + bssl::ScopedCBB cbb; if (EVP_marshal_public_key(cbb.get(), empty.get())) { fprintf(stderr, "Marshalled empty public key.\n"); return false; @@ -670,7 +669,7 @@ static bool Testd2i_PrivateKey(void) { return true; } -static int Main(void) { +int main() { CRYPTO_library_init(); if (!TestEVP_DigestSignInit()) { @@ -718,9 +717,3 @@ static int Main(void) { printf("PASS\n"); return 0; } - -} // namespace bssl - -int main() { - return bssl::Main(); -} diff --git a/src/crypto/evp/evp_test.cc b/src/crypto/evp/evp_test.cc index 68b869aa..bfaa38aa 100644 --- a/src/crypto/evp/evp_test.cc +++ b/src/crypto/evp/evp_test.cc @@ -75,7 +75,6 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) #include "../test/file_test.h" -namespace bssl { // evp_test dispatches between multiple test types. PrivateKey tests take a key // name parameter and single block, decode it as a PEM private key, and save it @@ -141,7 +140,7 @@ static bool ImportKey(FileTest *t, KeyMap *key_map, } // The key must re-encode correctly. - ScopedCBB cbb; + bssl::ScopedCBB cbb; uint8_t *der; size_t der_len; if (!CBB_init(cbb.get(), 0) || @@ -253,7 +252,7 @@ static bool TestEVP(FileTest *t, void *arg) { return true; } -static int Main(int argc, char *argv[]) { +int main(int argc, char *argv[]) { CRYPTO_library_init(); if (argc != 2) { fprintf(stderr, "%s <test file.txt>\n", argv[0]); @@ -263,9 +262,3 @@ static int Main(int argc, char *argv[]) { KeyMap map; return FileTestMain(TestEVP, &map, argv[1]); } - -} // namespace bssl - -int main(int argc, char *argv[]) { - return bssl::Main(argc, argv); -} diff --git a/src/crypto/hmac/hmac_test.cc b/src/crypto/hmac/hmac_test.cc index 60a95814..7b216e28 100644 --- a/src/crypto/hmac/hmac_test.cc +++ b/src/crypto/hmac/hmac_test.cc @@ -67,7 +67,6 @@ #include "../test/file_test.h" -namespace bssl { static const EVP_MD *GetDigest(const std::string &name) { if (name == "MD5") { @@ -117,7 +116,7 @@ static bool TestHMAC(FileTest *t, void *arg) { } // Test using HMAC_CTX. - ScopedHMAC_CTX ctx; + bssl::ScopedHMAC_CTX ctx; if (!HMAC_Init_ex(ctx.get(), key.data(), key.size(), digest, nullptr) || !HMAC_Update(ctx.get(), input.data(), input.size()) || !HMAC_Final(ctx.get(), mac.get(), &mac_len) || @@ -158,7 +157,7 @@ static bool TestHMAC(FileTest *t, void *arg) { return true; } -static int Main(int argc, char *argv[]) { +int main(int argc, char *argv[]) { CRYPTO_library_init(); if (argc != 2) { @@ -168,9 +167,3 @@ static int Main(int argc, char *argv[]) { return FileTestMain(TestHMAC, nullptr, argv[1]); } - -} // namespace bssl - -int main(int argc, char **argv) { - return bssl::Main(argc, argv); -} diff --git a/src/crypto/modes/CMakeLists.txt b/src/crypto/modes/CMakeLists.txt index 17faa155..dc9e5042 100644 --- a/src/crypto/modes/CMakeLists.txt +++ b/src/crypto/modes/CMakeLists.txt @@ -48,10 +48,11 @@ add_library( OBJECT cbc.c - ctr.c - ofb.c cfb.c + ctr.c gcm.c + ofb.c + polyval.c ${MODES_ARCH_SOURCES} ) diff --git a/src/crypto/modes/cbc.c b/src/crypto/modes/cbc.c index e41f2b49..6e9fe24c 100644 --- a/src/crypto/modes/cbc.c +++ b/src/crypto/modes/cbc.c @@ -52,10 +52,6 @@ #include "internal.h" -#ifndef STRICT_ALIGNMENT -# define STRICT_ALIGNMENT 0 -#endif - void CRYPTO_cbc128_encrypt(const uint8_t *in, uint8_t *out, size_t len, const void *key, uint8_t ivec[16], block128_f block) { diff --git a/src/crypto/modes/gcm.c b/src/crypto/modes/gcm.c index eb63aa03..3b793e82 100644 --- a/src/crypto/modes/gcm.c +++ b/src/crypto/modes/gcm.c @@ -65,14 +65,6 @@ #define GHASH_ASM #endif -#if defined(BSWAP4) && STRICT_ALIGNMENT == 1 -/* redefine, because alignment is ensured */ -#undef GETU32 -#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) -#undef PUTU32 -#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) -#endif - #define PACK(s) ((size_t)(s) << (sizeof(size_t) * 8 - 16)) #define REDUCE1BIT(V) \ do { \ @@ -121,27 +113,10 @@ static void gcm_init_4bit(u128 Htable[16], uint64_t H[2]) { Htable[15].hi = V.hi ^ Htable[7].hi, Htable[15].lo = V.lo ^ Htable[7].lo; #if defined(GHASH_ASM) && defined(OPENSSL_ARM) - /* ARM assembler expects specific dword order in Htable. */ - { - int j; - const union { - long one; - char little; - } is_endian = {1}; - - if (is_endian.little) { - for (j = 0; j < 16; ++j) { - V = Htable[j]; - Htable[j].hi = V.lo; - Htable[j].lo = V.hi; - } - } else { - for (j = 0; j < 16; ++j) { - V = Htable[j]; - Htable[j].hi = V.lo << 32 | V.lo >> 32; - Htable[j].lo = V.hi << 32 | V.hi >> 32; - } - } + for (int j = 0; j < 16; ++j) { + V = Htable[j]; + Htable[j].hi = V.lo; + Htable[j].lo = V.hi; } #endif } @@ -157,10 +132,6 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { u128 Z; int cnt = 15; size_t rem, nlo, nhi; - const union { - long one; - char little; - } is_endian = {1}; nlo = ((const uint8_t *)Xi)[15]; nhi = nlo >> 4; @@ -203,26 +174,8 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { Z.lo ^= Htable[nlo].lo; } - if (is_endian.little) { -#ifdef BSWAP8 - Xi[0] = BSWAP8(Z.hi); - Xi[1] = BSWAP8(Z.lo); -#else - uint8_t *p = (uint8_t *)Xi; - uint32_t v; - v = (uint32_t)(Z.hi >> 32); - PUTU32(p, v); - v = (uint32_t)(Z.hi); - PUTU32(p + 4, v); - v = (uint32_t)(Z.lo >> 32); - PUTU32(p + 8, v); - v = (uint32_t)(Z.lo); - PUTU32(p + 12, v); -#endif - } else { - Xi[0] = Z.hi; - Xi[1] = Z.lo; - } + Xi[0] = CRYPTO_bswap8(Z.hi); + Xi[1] = CRYPTO_bswap8(Z.lo); } /* Streamed gcm_mult_4bit, see CRYPTO_gcm128_[en|de]crypt for @@ -230,15 +183,11 @@ static void gcm_gmult_4bit(uint64_t Xi[2], const u128 Htable[16]) { * performance improvement, at least not on x86[_64]. It's here * mostly as reference and a placeholder for possible future * non-trivial optimization[s]... */ -static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len) { +static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], + const uint8_t *inp, size_t len) { u128 Z; int cnt; size_t rem, nlo, nhi; - const union { - long one; - char little; - } is_endian = {1}; do { cnt = 15; @@ -285,26 +234,8 @@ static void gcm_ghash_4bit(uint64_t Xi[2], const u128 Htable[16], const uint8_t Z.lo ^= Htable[nlo].lo; } - if (is_endian.little) { -#ifdef BSWAP8 - Xi[0] = BSWAP8(Z.hi); - Xi[1] = BSWAP8(Z.lo); -#else - uint8_t *p = (uint8_t *)Xi; - uint32_t v; - v = (uint32_t)(Z.hi >> 32); - PUTU32(p, v); - v = (uint32_t)(Z.hi); - PUTU32(p + 4, v); - v = (uint32_t)(Z.lo >> 32); - PUTU32(p + 8, v); - v = (uint32_t)(Z.lo); - PUTU32(p + 12, v); -#endif - } else { - Xi[0] = Z.hi; - Xi[1] = Z.lo; - } + Xi[0] = CRYPTO_bswap8(Z.hi); + Xi[1] = CRYPTO_bswap8(Z.lo); } while (inp += 16, len -= 16); } #else /* GHASH_ASM */ @@ -425,96 +356,88 @@ void gcm_ghash_p8(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, #endif #endif -void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key, - block128_f block) { - const union { - long one; - char little; - } is_endian = {1}; - - memset(ctx, 0, sizeof(*ctx)); - ctx->block = block; +void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, + u128 out_table[16], const uint8_t *gcm_key) { + union { + uint64_t u[2]; + uint8_t c[16]; + } H; - (*block)(ctx->H.c, ctx->H.c, key); + memcpy(H.c, gcm_key, 16); - if (is_endian.little) { -/* H is stored in host byte order */ -#ifdef BSWAP8 - ctx->H.u[0] = BSWAP8(ctx->H.u[0]); - ctx->H.u[1] = BSWAP8(ctx->H.u[1]); -#else - uint8_t *p = ctx->H.c; - uint64_t hi, lo; - hi = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); - lo = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); - ctx->H.u[0] = hi; - ctx->H.u[1] = lo; -#endif - } + /* H is stored in host byte order */ + H.u[0] = CRYPTO_bswap8(H.u[0]); + H.u[1] = CRYPTO_bswap8(H.u[1]); #if defined(GHASH_ASM_X86_OR_64) if (crypto_gcm_clmul_enabled()) { if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */ - gcm_init_avx(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_avx; - ctx->ghash = gcm_ghash_avx; - } else { - gcm_init_clmul(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_clmul; - ctx->ghash = gcm_ghash_clmul; + gcm_init_avx(out_table, H.u); + *out_mult = gcm_gmult_avx; + *out_hash = gcm_ghash_avx; + return; } + + gcm_init_clmul(out_table, H.u); + *out_mult = gcm_gmult_clmul; + *out_hash = gcm_ghash_clmul; return; } - gcm_init_4bit(ctx->Htable, ctx->H.u); #if defined(GHASH_ASM_X86) /* x86 only */ if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */ - ctx->gmult = gcm_gmult_4bit_mmx; - ctx->ghash = gcm_ghash_4bit_mmx; - } else { - ctx->gmult = gcm_gmult_4bit_x86; - ctx->ghash = gcm_ghash_4bit_x86; + gcm_init_4bit(out_table, H.u); + *out_mult = gcm_gmult_4bit_mmx; + *out_hash = gcm_ghash_4bit_mmx; + return; } -#else - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; #endif #elif defined(GHASH_ASM_ARM) if (pmull_capable()) { - gcm_init_v8(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_v8; - ctx->ghash = gcm_ghash_v8; - } else if (neon_capable()) { - gcm_init_neon(ctx->Htable,ctx->H.u); - ctx->gmult = gcm_gmult_neon; - ctx->ghash = gcm_ghash_neon; - } else { - gcm_init_4bit(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; + gcm_init_v8(out_table, H.u); + *out_mult = gcm_gmult_v8; + *out_hash = gcm_ghash_v8; + return; + } + + if (neon_capable()) { + gcm_init_neon(out_table, H.u); + *out_mult = gcm_gmult_neon; + *out_hash = gcm_ghash_neon; + return; } #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; + gcm_init_p8(out_table, H.u); + *out_mult = gcm_gmult_p8; + *out_hash = gcm_ghash_p8; + return; } +#endif + + gcm_init_4bit(out_table, H.u); +#if defined(GHASH_ASM_X86) + *out_mult = gcm_gmult_4bit_x86; + *out_hash = gcm_ghash_4bit_x86; #else - gcm_init_4bit(ctx->Htable, ctx->H.u); - ctx->gmult = gcm_gmult_4bit; - ctx->ghash = gcm_ghash_4bit; + *out_mult = gcm_gmult_4bit; + *out_hash = gcm_ghash_4bit; #endif } +void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *aes_key, + block128_f block) { + memset(ctx, 0, sizeof(*ctx)); + ctx->block = block; + + uint8_t gcm_key[16]; + memset(gcm_key, 0, sizeof(gcm_key)); + (*block)(gcm_key, gcm_key, aes_key); + + CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, gcm_key); +} + void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, const uint8_t *iv, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int ctr; #ifdef GCM_FUNCREF_4BIT void (*gcm_gmult_p)(uint64_t Xi[2], const u128 Htable[16]) = ctx->gmult; @@ -551,39 +474,15 @@ void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key, GCM_MUL(ctx, Yi); } len0 <<= 3; - if (is_endian.little) { -#ifdef BSWAP8 - ctx->Yi.u[1] ^= BSWAP8(len0); -#else - ctx->Yi.c[8] ^= (uint8_t)(len0 >> 56); - ctx->Yi.c[9] ^= (uint8_t)(len0 >> 48); - ctx->Yi.c[10] ^= (uint8_t)(len0 >> 40); - ctx->Yi.c[11] ^= (uint8_t)(len0 >> 32); - ctx->Yi.c[12] ^= (uint8_t)(len0 >> 24); - ctx->Yi.c[13] ^= (uint8_t)(len0 >> 16); - ctx->Yi.c[14] ^= (uint8_t)(len0 >> 8); - ctx->Yi.c[15] ^= (uint8_t)(len0); -#endif - } else { - ctx->Yi.u[1] ^= len0; - } + ctx->Yi.u[1] ^= CRYPTO_bswap8(len0); GCM_MUL(ctx, Yi); - - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); } (*ctx->block)(ctx->Yi.c, ctx->EK0.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { @@ -656,10 +555,6 @@ int CRYPTO_gcm128_aad(GCM128_CONTEXT *ctx, const uint8_t *aad, size_t len) { int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, const unsigned char *in, unsigned char *out, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; block128_f block = ctx->block; @@ -684,11 +579,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); n = ctx->mres; if (n) { @@ -709,11 +600,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, if (n == 0) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } ctx->Xi.c[n] ^= out[i] = in[i] ^ ctx->EKi.c[n]; n = (n + 1) % 16; @@ -735,11 +622,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } @@ -758,11 +641,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } @@ -779,11 +658,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { ctx->Xi.t[i] ^= out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } @@ -796,11 +671,7 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, if (len) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; ++n; @@ -814,10 +685,6 @@ int CRYPTO_gcm128_encrypt(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, const unsigned char *in, unsigned char *out, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; block128_f block = ctx->block; @@ -842,11 +709,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, ctx->ares = 0; } - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); n = ctx->mres; if (n) { @@ -870,11 +733,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, if (n == 0) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); } c = in[i]; out[i] = c ^ ctx->EKi.c[n]; @@ -899,11 +758,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } @@ -922,11 +777,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { out_t[i] = in_t[i] ^ ctx->EKi.t[i]; } @@ -942,11 +793,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); for (size_t i = 0; i < 16 / sizeof(size_t); ++i) { size_t c = in_t[i]; out_t[i] = c ^ ctx->EKi.t[i]; @@ -961,11 +808,7 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, if (len) { (*block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { uint8_t c = in[n]; ctx->Xi.c[n] ^= c; @@ -981,10 +824,6 @@ int CRYPTO_gcm128_decrypt(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; #ifdef GCM_FUNCREF_4BIT @@ -1034,21 +873,13 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, } #endif - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); #if defined(GHASH) while (len >= GHASH_CHUNK) { (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); ctr += GHASH_CHUNK / 16; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); GHASH(ctx, out, GHASH_CHUNK); out += GHASH_CHUNK; in += GHASH_CHUNK; @@ -1061,11 +892,7 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, (*stream)(in, out, j, key, ctx->Yi.c); ctr += (unsigned int)j; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); in += i; len -= i; #if defined(GHASH) @@ -1084,11 +911,7 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, if (len) { (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { ctx->Xi.c[n] ^= out[n] = in[n] ^ ctx->EKi.c[n]; ++n; @@ -1102,10 +925,6 @@ int CRYPTO_gcm128_encrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, const uint8_t *in, uint8_t *out, size_t len, ctr128_f stream) { - const union { - long one; - char little; - } is_endian = {1}; unsigned int n, ctr; uint64_t mlen = ctx->len.u[1]; #ifdef GCM_FUNCREF_4BIT @@ -1157,22 +976,14 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, } #endif - if (is_endian.little) { - ctr = GETU32(ctx->Yi.c + 12); - } else { - ctr = ctx->Yi.d[3]; - } + ctr = GETU32_aligned(ctx->Yi.c + 12); #if defined(GHASH) while (len >= GHASH_CHUNK) { GHASH(ctx, in, GHASH_CHUNK); (*stream)(in, out, GHASH_CHUNK / 16, key, ctx->Yi.c); ctr += GHASH_CHUNK / 16; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); out += GHASH_CHUNK; in += GHASH_CHUNK; len -= GHASH_CHUNK; @@ -1198,11 +1009,7 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, #endif (*stream)(in, out, j, key, ctx->Yi.c); ctr += (unsigned int)j; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); out += i; in += i; len -= i; @@ -1210,11 +1017,7 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, if (len) { (*ctx->block)(ctx->Yi.c, ctx->EKi.c, key); ++ctr; - if (is_endian.little) { - PUTU32(ctx->Yi.c + 12, ctr); - } else { - ctx->Yi.d[3] = ctr; - } + PUTU32_aligned(ctx->Yi.c + 12, ctr); while (len--) { uint8_t c = in[n]; ctx->Xi.c[n] ^= c; @@ -1228,10 +1031,6 @@ int CRYPTO_gcm128_decrypt_ctr32(GCM128_CONTEXT *ctx, const void *key, } int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { - const union { - long one; - char little; - } is_endian = {1}; uint64_t alen = ctx->len.u[0] << 3; uint64_t clen = ctx->len.u[1] << 3; #ifdef GCM_FUNCREF_4BIT @@ -1242,20 +1041,8 @@ int CRYPTO_gcm128_finish(GCM128_CONTEXT *ctx, const uint8_t *tag, size_t len) { GCM_MUL(ctx, Xi); } - if (is_endian.little) { -#ifdef BSWAP8 - alen = BSWAP8(alen); - clen = BSWAP8(clen); -#else - uint8_t *p = ctx->len.c; - - ctx->len.u[0] = alen; - ctx->len.u[1] = clen; - - alen = (uint64_t)GETU32(p) << 32 | GETU32(p + 4); - clen = (uint64_t)GETU32(p + 8) << 32 | GETU32(p + 12); -#endif - } + alen = CRYPTO_bswap8(alen); + clen = CRYPTO_bswap8(clen); ctx->Xi.u[0] ^= alen; ctx->Xi.u[1] ^= clen; diff --git a/src/crypto/modes/gcm_test.cc b/src/crypto/modes/gcm_test.cc index 51d966e0..8baf20e2 100644 --- a/src/crypto/modes/gcm_test.cc +++ b/src/crypto/modes/gcm_test.cc @@ -46,6 +46,13 @@ * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== */ +/* Per C99, various stdint.h and inttypes.h macros (the latter used by + * internal.h) are unavailable in C++ unless some macros are defined. C++11 + * overruled this decision, but older Android NDKs still require it. */ +#if !defined(__STDC_CONSTANT_MACROS) +#define __STDC_CONSTANT_MACROS +#endif + #include <stdio.h> #include <string.h> @@ -388,12 +395,22 @@ out: return ret; } +static bool TestByteSwap() { + return CRYPTO_bswap4(0x01020304) == 0x04030201 && + CRYPTO_bswap8(UINT64_C(0x0102030405060708)) == + UINT64_C(0x0807060504030201); +} + int main(void) { int ret = 0; unsigned i; CRYPTO_library_init(); + if (!TestByteSwap()) { + ret = 1; + } + for (i = 0; i < sizeof(test_cases) / sizeof(struct test_case); i++) { if (!run_test_case(i, &test_cases[i])) { ret = 1; diff --git a/src/crypto/modes/internal.h b/src/crypto/modes/internal.h index 430d0401..a53da044 100644 --- a/src/crypto/modes/internal.h +++ b/src/crypto/modes/internal.h @@ -51,6 +51,8 @@ #include <openssl/base.h> +#include <string.h> + #if defined(__cplusplus) extern "C" { #endif @@ -64,90 +66,58 @@ extern "C" { #define STRICT_ALIGNMENT 0 #endif -#if !defined(PEDANTIC) && !defined(OPENSSL_NO_ASM) #if defined(__GNUC__) && __GNUC__ >= 2 -#if defined(OPENSSL_X86_64) -#define BSWAP8(x) \ - ({ \ - uint64_t ret = (x); \ - asm("bswapq %0" : "+r"(ret)); \ - ret; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret = (x); \ - asm("bswapl %0" : "+r"(ret)); \ - ret; \ - }) -#elif defined(OPENSSL_X86) -#define BSWAP8(x) \ - ({ \ - uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ - asm("bswapl %0; bswapl %1" : "+r"(hi), "+r"(lo)); \ - (uint64_t) hi << 32 | lo; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret = (x); \ - asm("bswapl %0" : "+r"(ret)); \ - ret; \ - }) -#elif defined(OPENSSL_AARCH64) -#define BSWAP8(x) \ - ({ \ - uint64_t ret; \ - asm("rev %0,%1" : "=r"(ret) : "r"(x)); \ - ret; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret; \ - asm("rev %w0,%w1" : "=r"(ret) : "r"(x)); \ - ret; \ - }) -#elif defined(OPENSSL_ARM) && !defined(STRICT_ALIGNMENT) -#define BSWAP8(x) \ - ({ \ - uint32_t lo = (uint64_t)(x) >> 32, hi = (x); \ - asm("rev %0,%0; rev %1,%1" : "+r"(hi), "+r"(lo)); \ - (uint64_t) hi << 32 | lo; \ - }) -#define BSWAP4(x) \ - ({ \ - uint32_t ret; \ - asm("rev %0,%1" : "=r"(ret) : "r"((uint32_t)(x))); \ - ret; \ - }) -#endif +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + return __builtin_bswap32(x); +} + +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return __builtin_bswap64(x); +} #elif defined(_MSC_VER) -#if _MSC_VER >= 1300 OPENSSL_MSVC_PRAGMA(warning(push, 3)) #include <intrin.h> OPENSSL_MSVC_PRAGMA(warning(pop)) #pragma intrinsic(_byteswap_uint64, _byteswap_ulong) -#define BSWAP8(x) _byteswap_uint64((uint64_t)(x)) -#define BSWAP4(x) _byteswap_ulong((uint32_t)(x)) -#elif defined(OPENSSL_X86) -__inline uint32_t _bswap4(uint32_t val) { - _asm mov eax, val - _asm bswap eax +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + return _byteswap_ulong(x); } -#define BSWAP4(x) _bswap4(x) -#endif -#endif -#endif -#if defined(BSWAP4) && !defined(STRICT_ALIGNMENT) -#define GETU32(p) BSWAP4(*(const uint32_t *)(p)) -#define PUTU32(p, v) *(uint32_t *)(p) = BSWAP4(v) +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return _byteswap_uint64(x); +} #else -#define GETU32(p) \ - ((uint32_t)(p)[0] << 24 | (uint32_t)(p)[1] << 16 | (uint32_t)(p)[2] << 8 | (uint32_t)(p)[3]) -#define PUTU32(p, v) \ - ((p)[0] = (uint8_t)((v) >> 24), (p)[1] = (uint8_t)((v) >> 16), \ - (p)[2] = (uint8_t)((v) >> 8), (p)[3] = (uint8_t)(v)) +static inline uint32_t CRYPTO_bswap4(uint32_t x) { + x = (x >> 16) | (x << 16); + x = ((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8); + return x; +} + +static inline uint64_t CRYPTO_bswap8(uint64_t x) { + return CRYPTO_bswap4(x >> 32) | (((uint64_t)CRYPTO_bswap4(x)) << 32); +} #endif +static inline uint32_t GETU32(const void *in) { + uint32_t v; + memcpy(&v, in, sizeof(v)); + return CRYPTO_bswap4(v); +} + +static inline void PUTU32(void *out, uint32_t v) { + v = CRYPTO_bswap4(v); + memcpy(out, &v, sizeof(v)); +} + +static inline uint32_t GETU32_aligned(const void *in) { + const char *alias = (const char *) in; + return CRYPTO_bswap4(*((const uint32_t *) alias)); +} + +static inline void PUTU32_aligned(void *in, uint32_t v) { + char *alias = (char *) in; + *((uint32_t *) alias) = CRYPTO_bswap4(v); +} /* block128_f is the type of a 128-bit, block cipher. */ typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], @@ -156,6 +126,16 @@ typedef void (*block128_f)(const uint8_t in[16], uint8_t out[16], /* GCM definitions */ typedef struct { uint64_t hi,lo; } u128; +/* gmult_func multiplies |Xi| by the GCM key and writes the result back to + * |Xi|. */ +typedef void (*gmult_func)(uint64_t Xi[2], const u128 Htable[16]); + +/* ghash_func repeatedly multiplies |Xi| by the GCM key and adds in blocks from + * |inp|. The result is written back to |Xi| and the |len| argument must be a + * multiple of 16. */ +typedef void (*ghash_func)(uint64_t Xi[2], const u128 Htable[16], + const uint8_t *inp, size_t len); + /* This differs from upstream's |gcm128_context| in that it does not have the * |key| pointer, in order to make it |memcpy|-friendly. Rather the key is * passed into each call that needs it. */ @@ -166,14 +146,11 @@ struct gcm128_context { uint32_t d[4]; uint8_t c[16]; size_t t[16 / sizeof(size_t)]; - } Yi, EKi, EK0, len, Xi, H; + } Yi, EKi, EK0, len, Xi; - /* Relative position of Xi, H and pre-computed Htable is used in some - * assembler modules, i.e. don't change the order! */ u128 Htable[16]; - void (*gmult)(uint64_t Xi[2], const u128 Htable[16]); - void (*ghash)(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp, - size_t len); + gmult_func gmult; + ghash_func ghash; unsigned int mres, ares; block128_f block; @@ -212,6 +189,12 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, uint8_t ecount_buf[16], unsigned *num, ctr128_f ctr); +#if !defined(OPENSSL_NO_ASM) && \ + (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) +void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, + const void *key, const uint8_t *ivec); +#endif + /* GCM. * @@ -222,6 +205,12 @@ void CRYPTO_ctr128_encrypt_ctr32(const uint8_t *in, uint8_t *out, size_t len, typedef struct gcm128_context GCM128_CONTEXT; +/* CRYPTO_ghash_init writes a precomputed table of powers of |gcm_key| to + * |out_table| and sets |*out_mult| and |*out_hash| to (potentially hardware + * accelerated) functions for performing operations in the GHASH field. */ +void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash, + u128 out_table[16], const uint8_t *gcm_key); + /* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with * the given key. */ OPENSSL_EXPORT void CRYPTO_gcm128_init(GCM128_CONTEXT *ctx, const void *key, @@ -345,11 +334,36 @@ size_t CRYPTO_cts128_encrypt_block(const uint8_t *in, uint8_t *out, size_t len, block128_f block); -#if !defined(OPENSSL_NO_ASM) && \ - (defined(OPENSSL_X86) || defined(OPENSSL_X86_64)) -void aesni_ctr32_encrypt_blocks(const uint8_t *in, uint8_t *out, size_t blocks, - const void *key, const uint8_t *ivec); -#endif +/* POLYVAL. + * + * POLYVAL is a polynomial authenticator that operates over a field very + * similar to the one that GHASH uses. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#section-3. */ + +typedef union { + uint64_t u[2]; + uint8_t c[16]; +} polyval_block; + +struct polyval_ctx { + polyval_block S; + u128 Htable[16]; + gmult_func gmult; + ghash_func ghash; +}; + +/* CRYPTO_POLYVAL_init initialises |ctx| using |key|. */ +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]); + +/* CRYPTO_POLYVAL_update_blocks updates the accumulator in |ctx| given the + * blocks from |in|. Only a whole number of blocks can be processed so |in_len| + * must be a multiple of 16. */ +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len); + +/* CRYPTO_POLYVAL_finish writes the accumulator from |ctx| to |out|. */ +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]); + #if defined(__cplusplus) } /* extern C */ diff --git a/src/crypto/modes/polyval.c b/src/crypto/modes/polyval.c new file mode 100644 index 00000000..c5121a18 --- /dev/null +++ b/src/crypto/modes/polyval.c @@ -0,0 +1,93 @@ +/* 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/base.h> + +#if !defined(OPENSSL_SMALL) + +#include <assert.h> +#include <string.h> + +#include "internal.h" +#include "../internal.h" + + +/* byte_reverse reverses the order of the bytes in |b->c|. */ +static void byte_reverse(polyval_block *b) { + const uint64_t t = CRYPTO_bswap8(b->u[0]); + b->u[0] = CRYPTO_bswap8(b->u[1]); + b->u[1] = t; +} + +/* reverse_and_mulX_ghash interprets the bytes |b->c| as a reversed element of + * the GHASH field, multiplies that by 'x' and serialises the result back into + * |b|, but with GHASH's backwards bit ordering. */ +static void reverse_and_mulX_ghash(polyval_block *b) { + uint64_t hi = b->u[0]; + uint64_t lo = b->u[1]; + const unsigned carry = constant_time_eq(hi & 1, 1); + hi >>= 1; + hi |= lo << 63; + lo >>= 1; + lo ^= ((uint64_t) constant_time_select(carry, 0xe1, 0)) << 56; + + b->u[0] = CRYPTO_bswap8(lo); + b->u[1] = CRYPTO_bswap8(hi); +} + +/* POLYVAL(H, X_1, ..., X_n) = + * ByteReverse(GHASH(mulX_GHASH(ByteReverse(H)), ByteReverse(X_1), ..., + * ByteReverse(X_n))). + * + * See https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02#appendix-A. */ + +void CRYPTO_POLYVAL_init(struct polyval_ctx *ctx, const uint8_t key[16]) { + polyval_block H; + memcpy(H.c, key, 16); + reverse_and_mulX_ghash(&H); + + CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, H.c); + memset(&ctx->S, 0, sizeof(ctx->S)); +} + +void CRYPTO_POLYVAL_update_blocks(struct polyval_ctx *ctx, const uint8_t *in, + size_t in_len) { + assert((in_len & 15) == 0); + polyval_block reversed[32]; + + while (in_len > 0) { + size_t todo = in_len; + if (todo > sizeof(reversed)) { + todo = sizeof(reversed); + } + memcpy(reversed, in, todo); + in_len -= todo; + + size_t blocks = todo / sizeof(polyval_block); + for (size_t i = 0; i < blocks; i++) { + byte_reverse(&reversed[i]); + } + + ctx->ghash(ctx->S.u, ctx->Htable, (const uint8_t *) reversed, todo); + } +} + +void CRYPTO_POLYVAL_finish(const struct polyval_ctx *ctx, uint8_t out[16]) { + polyval_block S = ctx->S; + byte_reverse(&S); + memcpy(out, &S.c, sizeof(polyval_block)); +} + + +#endif /* !OPENSSL_SMALL */ diff --git a/src/crypto/rand/urandom.c b/src/crypto/rand/urandom.c index 25726259..17d194c5 100644 --- a/src/crypto/rand/urandom.c +++ b/src/crypto/rand/urandom.c @@ -21,6 +21,7 @@ #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <stdio.h> #include <string.h> #include <unistd.h> @@ -87,12 +88,16 @@ struct rand_buffer { /* requested_lock is used to protect the |*_requested| variables. */ static struct CRYPTO_STATIC_MUTEX requested_lock = CRYPTO_STATIC_MUTEX_INIT; -/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by +/* The following constants are magic values of |urandom_fd|. */ +static const int kUnset = -2; +static const int kHaveGetrandom = -3; + +/* urandom_fd_requested is set by |RAND_set_urandom_fd|. It's protected by * |requested_lock|. */ -static int urandom_fd_requested = -2; +static int urandom_fd_requested = -2 /* kUnset */; /* urandom_fd is a file descriptor to /dev/urandom. It's protected by |once|. */ -static int urandom_fd = -2; +static int urandom_fd = -2 /* kUnset */; /* urandom_buffering_requested is set by |RAND_enable_fork_unsafe_buffering|. * It's protected by |requested_lock|. */ @@ -115,12 +120,31 @@ static void init_once(void) { CRYPTO_STATIC_MUTEX_unlock_read(&requested_lock); #if defined(USE_SYS_getrandom) - /* Initial test of getrandom to find any unexpected behavior. */ uint8_t dummy; - syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); -#endif + long getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), GRND_NONBLOCK); + + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } else if (getrandom_ret == -1 && errno == EAGAIN) { + fprintf(stderr, + "getrandom indicates that the entropy pool has not been " + "initialized. Rather than continue with poor entropy, this process " + "will block until entropy is available.\n"); + do { + getrandom_ret = + syscall(SYS_getrandom, &dummy, sizeof(dummy), 0 /* no flags */); + } while (getrandom_ret == -1 && errno == EINTR); + + if (getrandom_ret == 1) { + urandom_fd = kHaveGetrandom; + return; + } + } +#endif /* USE_SYS_getrandom */ - if (fd == -2) { + if (fd == kUnset) { do { fd = open("/dev/urandom", O_RDONLY); } while (fd == -1 && errno == EINTR); @@ -156,7 +180,9 @@ void RAND_set_urandom_fd(int fd) { CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_fd != fd) { + if (urandom_fd == kHaveGetrandom) { + close(fd); + } else if (urandom_fd != fd) { abort(); // Already initialized. } } @@ -168,7 +194,7 @@ void RAND_enable_fork_unsafe_buffering(int fd) { abort(); } } else { - fd = -2; + fd = kUnset; } CRYPTO_STATIC_MUTEX_lock_write(&requested_lock); @@ -177,7 +203,15 @@ void RAND_enable_fork_unsafe_buffering(int fd) { CRYPTO_STATIC_MUTEX_unlock_write(&requested_lock); CRYPTO_once(&once, init_once); - if (urandom_buffering != 1 || (fd >= 0 && urandom_fd != fd)) { + if (urandom_buffering != 1) { + abort(); // Already initialized + } + + if (urandom_fd == kHaveGetrandom) { + if (fd >= 0) { + close(fd); + } + } else if (urandom_fd != fd) { abort(); // Already initialized. } } @@ -209,9 +243,19 @@ static char fill_with_entropy(uint8_t *out, size_t len) { ssize_t r; while (len > 0) { - do { - r = read(urandom_fd, out, len); - } while (r == -1 && errno == EINTR); + if (urandom_fd == kHaveGetrandom) { +#if defined(USE_SYS_getrandom) + do { + r = syscall(SYS_getrandom, out, len, 0 /* no flags */); + } while (r == -1 && errno == EINTR); +#else + abort(); +#endif + } else { + do { + r = read(urandom_fd, out, len); + } while (r == -1 && errno == EINTR); + } if (r <= 0) { return 0; diff --git a/src/crypto/sha/asm/sha256-armv4.pl b/src/crypto/sha/asm/sha256-armv4.pl index e1be2269..bac7ce85 100644 --- a/src/crypto/sha/asm/sha256-armv4.pl +++ b/src/crypto/sha/asm/sha256-armv4.pl @@ -1,4 +1,11 @@ -#!/usr/bin/env perl +#! /usr/bin/env perl +# Copyright 2007-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 @@ -175,16 +182,11 @@ $code=<<___; #endif .text -#if __ARM_ARCH__<7 -.code 32 -#else +#if defined(__thumb2__) .syntax unified -# if defined(__thumb2__) && !defined(__APPLE__) -# define adrl adr .thumb -# else +#else .code 32 -# endif #endif .type K256,%object @@ -218,10 +220,10 @@ K256: .type sha256_block_data_order,%function sha256_block_data_order: .Lsha256_block_data_order: -#if __ARM_ARCH__<7 +#if __ARM_ARCH__<7 && !defined(__thumb2__) sub r3,pc,#8 @ sha256_block_data_order #else - adr r3,sha256_block_data_order + adr r3,.Lsha256_block_data_order #endif #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) ldr r12,.LOPENSSL_armcap @@ -473,13 +475,14 @@ $code.=<<___; .global sha256_block_data_order_neon .type sha256_block_data_order_neon,%function -.align 4 +.align 5 +.skip 16 sha256_block_data_order_neon: .LNEON: stmdb sp!,{r4-r12,lr} sub $H,sp,#16*4+16 - adrl $Ktbl,K256 + adr $Ktbl,K256 bic $H,$H,#15 @ align for 128-bit stores mov $t2,sp mov sp,$H @ alloca @@ -599,7 +602,7 @@ my $Ktbl="r3"; $code.=<<___; #if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__) -# if defined(__thumb2__) && !defined(__APPLE__) +# if defined(__thumb2__) # define INST(a,b,c,d) .byte c,d|0xc,a,b # else # define INST(a,b,c,d) .byte a,b,c,d @@ -610,16 +613,11 @@ $code.=<<___; sha256_block_data_order_armv8: .LARMv8: vld1.32 {$ABCD,$EFGH},[$ctx] -# ifdef __APPLE__ sub $Ktbl,$Ktbl,#256+32 -# elif defined(__thumb2__) - adr $Ktbl,.LARMv8 - sub $Ktbl,$Ktbl,#.LARMv8-K256 -# else - adrl $Ktbl,K256 -# endif add $len,$inp,$len,lsl#6 @ len to point at the end of inp + b .Loop_v8 +.align 4 .Loop_v8: vld1.8 {@MSG[0]-@MSG[1]},[$inp]! vld1.8 {@MSG[2]-@MSG[3]},[$inp]! diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc index c39d98d9..0c25754e 100644 --- a/src/crypto/x509/x509_test.cc +++ b/src/crypto/x509/x509_test.cc @@ -25,7 +25,6 @@ #include <openssl/pool.h> #include <openssl/x509.h> -namespace bssl { static const char kCrossSigningRootPEM[] = "-----BEGIN CERTIFICATE-----\n" @@ -724,7 +723,7 @@ static bool TestSignCtx() { } // Test PKCS#1 v1.5. - ScopedEVP_MD_CTX md_ctx; + bssl::ScopedEVP_MD_CTX md_ctx; if (!EVP_DigestSignInit(md_ctx.get(), NULL, EVP_sha256(), NULL, pkey.get()) || !SignatureRoundTrips(md_ctx.get(), pkey.get())) { fprintf(stderr, "RSA PKCS#1 with SHA-256 failed\n"); @@ -941,7 +940,51 @@ static bool TestFromBufferReused() { return true; } -static int Main() { +static bool TestFailedParseFromBuffer() { + static const uint8_t kNonsense[] = {1, 2, 3, 4, 5}; + + bssl::UniquePtr<CRYPTO_BUFFER> buf( + CRYPTO_BUFFER_new(kNonsense, sizeof(kNonsense), nullptr)); + if (!buf) { + return false; + } + + bssl::UniquePtr<X509> cert(X509_parse_from_buffer(buf.get())); + if (cert) { + fprintf(stderr, "Nonsense somehow parsed.\n"); + return false; + } + ERR_clear_error(); + + // Test a buffer with trailing data. + size_t data_len; + bssl::UniquePtr<uint8_t> data; + if (!PEMToDER(&data, &data_len, kRootCAPEM)) { + return false; + } + + std::unique_ptr<uint8_t[]> data_with_trailing_byte(new uint8_t[data_len + 1]); + memcpy(data_with_trailing_byte.get(), data.get(), data_len); + data_with_trailing_byte[data_len] = 0; + + bssl::UniquePtr<CRYPTO_BUFFER> buf_with_trailing_byte( + CRYPTO_BUFFER_new(data_with_trailing_byte.get(), data_len + 1, nullptr)); + if (!buf_with_trailing_byte) { + return false; + } + + bssl::UniquePtr<X509> root( + X509_parse_from_buffer(buf_with_trailing_byte.get())); + if (root) { + fprintf(stderr, "Parsed buffer with trailing byte.\n"); + return false; + } + ERR_clear_error(); + + return true; +} + +int main() { CRYPTO_library_init(); if (!TestVerify() || @@ -952,16 +995,11 @@ static int Main() { !TestFromBuffer() || !TestFromBufferTrailingData() || !TestFromBufferModified() || - !TestFromBufferReused()) { + !TestFromBufferReused() || + !TestFailedParseFromBuffer()) { return 1; } printf("PASS\n"); return 0; } - -} // namespace bssl - -int main() { - return bssl::Main(); -} diff --git a/src/crypto/x509/x_x509.c b/src/crypto/x509/x_x509.c index 845d4b28..d3cd5b0d 100644 --- a/src/crypto/x509/x_x509.c +++ b/src/crypto/x509/x_x509.c @@ -106,6 +106,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, ret->crldp = NULL; ret->buf = NULL; CRYPTO_new_ex_data(&ret->ex_data); + CRYPTO_MUTEX_init(&ret->lock); break; case ASN1_OP_D2I_PRE: @@ -120,6 +121,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, break; case ASN1_OP_FREE_POST: + CRYPTO_MUTEX_cleanup(&ret->lock); CRYPTO_free_ex_data(&g_ex_data_class, ret, &ret->ex_data); X509_CERT_AUX_free(ret->aux); ASN1_OCTET_STRING_free(ret->skid); @@ -129,9 +131,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, GENERAL_NAMES_free(ret->altname); NAME_CONSTRAINTS_free(ret->nc); CRYPTO_BUFFER_free(ret->buf); - - if (ret->name != NULL) - OPENSSL_free(ret->name); + OPENSSL_free(ret->name); break; } @@ -162,8 +162,8 @@ X509 *X509_parse_from_buffer(CRYPTO_BUFFER *buf) { X509 *x509p = x509; X509 *ret = d2i_X509(&x509p, &inp, CRYPTO_BUFFER_len(buf)); if (ret == NULL || - (inp - CRYPTO_BUFFER_data(buf)) != (ptrdiff_t) CRYPTO_BUFFER_len(buf)) { - X509_free(x509); + inp - CRYPTO_BUFFER_data(buf) != (ptrdiff_t)CRYPTO_BUFFER_len(buf)) { + X509_free(x509p); return NULL; } assert(x509p == x509); diff --git a/src/crypto/x509v3/v3_purp.c b/src/crypto/x509v3/v3_purp.c index 91524444..324de85a 100644 --- a/src/crypto/x509v3/v3_purp.c +++ b/src/crypto/x509v3/v3_purp.c @@ -146,9 +146,7 @@ int X509_check_purpose(X509 *x, int id, int ca) { int idx; const X509_PURPOSE *pt; - if (!(x->ex_flags & EXFLAG_SET)) { - x509v3_cache_extensions(x); - } + x509v3_cache_extensions(x); if (id == -1) return 1; idx = X509_PURPOSE_get_by_id(id); @@ -407,16 +405,6 @@ static void setup_crldp(X509 *x) setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); } -/* - * g_x509_cache_extensions_lock is used to protect against concurrent calls - * to |x509v3_cache_extensions|. Ideally this would be done with a - * |CRYPTO_once_t| in the |X509| structure, but |CRYPTO_once_t| isn't public. - * Note: it's not entirely clear whether this lock is needed. Not all paths to - * this function took a lock in OpenSSL. - */ -static struct CRYPTO_STATIC_MUTEX g_x509_cache_extensions_lock = - CRYPTO_STATIC_MUTEX_INIT; - static void x509v3_cache_extensions(X509 *x) { BASIC_CONSTRAINTS *bs; @@ -428,10 +416,17 @@ static void x509v3_cache_extensions(X509 *x) size_t i; int j; - CRYPTO_STATIC_MUTEX_lock_write(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_lock_read(&x->lock); + const int is_set = x->ex_flags & EXFLAG_SET; + CRYPTO_MUTEX_unlock_read(&x->lock); + if (is_set) { + return; + } + + CRYPTO_MUTEX_lock_write(&x->lock); if (x->ex_flags & EXFLAG_SET) { - CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_unlock_write(&x->lock); return; } @@ -564,7 +559,7 @@ static void x509v3_cache_extensions(X509 *x) } x->ex_flags |= EXFLAG_SET; - CRYPTO_STATIC_MUTEX_unlock_write(&g_x509_cache_extensions_lock); + CRYPTO_MUTEX_unlock_write(&x->lock); } /* @@ -604,10 +599,7 @@ static int check_ca(const X509 *x) int X509_check_ca(X509 *x) { - if (!(x->ex_flags & EXFLAG_SET)) { - x509v3_cache_extensions(x); - } - + x509v3_cache_extensions(x); return check_ca(x); } diff --git a/src/include/openssl/aead.h b/src/include/openssl/aead.h index fff0e496..eaa2b8fd 100644 --- a/src/include/openssl/aead.h +++ b/src/include/openssl/aead.h @@ -114,6 +114,14 @@ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_ctr_hmac_sha256(void); * authentication. See |EVP_aead_aes_128_ctr_hmac_sha256| for details. */ OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_ctr_hmac_sha256(void); +/* EVP_aead_aes_128_gcm_siv is AES-128 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_128_gcm_siv(void); + +/* EVP_aead_aes_256_gcm_siv is AES-256 in GCM-SIV mode. See + * https://tools.ietf.org/html/draft-irtf-cfrg-gcmsiv-02 */ +OPENSSL_EXPORT const EVP_AEAD *EVP_aead_aes_256_gcm_siv(void); + /* EVP_has_aes_hardware returns one if we enable hardware support for fast and * constant-time AES-GCM. */ OPENSSL_EXPORT int EVP_has_aes_hardware(void); diff --git a/src/include/openssl/bio.h b/src/include/openssl/bio.h index 3c8b97d4..58a47479 100644 --- a/src/include/openssl/bio.h +++ b/src/include/openssl/bio.h @@ -616,18 +616,6 @@ OPENSSL_EXPORT int BIO_do_connect(BIO *bio); OPENSSL_EXPORT int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, size_t writebuf2); -/* BIO_new_bio_pair_external_buf is the same as |BIO_new_bio_pair| with the - * difference that the caller keeps ownership of the write buffers - * |ext_writebuf1_len| and |ext_writebuf2_len|. This is useful when using zero - * copy API for read and write operations, in cases where the buffers need to - * outlive the BIO pairs. It returns one on success and zero on error. */ -OPENSSL_EXPORT int BIO_new_bio_pair_external_buf(BIO** bio1_p, - size_t writebuf1_len, - uint8_t* ext_writebuf1, - BIO** bio2_p, - size_t writebuf2_len, - uint8_t* ext_writebuf2); - /* BIO_ctrl_get_read_request returns the number of bytes that the other side of * |bio| tried (unsuccessfully) to read. */ OPENSSL_EXPORT size_t BIO_ctrl_get_read_request(BIO *bio); @@ -643,63 +631,6 @@ OPENSSL_EXPORT size_t BIO_ctrl_get_write_guarantee(BIO *bio); OPENSSL_EXPORT int BIO_shutdown_wr(BIO *bio); -/* Zero copy versions of BIO_read and BIO_write for BIO pairs. */ - -/* BIO_zero_copy_get_read_buf initiates a zero copy read operation. - * |out_read_buf| is set to the internal read buffer, and |out_buf_offset| is - * set to the current read position of |out_read_buf|. The number of bytes - * available for read from |out_read_buf| + |out_buf_offset| is returned in - * |out_available_bytes|. Note that this function might report fewer bytes - * available than |BIO_pending|, if the internal ring buffer is wrapped. It - * returns one on success. In case of error it returns zero and pushes to the - * error stack. - * - * The zero copy read operation is completed by calling - * |BIO_zero_copy_get_read_buf_done|. Neither |BIO_zero_copy_get_read_buf| nor - * any other I/O read operation may be called while a zero copy read operation - * is active. */ -OPENSSL_EXPORT int BIO_zero_copy_get_read_buf(BIO* bio, - uint8_t** out_read_buf, - size_t* out_buf_offset, - size_t* out_available_bytes); - -/* BIO_zero_copy_get_read_buf_done must be called after reading from a BIO using - * |BIO_zero_copy_get_read_buf| to finish the read operation. The |bytes_read| - * argument is the number of bytes read. - * - * It returns one on success. In case of error it returns zero and pushes to the - * error stack. */ -OPENSSL_EXPORT int BIO_zero_copy_get_read_buf_done(BIO* bio, size_t bytes_read); - -/* BIO_zero_copy_get_write_buf initiates a zero copy write operation. - * |out_write_buf| is set to to the internal write buffer, and |out_buf_offset| - * is set to the current write position of |out_write_buf|. - * The number of bytes available for write from |out_write_buf| + - * |out_buf_offset| is returned in |out_available_bytes|. Note that this - * function might report fewer bytes available than - * |BIO_ctrl_get_write_guarantee|, if the internal buffer is wrapped. It returns - * one on success. In case of error it returns zero and pushes to the error - * stack. - * - * The zero copy write operation is completed by calling - * |BIO_zero_copy_get_write_buf_done|. Neither |BIO_zero_copy_get_write_buf| - * nor any other I/O write operation may be called while a zero copy write - * operation is active. */ -OPENSSL_EXPORT int BIO_zero_copy_get_write_buf(BIO* bio, - uint8_t** out_write_buf, - size_t* out_buf_offset, - size_t* out_available_bytes); - -/* BIO_zero_copy_get_write_buf_done must be called after writing to a BIO using - * |BIO_zero_copy_get_write_buf| to finish the write operation. The - * |bytes_written| argument gives the number of bytes written. - * - * It returns one on success. In case of error it returns zero and pushes to the - * error stack. */ -OPENSSL_EXPORT int BIO_zero_copy_get_write_buf_done(BIO* bio, - size_t bytes_written); - - /* BIO_NOCLOSE and |BIO_CLOSE| can be used as symbolic arguments when a "close * flag" is passed to a BIO function. */ #define BIO_NOCLOSE 0 diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h index 764d8c5f..8deb278f 100644 --- a/src/include/openssl/bn.h +++ b/src/include/openssl/bn.h @@ -575,8 +575,10 @@ OPENSSL_EXPORT int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, OPENSSL_EXPORT int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m); -/* BN_mod_sqrt returns a |BIGNUM|, r, such that r^2 == a (mod p). |p| must be a - * prime. */ +/* BN_mod_sqrt returns a newly-allocated |BIGNUM|, r, such that + * r^2 == a (mod p). |p| must be a prime. It returns NULL on error or if |a| is + * not a square mod |p|. In the latter case, it will add |BN_R_NOT_A_SQUARE| to + * the error queue. */ OPENSSL_EXPORT BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx); diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index f5b9f9d3..c29040ac 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -608,11 +608,6 @@ OPENSSL_EXPORT int SSL_version(const SSL *ssl); * client's. */ #define SSL_OP_CIPHER_SERVER_PREFERENCE 0x00400000L -/* SSL_OP_DISABLE_NPN configures an individual |SSL| to not advertise NPN, - * despite |SSL_CTX_set_next_proto_select_cb| being configured on the - * |SSL_CTX|. */ -#define SSL_OP_DISABLE_NPN 0x00800000L - /* The following flags toggle individual protocol versions. This is deprecated. * Use |SSL_CTX_set_min_proto_version| and |SSL_CTX_set_max_proto_version| * instead. */ @@ -1620,7 +1615,7 @@ OPENSSL_EXPORT long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout); * should not be used. */ OPENSSL_EXPORT int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); /* Session caching. @@ -1721,6 +1716,15 @@ OPENSSL_EXPORT long SSL_CTX_set_timeout(SSL_CTX *ctx, long timeout); * |ctx|. */ OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); +/* SSL_set_session_timeout sets the default lifetime, in seconds, of the + * session created in |ssl| to |timeout|, and returns the old value. + * + * By default the value |SSL_DEFAULT_SESSION_TIMEOUT| is used, which can be + * overridden at the context level by calling |SSL_CTX_set_timeout|. + * + * If |timeout| is zero the newly created session will not be resumable. */ +OPENSSL_EXPORT long SSL_set_session_timeout(SSL *ssl, long timeout); + /* SSL_CTX_set_session_id_context sets |ctx|'s session ID context to |sid_ctx|. * It returns one on success and zero on error. The session ID context is an * application-defined opaque byte string. A session will not be used in a @@ -1734,13 +1738,13 @@ OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); * relevant if a server requires client auth. */ OPENSSL_EXPORT int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); /* SSL_set_session_id_context sets |ssl|'s session ID context to |sid_ctx|. It * returns one on success and zero on error. See also * |SSL_CTX_set_session_id_context|. */ OPENSSL_EXPORT int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, - unsigned sid_ctx_len); + size_t sid_ctx_len); /* SSL_SESSION_CACHE_MAX_SIZE_DEFAULT is the default maximum size of a session * cache. */ @@ -2502,15 +2506,14 @@ OPENSSL_EXPORT int SSL_select_next_proto(uint8_t **out, uint8_t *out_len, * * See draft-balfanz-tls-channelid-01. */ -/* SSL_CTX_enable_tls_channel_id either configures a TLS server to accept TLS - * Channel IDs from clients, or configures a client to send TLS Channel IDs to - * a server. It returns one. */ -OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); +/* SSL_CTX_set_tls_channel_id_enabled configures whether connections associated + * with |ctx| should enable Channel ID. */ +OPENSSL_EXPORT void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, + int enabled); -/* SSL_enable_tls_channel_id either configures a TLS server to accept TLS - * Channel IDs from clients, or configures a client to send TLS Channel IDs to - * server. It returns one. */ -OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); +/* SSL_set_tls_channel_id_enabled configures whether |ssl| should enable Channel + * ID. */ +OPENSSL_EXPORT void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled); /* SSL_CTX_set1_tls_channel_id configures a TLS client to send a TLS Channel ID * to compatible servers. |private_key| must be a P-256 EC key. It returns one @@ -2942,10 +2945,11 @@ OPENSSL_EXPORT int SSL_CTX_set_max_send_fragment(SSL_CTX *ctx, OPENSSL_EXPORT int SSL_set_max_send_fragment(SSL *ssl, size_t max_send_fragment); -/* ssl_early_callback_ctx is passed to certain callbacks that are called very - * early on during the server handshake. At this point, much of the SSL* hasn't - * been filled out and only the ClientHello can be depended on. */ -struct ssl_early_callback_ctx { +/* ssl_early_callback_ctx (aka |SSL_CLIENT_HELLO|) is passed to certain + * callbacks that are called very early on during the server handshake. At this + * point, much of the SSL* hasn't been filled out and only the ClientHello can + * be depended on. */ +typedef struct ssl_early_callback_ctx { SSL *ssl; const uint8_t *client_hello; size_t client_hello_len; @@ -2960,15 +2964,15 @@ struct ssl_early_callback_ctx { size_t compression_methods_len; const uint8_t *extensions; size_t extensions_len; -}; +} SSL_CLIENT_HELLO; -/* SSL_early_callback_ctx_extension_get searches the extensions in |ctx| for an - * extension of the given type. If not found, it returns zero. Otherwise it - * sets |out_data| to point to the extension contents (not including the type - * and length bytes), sets |out_len| to the length of the extension contents - * and returns one. */ +/* SSL_early_callback_ctx_extension_get searches the extensions in + * |client_hello| for an extension of the given type. If not found, it returns + * zero. Otherwise it sets |out_data| to point to the extension contents (not + * including the type and length bytes), sets |out_len| to the length of the + * extension contents and returns one. */ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get( - const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, + const SSL_CLIENT_HELLO *client_hello, uint16_t extension_type, const uint8_t **out_data, size_t *out_len); /* SSL_CTX_set_select_certificate_cb sets a callback that is called before most @@ -2978,19 +2982,19 @@ OPENSSL_EXPORT int SSL_early_callback_ctx_extension_get( * pause the handshake to perform an asynchronous operation. If paused, * |SSL_get_error| will return |SSL_ERROR_PENDING_CERTIFICATE|. * - * Note: The |ssl_early_callback_ctx| is only valid for the duration of the - * callback and is not valid while the handshake is paused. Further, unlike with - * most callbacks, when the handshake loop is resumed, it will not call the - * callback a second time. The caller must finish reconfiguring the connection - * before resuming the handshake. */ + * Note: The |SSL_CLIENT_HELLO| is only valid for the duration of the callback + * and is not valid while the handshake is paused. Further, unlike with most + * callbacks, when the handshake loop is resumed, it will not call the callback + * a second time. The caller must finish reconfiguring the connection before + * resuming the handshake. */ OPENSSL_EXPORT void SSL_CTX_set_select_certificate_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *)); /* SSL_CTX_set_dos_protection_cb sets a callback that is called once the * resumption decision for a ClientHello has been made. It can return one to * allow the handshake to continue or zero to cause the handshake to abort. */ OPENSSL_EXPORT void SSL_CTX_set_dos_protection_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)); + SSL_CTX *ctx, int (*cb)(const SSL_CLIENT_HELLO *)); /* SSL_ST_* are possible values for |SSL_state| and the bitmasks that make them * up. */ @@ -3146,11 +3150,6 @@ OPENSSL_EXPORT size_t SSL_max_seal_overhead(const SSL *ssl); /* SSL_library_init calls |CRYPTO_library_init| and returns one. */ OPENSSL_EXPORT int SSL_library_init(void); -/* SSL_set_reject_peer_renegotiations calls |SSL_set_renegotiate_mode| with - * |ssl_never_renegotiate| if |reject| is one and |ssl_renegotiate_freely| if - * zero. */ -OPENSSL_EXPORT void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject); - /* SSL_CIPHER_description writes a description of |cipher| into |buf| and * returns |buf|. If |buf| is NULL, it returns a newly allocated string, to be * freed with |OPENSSL_free|, or NULL on error. @@ -3627,6 +3626,12 @@ OPENSSL_EXPORT int SSL_set_min_version(SSL *ssl, uint16_t version); /* SSL_set_max_version calls |SSL_set_max_proto_version|. */ OPENSSL_EXPORT int SSL_set_max_version(SSL *ssl, uint16_t version); +/* SSL_CTX_enable_tls_channel_id calls |SSL_CTX_set_tls_channel_id_enabled|. */ +OPENSSL_EXPORT int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx); + +/* SSL_enable_tls_channel_id calls |SSL_set_tls_channel_id_enabled|. */ +OPENSSL_EXPORT int SSL_enable_tls_channel_id(SSL *ssl); + /* Private structures. * @@ -3679,7 +3684,7 @@ struct ssl_session_st { /* this is used to determine whether the session is being reused in * the appropriate context. It is up to the application to set this, * via SSL_new */ - unsigned int sid_ctx_length; + uint8_t sid_ctx_length; uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; char *psk_identity; @@ -3730,7 +3735,7 @@ struct ssl_session_st { * SHA-2, depending on TLS version) for the original, full handshake that * created a session. This is used by Channel IDs during resumption. */ uint8_t original_handshake_hash[EVP_MAX_MD_SIZE]; - unsigned original_handshake_hash_len; + uint8_t original_handshake_hash_len; uint32_t tlsext_tick_lifetime_hint; /* Session lifetime hint in seconds */ @@ -3903,7 +3908,7 @@ struct ssl_ctx_st { void *msg_callback_arg; int verify_mode; - unsigned int sid_ctx_length; + uint8_t sid_ctx_length; uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; int (*default_verify_callback)( int ok, X509_STORE_CTX *ctx); /* called 'verify_callback' in the SSL */ @@ -3916,12 +3921,12 @@ struct ssl_ctx_st { * with an error and cause SSL_get_error to return * SSL_ERROR_PENDING_CERTIFICATE. Note: when the handshake loop is resumed, it * will not call the callback a second time. */ - int (*select_certificate_cb)(const struct ssl_early_callback_ctx *); + int (*select_certificate_cb)(const SSL_CLIENT_HELLO *); /* dos_protection_cb is called once the resumption decision for a ClientHello * has been made. It returns one to continue the handshake or zero to * abort. */ - int (*dos_protection_cb) (const struct ssl_early_callback_ctx *); + int (*dos_protection_cb) (const SSL_CLIENT_HELLO *); /* Maximum amount of data to send in one fragment. actual record size can be * more than this due to padding and MAC overheads. */ @@ -4042,6 +4047,8 @@ struct ssl_ctx_st { int freelist_max_len; }; +typedef struct ssl_handshake_st SSL_HANDSHAKE; + struct ssl_st { /* method is the method table corresponding to the current protocol (DTLS or * TLS). */ @@ -4080,7 +4087,7 @@ struct ssl_st { * with a better mechanism. */ BIO *bbio; - int (*handshake_func)(SSL *); + int (*handshake_func)(SSL_HANDSHAKE *hs); BUF_MEM *init_buf; /* buffer used during init */ @@ -4123,7 +4130,7 @@ struct ssl_st { /* the session_id_context is used to ensure sessions are only reused * in the appropriate context */ - unsigned int sid_ctx_length; + uint8_t sid_ctx_length; uint8_t sid_ctx[SSL_MAX_SID_CTX_LENGTH]; /* session is the configured session to be offered by the client. This session @@ -4157,8 +4164,6 @@ struct ssl_st { uint32_t options; /* protocol behaviour */ uint32_t mode; /* API behaviour */ uint32_t max_cert_list; - int client_version; /* what was passed, used for - * SSLv3/TLS rollback check */ char *tlsext_hostname; size_t supported_group_list_len; uint16_t *supported_group_list; /* our list */ @@ -4215,6 +4220,10 @@ struct ssl_st { /* TODO(agl): remove once node.js not longer references this. */ int tlsext_status_type; + + /* session_timeout is the default lifetime in seconds of the session + * created in this connection. */ + long session_timeout; }; @@ -4267,7 +4276,6 @@ struct ssl_st { #define SSL_CTRL_NEED_TMP_RSA doesnt_exist #define SSL_CTRL_OPTIONS doesnt_exist #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 @@ -4299,7 +4307,6 @@ struct ssl_st { #define SSL_CTX_clear_chain_certs SSL_CTX_clear_chain_certs #define SSL_CTX_clear_mode SSL_CTX_clear_mode #define SSL_CTX_clear_options SSL_CTX_clear_options -#define SSL_CTX_enable_tls_channel_id SSL_CTX_enable_tls_channel_id #define SSL_CTX_get0_chain_certs SSL_CTX_get0_chain_certs #define SSL_CTX_get_extra_chain_certs SSL_CTX_get_extra_chain_certs #define SSL_CTX_get_max_cert_list SSL_CTX_get_max_cert_list @@ -4315,7 +4322,6 @@ struct ssl_st { #define SSL_CTX_set0_chain SSL_CTX_set0_chain #define SSL_CTX_set1_chain SSL_CTX_set1_chain #define SSL_CTX_set1_curves SSL_CTX_set1_curves -#define SSL_CTX_set1_tls_channel_id SSL_CTX_set1_tls_channel_id #define SSL_CTX_set_max_cert_list SSL_CTX_set_max_cert_list #define SSL_CTX_set_max_send_fragment SSL_CTX_set_max_send_fragment #define SSL_CTX_set_mode SSL_CTX_set_mode @@ -4336,7 +4342,6 @@ struct ssl_st { #define SSL_clear_chain_certs SSL_clear_chain_certs #define SSL_clear_mode SSL_clear_mode #define SSL_clear_options SSL_clear_options -#define SSL_enable_tls_channel_id SSL_enable_tls_channel_id #define SSL_get0_certificate_types SSL_get0_certificate_types #define SSL_get0_chain_certs SSL_get0_chain_certs #define SSL_get_max_cert_list SSL_get_max_cert_list @@ -4344,14 +4349,12 @@ struct ssl_st { #define SSL_get_options SSL_get_options #define SSL_get_secure_renegotiation_support \ SSL_get_secure_renegotiation_support -#define SSL_get_tls_channel_id SSL_get_tls_channel_id #define SSL_need_tmp_RSA SSL_need_tmp_RSA #define SSL_num_renegotiations SSL_num_renegotiations #define SSL_session_reused SSL_session_reused #define SSL_set0_chain SSL_set0_chain #define SSL_set1_chain SSL_set1_chain #define SSL_set1_curves SSL_set1_curves -#define SSL_set1_tls_channel_id SSL_set1_tls_channel_id #define SSL_set_max_cert_list SSL_set_max_cert_list #define SSL_set_max_send_fragment SSL_set_max_send_fragment #define SSL_set_mode SSL_set_mode @@ -4552,6 +4555,8 @@ BORINGSSL_MAKE_DELETER(SSL_SESSION, SSL_SESSION_free) #define SSL_R_PRE_SHARED_KEY_MUST_BE_LAST 267 #define SSL_R_OLD_SESSION_PRF_HASH_MISMATCH 268 #define SSL_R_INVALID_SCT_LIST 269 +#define SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA 270 +#define SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH 271 #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/x509.h b/src/include/openssl/x509.h index 8f2e1c3a..ffd0fbc8 100644 --- a/src/include/openssl/x509.h +++ b/src/include/openssl/x509.h @@ -263,6 +263,7 @@ struct x509_st unsigned char sha1_hash[SHA_DIGEST_LENGTH]; X509_CERT_AUX *aux; CRYPTO_BUFFER *buf; + CRYPTO_MUTEX lock; } /* X509 */; DECLARE_STACK_OF(X509) diff --git a/src/ssl/custom_extensions.c b/src/ssl/custom_extensions.c index 46b5efb4..10fbfc8f 100644 --- a/src/ssl/custom_extensions.c +++ b/src/ssl/custom_extensions.c @@ -58,7 +58,8 @@ static int default_add_callback(SSL *ssl, unsigned extension_value, return 1; } -static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { +static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) { + SSL *const ssl = hs->ssl; STACK_OF(SSL_CUSTOM_EXTENSION) *stack = ssl->ctx->client_custom_extensions; if (ssl->server) { stack = ssl->ctx->server_custom_extensions; @@ -72,7 +73,7 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i); if (ssl->server && - !(ssl->s3->hs->custom_extensions.received & (1u << i))) { + !(hs->custom_extensions.received & (1u << i))) { /* Servers cannot echo extensions that the client didn't send. */ continue; } @@ -102,8 +103,8 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { } if (!ssl->server) { - assert((ssl->s3->hs->custom_extensions.sent & (1u << i)) == 0); - ssl->s3->hs->custom_extensions.sent |= (1u << i); + assert((hs->custom_extensions.sent & (1u << i)) == 0); + hs->custom_extensions.sent |= (1u << i); } break; @@ -121,12 +122,13 @@ static int custom_ext_add_hello(SSL *ssl, CBB *extensions) { return 1; } -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); +int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions) { + return custom_ext_add_hello(hs, extensions); } -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { +int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension) { + SSL *const ssl = hs->ssl; unsigned index; const SSL_CUSTOM_EXTENSION *ext = custom_ext_find(ssl->ctx->client_custom_extensions, &index, value); @@ -134,7 +136,7 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, if (/* Unknown extensions are not allowed in a ServerHello. */ ext == NULL || /* Also, if we didn't send the extension, that's also unacceptable. */ - !(ssl->s3->hs->custom_extensions.sent & (1u << index))) { + !(hs->custom_extensions.sent & (1u << index))) { OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)value); *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; @@ -152,8 +154,9 @@ int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, return 1; } -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension) { +int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension) { + SSL *const ssl = hs->ssl; unsigned index; const SSL_CUSTOM_EXTENSION *ext = custom_ext_find(ssl->ctx->server_custom_extensions, &index, value); @@ -162,8 +165,8 @@ int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, return 1; } - assert((ssl->s3->hs->custom_extensions.received & (1u << index)) == 0); - ssl->s3->hs->custom_extensions.received |= (1u << index); + assert((hs->custom_extensions.received & (1u << index)) == 0); + hs->custom_extensions.received |= (1u << index); if (ext->parse_callback && !ext->parse_callback(ssl, value, CBS_data(extension), CBS_len(extension), @@ -176,8 +179,8 @@ int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, return 1; } -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions) { - return custom_ext_add_hello(ssl, extensions); +int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions) { + return custom_ext_add_hello(hs, extensions); } /* MAX_NUM_CUSTOM_EXTENSIONS is the maximum number of custom extensions that diff --git a/src/ssl/d1_lib.c b/src/ssl/d1_lib.c index a63b8c9b..cafb4c26 100644 --- a/src/ssl/d1_lib.c +++ b/src/ssl/d1_lib.c @@ -113,10 +113,6 @@ void dtls1_free(SSL *ssl) { ssl->d1 = NULL; } -int dtls1_supports_cipher(const SSL_CIPHER *cipher) { - return cipher->algorithm_enc != SSL_eNULL; -} - void DTLSv1_set_initial_timeout_duration(SSL *ssl, unsigned int duration_ms) { ssl->initial_timeout_duration_ms = duration_ms; } @@ -260,11 +256,3 @@ int DTLSv1_handle_timeout(SSL *ssl) { dtls1_start_timer(ssl); return dtls1_retransmit_outgoing_messages(ssl); } - -void dtls1_expect_flight(SSL *ssl) { - dtls1_start_timer(ssl); -} - -void dtls1_received_flight(SSL *ssl) { - dtls1_stop_timer(ssl); -} diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c index 8e92cc9f..89b5491e 100644 --- a/src/ssl/dtls_method.c +++ b/src/ssl/dtls_method.c @@ -94,6 +94,14 @@ static uint16_t dtls1_version_to_wire(uint16_t version) { return 0; } +static int dtls1_supports_cipher(const SSL_CIPHER *cipher) { + return cipher->algorithm_enc != SSL_eNULL; +} + +static void dtls1_expect_flight(SSL *ssl) { dtls1_start_timer(ssl); } + +static void dtls1_received_flight(SSL *ssl) { dtls1_stop_timer(ssl); } + static int dtls1_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { /* Cipher changes are illegal when there are buffered incoming messages. */ if (dtls_has_incoming_messages(ssl)) { diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c index 70d8d96d..4a58af90 100644 --- a/src/ssl/handshake_client.c +++ b/src/ssl/handshake_client.c @@ -170,23 +170,24 @@ #include "internal.h" -static int ssl3_send_client_hello(SSL *ssl); -static int dtls1_get_hello_verify(SSL *ssl); -static int ssl3_get_server_hello(SSL *ssl); -static int ssl3_get_server_certificate(SSL *ssl); -static int ssl3_get_cert_status(SSL *ssl); -static int ssl3_verify_server_cert(SSL *ssl); -static int ssl3_get_server_key_exchange(SSL *ssl); -static int ssl3_get_certificate_request(SSL *ssl); -static int ssl3_get_server_hello_done(SSL *ssl); -static int ssl3_send_client_certificate(SSL *ssl); -static int ssl3_send_client_key_exchange(SSL *ssl); -static int ssl3_send_cert_verify(SSL *ssl); -static int ssl3_send_next_proto(SSL *ssl); -static int ssl3_send_channel_id(SSL *ssl); -static int ssl3_get_new_session_ticket(SSL *ssl); - -int ssl3_connect(SSL *ssl) { +static int ssl3_send_client_hello(SSL_HANDSHAKE *hs); +static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs); +static int ssl3_get_server_hello(SSL_HANDSHAKE *hs); +static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs); +static int ssl3_get_cert_status(SSL_HANDSHAKE *hs); +static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs); +static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs); +static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs); +static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs); +static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs); +static int ssl3_send_next_proto(SSL_HANDSHAKE *hs); +static int ssl3_send_channel_id(SSL_HANDSHAKE *hs); +static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs); + +int ssl3_connect(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = -1; int state, skip = 0; @@ -205,12 +206,6 @@ int ssl3_connect(SSL *ssl) { case SSL_ST_CONNECT: ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); - ssl->s3->hs = ssl_handshake_new(tls13_client_handshake); - if (ssl->s3->hs == NULL) { - ret = -1; - goto end; - } - if (!ssl_init_wbio_buffer(ssl)) { ret = -1; goto end; @@ -221,7 +216,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_CLNT_HELLO_A: case SSL3_ST_CW_CLNT_HELLO_B: - ret = ssl3_send_client_hello(ssl); + ret = ssl3_send_client_hello(hs); if (ret <= 0) { goto end; } @@ -236,7 +231,7 @@ int ssl3_connect(SSL *ssl) { case DTLS1_ST_CR_HELLO_VERIFY_REQUEST_A: assert(SSL_is_dtls(ssl)); - ret = dtls1_get_hello_verify(ssl); + ret = dtls1_get_hello_verify(hs); if (ret <= 0) { goto end; } @@ -249,7 +244,7 @@ int ssl3_connect(SSL *ssl) { break; case SSL3_ST_CR_SRVR_HELLO_A: - ret = ssl3_get_server_hello(ssl); + ret = ssl3_get_server_hello(hs); if (ssl->state == SSL_ST_TLS13) { break; } @@ -266,7 +261,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CR_CERT_A: if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ret = ssl3_get_server_certificate(ssl); + ret = ssl3_get_server_certificate(hs); if (ret <= 0) { goto end; } @@ -277,8 +272,8 @@ int ssl3_connect(SSL *ssl) { break; case SSL3_ST_CR_CERT_STATUS_A: - if (ssl->s3->hs->certificate_status_expected) { - ret = ssl3_get_cert_status(ssl); + if (hs->certificate_status_expected) { + ret = ssl3_get_cert_status(hs); if (ret <= 0) { goto end; } @@ -290,7 +285,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_VERIFY_SERVER_CERT: if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ret = ssl3_verify_server_cert(ssl); + ret = ssl3_verify_server_cert(hs); if (ret <= 0) { goto end; } @@ -301,7 +296,7 @@ int ssl3_connect(SSL *ssl) { break; case SSL3_ST_CR_KEY_EXCH_A: - ret = ssl3_get_server_key_exchange(ssl); + ret = ssl3_get_server_key_exchange(hs); if (ret <= 0) { goto end; } @@ -310,7 +305,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CR_CERT_REQ_A: if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ret = ssl3_get_certificate_request(ssl); + ret = ssl3_get_certificate_request(hs); if (ret <= 0) { goto end; } @@ -321,7 +316,7 @@ int ssl3_connect(SSL *ssl) { break; case SSL3_ST_CR_SRVR_DONE_A: - ret = ssl3_get_server_hello_done(ssl); + ret = ssl3_get_server_hello_done(hs); if (ret <= 0) { goto end; } @@ -332,8 +327,8 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_CERT_A: case SSL3_ST_CW_CERT_B: case SSL3_ST_CW_CERT_C: - if (ssl->s3->hs->cert_request) { - ret = ssl3_send_client_certificate(ssl); + if (hs->cert_request) { + ret = ssl3_send_client_certificate(hs); if (ret <= 0) { goto end; } @@ -345,7 +340,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_KEY_EXCH_A: case SSL3_ST_CW_KEY_EXCH_B: - ret = ssl3_send_client_key_exchange(ssl); + ret = ssl3_send_client_key_exchange(hs); if (ret <= 0) { goto end; } @@ -355,8 +350,8 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_CERT_VRFY_A: case SSL3_ST_CW_CERT_VRFY_B: case SSL3_ST_CW_CERT_VRFY_C: - if (ssl->s3->hs->cert_request) { - ret = ssl3_send_cert_verify(ssl); + if (hs->cert_request) { + ret = ssl3_send_cert_verify(hs); if (ret <= 0) { goto end; } @@ -374,7 +369,7 @@ int ssl3_connect(SSL *ssl) { ssl->state = SSL3_ST_CW_NEXT_PROTO_A; - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_WRITE)) { ret = -1; goto end; } @@ -383,8 +378,8 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_NEXT_PROTO_A: case SSL3_ST_CW_NEXT_PROTO_B: - if (ssl->s3->hs->next_proto_neg_seen) { - ret = ssl3_send_next_proto(ssl); + if (hs->next_proto_neg_seen) { + ret = ssl3_send_next_proto(hs); if (ret <= 0) { goto end; } @@ -397,7 +392,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_CHANNEL_ID_A: case SSL3_ST_CW_CHANNEL_ID_B: if (ssl->s3->tlsext_channel_id_valid) { - ret = ssl3_send_channel_id(ssl); + ret = ssl3_send_channel_id(hs); if (ret <= 0) { goto end; } @@ -409,7 +404,7 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_CW_FINISHED_A: case SSL3_ST_CW_FINISHED_B: - ret = ssl3_send_finished(ssl, SSL3_ST_CW_FINISHED_A, + ret = ssl3_send_finished(hs, SSL3_ST_CW_FINISHED_A, SSL3_ST_CW_FINISHED_B); if (ret <= 0) { goto end; @@ -441,15 +436,15 @@ int ssl3_connect(SSL *ssl) { case SSL3_ST_FALSE_START: ssl->state = SSL3_ST_CR_SESSION_TICKET_A; - ssl->s3->hs->in_false_start = 1; + hs->in_false_start = 1; ssl_free_wbio_buffer(ssl); ret = 1; goto end; case SSL3_ST_CR_SESSION_TICKET_A: - if (ssl->s3->hs->ticket_expected) { - ret = ssl3_get_new_session_ticket(ssl); + if (hs->ticket_expected) { + ret = ssl3_get_new_session_ticket(hs); if (ret <= 0) { goto end; } @@ -465,7 +460,7 @@ int ssl3_connect(SSL *ssl) { goto end; } - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_CLIENT_READ)) { + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_CLIENT_READ)) { ret = -1; goto end; } @@ -473,7 +468,7 @@ int ssl3_connect(SSL *ssl) { break; case SSL3_ST_CR_FINISHED_A: - ret = ssl3_get_finished(ssl); + ret = ssl3_get_finished(hs); if (ret <= 0) { goto end; } @@ -499,7 +494,7 @@ int ssl3_connect(SSL *ssl) { break; case SSL_ST_TLS13: - ret = tls13_handshake(ssl); + ret = tls13_handshake(hs); if (ret <= 0) { goto end; } @@ -540,12 +535,9 @@ int ssl3_connect(SSL *ssl) { ssl->s3->initial_handshake_complete = 1; if (is_initial_handshake) { /* Renegotiations do not participate in session resumption. */ - ssl_update_cache(ssl, SSL_SESS_CACHE_CLIENT); + ssl_update_cache(hs, SSL_SESS_CACHE_CLIENT); } - ssl_handshake_free(ssl->s3->hs); - ssl->s3->hs = NULL; - ret = 1; ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1); goto end; @@ -650,7 +642,7 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, /* For SSLv3, the SCSV is added. Otherwise the renegotiation extension is * added. */ - if (ssl->client_version == SSL3_VERSION && + if (max_version == SSL3_VERSION && !ssl->s3->initial_handshake_complete) { if (!CBB_add_u16(&child, SSL3_CK_SCSV & 0xffff)) { return 0; @@ -666,7 +658,8 @@ static int ssl_write_client_cipher_list(SSL *ssl, CBB *out, return CBB_flush(out); } -int ssl_write_client_hello(SSL *ssl) { +int ssl_write_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -682,7 +675,7 @@ int ssl_write_client_hello(SSL *ssl) { !ssl->s3->initial_handshake_complete; CBB child; - if (!CBB_add_u16(&body, ssl->client_version) || + if (!CBB_add_u16(&body, hs->client_version) || !CBB_add_bytes(&body, ssl->s3->client_random, SSL3_RANDOM_SIZE) || !CBB_add_u8_length_prefixed(&body, &child) || (has_session && @@ -703,7 +696,7 @@ int ssl_write_client_hello(SSL *ssl) { if (!ssl_write_client_cipher_list(ssl, &body, min_version, max_version) || !CBB_add_u8(&body, 1 /* one compression method */) || !CBB_add_u8(&body, 0 /* null compression */) || - !ssl_add_clienthello_tlsext(ssl, &body, header_len + CBB_len(&body))) { + !ssl_add_clienthello_tlsext(hs, &body, header_len + CBB_len(&body))) { goto err; } @@ -715,7 +708,7 @@ int ssl_write_client_hello(SSL *ssl) { /* Now that the length prefixes have been computed, fill in the placeholder * PSK binder. */ - if (ssl->s3->hs->needs_psk_binder && + if (hs->needs_psk_binder && !tls13_write_psk_binder(ssl, msg, len)) { OPENSSL_free(msg); goto err; @@ -728,7 +721,8 @@ int ssl_write_client_hello(SSL *ssl) { return 0; } -static int ssl3_send_client_hello(SSL *ssl) { +static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_CLNT_HELLO_B) { return ssl->method->write_message(ssl); } @@ -745,18 +739,18 @@ static int ssl3_send_client_hello(SSL *ssl) { return -1; } + uint16_t max_wire_version = ssl->method->version_to_wire(max_version); assert(ssl->state == SSL3_ST_CW_CLNT_HELLO_A); if (!ssl->s3->have_version) { - ssl->version = ssl->method->version_to_wire(max_version); - /* Only set |ssl->client_version| on the initial handshake. Renegotiations, - * although locked to a version, reuse the value. When using the plain RSA - * 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); - } + ssl->version = max_wire_version; + } + + /* Always advertise the ClientHello version from the original maximum version, + * even on renegotiation. The static RSA key exchange uses this field, and + * some servers fail when it changes across handshakes. */ + hs->client_version = max_wire_version; + if (max_version >= TLS1_3_VERSION) { + hs->client_version = ssl->method->version_to_wire(TLS1_2_VERSION); } /* If the configured session has expired or was created at a disabled @@ -781,7 +775,7 @@ static int ssl3_send_client_hello(SSL *ssl) { return -1; } - if (!ssl_write_client_hello(ssl)) { + if (!ssl_write_client_hello(hs)) { return -1; } @@ -789,7 +783,8 @@ static int ssl3_send_client_hello(SSL *ssl) { return ssl->method->write_message(ssl); } -static int dtls1_get_hello_verify(SSL *ssl) { +static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int al; CBS hello_verify_request, cookie; uint16_t server_version; @@ -831,7 +826,8 @@ f_err: return -1; } -static int ssl3_get_server_hello(SSL *ssl) { +static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; CERT *ct = ssl->cert; int al = SSL_AD_INTERNAL_ERROR; CBS server_hello, server_random, session_id; @@ -894,10 +890,11 @@ static int ssl3_get_server_hello(SSL *ssl) { if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { ssl->state = SSL_ST_TLS13; + hs->do_tls13_handshake = tls13_client_handshake; return 1; } - ssl_clear_tls13_state(ssl); + ssl_clear_tls13_state(hs); if (ssl->s3->tmp.message_type != SSL3_MT_SERVER_HELLO) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); @@ -930,7 +927,7 @@ static int ssl3_get_server_hello(SSL *ssl) { /* The session wasn't resumed. Create a fresh SSL_SESSION to * fill out. */ ssl_set_session(ssl, NULL); - if (!ssl_get_new_session(ssl, 0 /* client */)) { + if (!ssl_get_new_session(hs, 0 /* client */)) { goto f_err; } /* Note: session_id could be empty. */ @@ -1001,7 +998,7 @@ static int ssl3_get_server_hello(SSL *ssl) { } /* TLS extensions */ - if (!ssl_parse_serverhello_tlsext(ssl, &server_hello)) { + if (!ssl_parse_serverhello_tlsext(hs, &server_hello)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); goto err; } @@ -1034,7 +1031,8 @@ err: return -1; } -static int ssl3_get_server_certificate(SSL *ssl) { +static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CERTIFICATE, ssl_hash_message); if (ret <= 0) { @@ -1078,7 +1076,8 @@ err: return -1; } -static int ssl3_get_cert_status(SSL *ssl) { +static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int al; CBS certificate_status, ocsp_response; uint8_t status_type; @@ -1119,7 +1118,8 @@ f_err: return -1; } -static int ssl3_verify_server_cert(SSL *ssl) { +static int ssl3_verify_server_cert(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!ssl_verify_cert_chain(ssl, &ssl->s3->new_session->verify_result, ssl->s3->new_session->x509_chain)) { return -1; @@ -1128,7 +1128,8 @@ static int ssl3_verify_server_cert(SSL *ssl) { return 1; } -static int ssl3_get_server_key_exchange(SSL *ssl) { +static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int al; EVP_PKEY *pkey = NULL; DH *dh = NULL; @@ -1191,7 +1192,7 @@ static int ssl3_get_server_key_exchange(SSL *ssl) { * empty hint. Having different capabilities is odd, so we interpret empty * and missing as identical. */ if (CBS_len(&psk_identity_hint) != 0 && - !CBS_strdup(&psk_identity_hint, &ssl->s3->hs->peer_psk_identity_hint)) { + !CBS_strdup(&psk_identity_hint, &hs->peer_psk_identity_hint)) { al = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto f_err; @@ -1234,11 +1235,11 @@ static int ssl3_get_server_key_exchange(SSL *ssl) { goto err; } - SSL_ECDH_CTX_init_for_dhe(&ssl->s3->hs->ecdh_ctx, dh); + SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh); dh = NULL; /* Save the peer public key for later. */ - if (!CBS_stow(&dh_Ys, &ssl->s3->hs->peer_key, &ssl->s3->hs->peer_key_len)) { + if (!CBS_stow(&dh_Ys, &hs->peer_key, &hs->peer_key_len)) { goto err; } } else if (alg_k & SSL_kECDHE) { @@ -1264,12 +1265,12 @@ static int ssl3_get_server_key_exchange(SSL *ssl) { } /* Initialize ECDH and save the peer public key for later. */ - if (!SSL_ECDH_CTX_init(&ssl->s3->hs->ecdh_ctx, group_id) || - !CBS_stow(&point, &ssl->s3->hs->peer_key, &ssl->s3->hs->peer_key_len)) { + if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + !CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) { goto err; } } else if (alg_k & SSL_kCECPQ1) { - SSL_ECDH_CTX_init_for_cecpq1(&ssl->s3->hs->ecdh_ctx); + SSL_ECDH_CTX_init_for_cecpq1(&hs->ecdh_ctx); CBS key; if (!CBS_get_u16_length_prefixed(&server_key_exchange, &key)) { al = SSL_AD_DECODE_ERROR; @@ -1277,7 +1278,7 @@ static int ssl3_get_server_key_exchange(SSL *ssl) { goto f_err; } - if (!CBS_stow(&key, &ssl->s3->hs->peer_key, &ssl->s3->hs->peer_key_len)) { + if (!CBS_stow(&key, &hs->peer_key, &hs->peer_key_len)) { goto err; } } else if (!(alg_k & SSL_kPSK)) { @@ -1382,7 +1383,8 @@ err: return -1; } -static int ssl3_get_certificate_request(SSL *ssl) { +static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int msg_ret = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message); if (msg_ret <= 0) { return msg_ret; @@ -1413,8 +1415,8 @@ static int ssl3_get_certificate_request(SSL *ssl) { return -1; } - if (!CBS_stow(&certificate_types, &ssl->s3->hs->certificate_types, - &ssl->s3->hs->num_certificate_types)) { + if (!CBS_stow(&certificate_types, &hs->certificate_types, + &hs->num_certificate_types)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return -1; } @@ -1422,7 +1424,7 @@ static int ssl3_get_certificate_request(SSL *ssl) { if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { CBS supported_signature_algorithms; if (!CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return -1; @@ -1443,13 +1445,14 @@ static int ssl3_get_certificate_request(SSL *ssl) { return -1; } - ssl->s3->hs->cert_request = 1; - sk_X509_NAME_pop_free(ssl->s3->hs->ca_names, X509_NAME_free); - ssl->s3->hs->ca_names = ca_sk; + hs->cert_request = 1; + sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + hs->ca_names = ca_sk; return 1; } -static int ssl3_get_server_hello_done(SSL *ssl) { +static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = ssl->method->ssl_get_message(ssl, SSL3_MT_SERVER_HELLO_DONE, ssl_hash_message); if (ret <= 0) { @@ -1466,7 +1469,8 @@ static int ssl3_get_server_hello_done(SSL *ssl) { return 1; } -static int ssl3_send_client_certificate(SSL *ssl) { +static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_CERT_A) { /* Call cert_cb to update the certificate. */ if (ssl->cert->cert_cb) { @@ -1496,7 +1500,7 @@ static int ssl3_send_client_certificate(SSL *ssl) { } if (!ssl_has_certificate(ssl)) { - ssl->s3->hs->cert_request = 0; + hs->cert_request = 0; /* Without a client certificate, the handshake buffer may be released. */ ssl3_free_handshake_buffer(ssl); @@ -1520,7 +1524,8 @@ static int ssl3_send_client_certificate(SSL *ssl) { OPENSSL_COMPILE_ASSERT(sizeof(size_t) >= sizeof(unsigned), SIZE_T_IS_SMALLER_THAN_UNSIGNED); -static int ssl3_send_client_key_exchange(SSL *ssl) { +static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_KEY_EXCH_B) { return ssl->method->write_message(ssl); } @@ -1548,9 +1553,9 @@ static int ssl3_send_client_key_exchange(SSL *ssl) { char identity[PSK_MAX_IDENTITY_LEN + 1]; memset(identity, 0, sizeof(identity)); - psk_len = ssl->psk_client_callback( - ssl, ssl->s3->hs->peer_psk_identity_hint, identity, sizeof(identity), - psk, sizeof(psk)); + psk_len = + ssl->psk_client_callback(ssl, hs->peer_psk_identity_hint, identity, + sizeof(identity), psk, sizeof(psk)); if (psk_len == 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -1598,8 +1603,8 @@ static int ssl3_send_client_key_exchange(SSL *ssl) { EVP_PKEY_free(pkey); - pms[0] = ssl->client_version >> 8; - pms[1] = ssl->client_version & 0xff; + pms[0] = hs->client_version >> 8; + pms[1] = hs->client_version & 0xff; if (!RAND_bytes(&pms[2], SSL_MAX_MASTER_KEY_LENGTH - 2)) { goto err; } @@ -1627,15 +1632,14 @@ static int ssl3_send_client_key_exchange(SSL *ssl) { } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) { /* Generate a keypair and serialize the public half. */ CBB child; - if (!SSL_ECDH_CTX_add_key(&ssl->s3->hs->ecdh_ctx, &body, &child)) { + if (!SSL_ECDH_CTX_add_key(&hs->ecdh_ctx, &body, &child)) { goto err; } /* Compute the premaster. */ uint8_t alert; - if (!SSL_ECDH_CTX_accept(&ssl->s3->hs->ecdh_ctx, &child, &pms, &pms_len, - &alert, ssl->s3->hs->peer_key, - ssl->s3->hs->peer_key_len)) { + if (!SSL_ECDH_CTX_accept(&hs->ecdh_ctx, &child, &pms, &pms_len, &alert, + hs->peer_key, hs->peer_key_len)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); goto err; } @@ -1644,10 +1648,10 @@ static int ssl3_send_client_key_exchange(SSL *ssl) { } /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&ssl->s3->hs->ecdh_ctx); - OPENSSL_free(ssl->s3->hs->peer_key); - ssl->s3->hs->peer_key = NULL; - ssl->s3->hs->peer_key_len = 0; + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + OPENSSL_free(hs->peer_key); + hs->peer_key = NULL; + hs->peer_key_len = 0; } else if (alg_k & SSL_kPSK) { /* For plain PSK, other_secret is a block of 0s with the same length as * the pre-shared key. */ @@ -1717,7 +1721,8 @@ err: return -1; } -static int ssl3_send_cert_verify(SSL *ssl) { +static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_CERT_VRFY_C) { return ssl->method->write_message(ssl); } @@ -1731,7 +1736,7 @@ static int ssl3_send_cert_verify(SSL *ssl) { } uint16_t signature_algorithm; - if (!tls1_choose_signature_algorithm(ssl, &signature_algorithm)) { + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { goto err; } if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { @@ -1819,7 +1824,8 @@ err: return -1; } -static int ssl3_send_next_proto(SSL *ssl) { +static int ssl3_send_next_proto(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_NEXT_PROTO_B) { return ssl->method->write_message(ssl); } @@ -1846,7 +1852,8 @@ static int ssl3_send_next_proto(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_send_channel_id(SSL *ssl) { +static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_CW_CHANNEL_ID_B) { return ssl->method->write_message(ssl); } @@ -1875,7 +1882,8 @@ static int ssl3_send_channel_id(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_get_new_session_ticket(SSL *ssl) { +static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = ssl->method->ssl_get_message(ssl, SSL3_MT_NEW_SESSION_TICKET, ssl_hash_message); if (ret <= 0) { @@ -1897,7 +1905,7 @@ static int ssl3_get_new_session_ticket(SSL *ssl) { /* RFC 5077 allows a server to change its mind and send no ticket after * negotiating the extension. The value of |ticket_expected| is checked in * |ssl_update_cache| so is cleared here to avoid an unnecessary update. */ - ssl->s3->hs->ticket_expected = 0; + hs->ticket_expected = 0; return 1; } diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c index 3b66ab7d..c1140747 100644 --- a/src/ssl/handshake_server.c +++ b/src/ssl/handshake_server.c @@ -171,21 +171,22 @@ #include "../crypto/internal.h" -static int ssl3_get_client_hello(SSL *ssl); -static int ssl3_send_server_hello(SSL *ssl); -static int ssl3_send_server_certificate(SSL *ssl); -static int ssl3_send_certificate_status(SSL *ssl); -static int ssl3_send_server_key_exchange(SSL *ssl); -static int ssl3_send_certificate_request(SSL *ssl); -static int ssl3_send_server_hello_done(SSL *ssl); -static int ssl3_get_client_certificate(SSL *ssl); -static int ssl3_get_client_key_exchange(SSL *ssl); -static int ssl3_get_cert_verify(SSL *ssl); -static int ssl3_get_next_proto(SSL *ssl); -static int ssl3_get_channel_id(SSL *ssl); -static int ssl3_send_new_session_ticket(SSL *ssl); - -int ssl3_accept(SSL *ssl) { +static int ssl3_get_client_hello(SSL_HANDSHAKE *hs); +static int ssl3_send_server_hello(SSL_HANDSHAKE *hs); +static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs); +static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs); +static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs); +static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs); +static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs); +static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs); +static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs); +static int ssl3_get_next_proto(SSL_HANDSHAKE *hs); +static int ssl3_get_channel_id(SSL_HANDSHAKE *hs); +static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs); + +int ssl3_accept(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint32_t alg_a; int ret = -1; int state, skip = 0; @@ -205,12 +206,6 @@ int ssl3_accept(SSL *ssl) { case SSL_ST_ACCEPT: ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); - ssl->s3->hs = ssl_handshake_new(tls13_server_handshake); - if (ssl->s3->hs == NULL) { - ret = -1; - goto end; - } - /* Enable a write buffer. This groups handshake messages within a flight * into a single write. */ if (!ssl_init_wbio_buffer(ssl)) { @@ -232,7 +227,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SR_CLNT_HELLO_C: case SSL3_ST_SR_CLNT_HELLO_D: case SSL3_ST_SR_CLNT_HELLO_E: - ret = ssl3_get_client_hello(ssl); + ret = ssl3_get_client_hello(hs); if (ssl->state == SSL_ST_TLS13) { break; } @@ -245,7 +240,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_SRVR_HELLO_A: case SSL3_ST_SW_SRVR_HELLO_B: - ret = ssl3_send_server_hello(ssl); + ret = ssl3_send_server_hello(hs); if (ret <= 0) { goto end; } @@ -259,7 +254,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_CERT_A: case SSL3_ST_SW_CERT_B: if (ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ret = ssl3_send_server_certificate(ssl); + ret = ssl3_send_server_certificate(hs); if (ret <= 0) { goto end; } @@ -271,8 +266,8 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_CERT_STATUS_A: case SSL3_ST_SW_CERT_STATUS_B: - if (ssl->s3->hs->certificate_status_expected) { - ret = ssl3_send_certificate_status(ssl); + if (hs->certificate_status_expected) { + ret = ssl3_send_certificate_status(hs); if (ret <= 0) { goto end; } @@ -290,7 +285,7 @@ int ssl3_accept(SSL *ssl) { /* PSK ciphers send ServerKeyExchange if there is an identity hint. */ if (ssl_cipher_requires_server_key_exchange(ssl->s3->tmp.new_cipher) || ((alg_a & SSL_aPSK) && ssl->psk_identity_hint)) { - ret = ssl3_send_server_key_exchange(ssl); + ret = ssl3_send_server_key_exchange(hs); if (ret <= 0) { goto end; } @@ -303,8 +298,8 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_CERT_REQ_A: case SSL3_ST_SW_CERT_REQ_B: - if (ssl->s3->hs->cert_request) { - ret = ssl3_send_certificate_request(ssl); + if (hs->cert_request) { + ret = ssl3_send_certificate_request(hs); if (ret <= 0) { goto end; } @@ -316,7 +311,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_SRVR_DONE_A: case SSL3_ST_SW_SRVR_DONE_B: - ret = ssl3_send_server_hello_done(ssl); + ret = ssl3_send_server_hello_done(hs); if (ret <= 0) { goto end; } @@ -325,8 +320,8 @@ int ssl3_accept(SSL *ssl) { break; case SSL3_ST_SR_CERT_A: - if (ssl->s3->hs->cert_request) { - ret = ssl3_get_client_certificate(ssl); + if (hs->cert_request) { + ret = ssl3_get_client_certificate(hs); if (ret <= 0) { goto end; } @@ -336,7 +331,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SR_KEY_EXCH_A: case SSL3_ST_SR_KEY_EXCH_B: - ret = ssl3_get_client_key_exchange(ssl); + ret = ssl3_get_client_key_exchange(hs); if (ret <= 0) { goto end; } @@ -344,7 +339,7 @@ int ssl3_accept(SSL *ssl) { break; case SSL3_ST_SR_CERT_VRFY_A: - ret = ssl3_get_cert_verify(ssl); + ret = ssl3_get_cert_verify(hs); if (ret <= 0) { goto end; } @@ -358,7 +353,7 @@ int ssl3_accept(SSL *ssl) { goto end; } - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_READ)) { + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_READ)) { ret = -1; goto end; } @@ -367,8 +362,8 @@ int ssl3_accept(SSL *ssl) { break; case SSL3_ST_SR_NEXT_PROTO_A: - if (ssl->s3->hs->next_proto_neg_seen) { - ret = ssl3_get_next_proto(ssl); + if (hs->next_proto_neg_seen) { + ret = ssl3_get_next_proto(hs); if (ret <= 0) { goto end; } @@ -380,7 +375,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SR_CHANNEL_ID_A: if (ssl->s3->tlsext_channel_id_valid) { - ret = ssl3_get_channel_id(ssl); + ret = ssl3_get_channel_id(hs); if (ret <= 0) { goto end; } @@ -391,7 +386,7 @@ int ssl3_accept(SSL *ssl) { break; case SSL3_ST_SR_FINISHED_A: - ret = ssl3_get_finished(ssl); + ret = ssl3_get_finished(hs); if (ret <= 0) { goto end; } @@ -416,8 +411,8 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_SESSION_TICKET_A: case SSL3_ST_SW_SESSION_TICKET_B: - if (ssl->s3->hs->ticket_expected) { - ret = ssl3_send_new_session_ticket(ssl); + if (hs->ticket_expected) { + ret = ssl3_send_new_session_ticket(hs); if (ret <= 0) { goto end; } @@ -434,7 +429,7 @@ int ssl3_accept(SSL *ssl) { } ssl->state = SSL3_ST_SW_FINISHED_A; - if (!tls1_change_cipher_state(ssl, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { + if (!tls1_change_cipher_state(hs, SSL3_CHANGE_CIPHER_SERVER_WRITE)) { ret = -1; goto end; } @@ -442,7 +437,7 @@ int ssl3_accept(SSL *ssl) { case SSL3_ST_SW_FINISHED_A: case SSL3_ST_SW_FINISHED_B: - ret = ssl3_send_finished(ssl, SSL3_ST_SW_FINISHED_A, + ret = ssl3_send_finished(hs, SSL3_ST_SW_FINISHED_A, SSL3_ST_SW_FINISHED_B); if (ret <= 0) { goto end; @@ -469,7 +464,7 @@ int ssl3_accept(SSL *ssl) { break; case SSL_ST_TLS13: - ret = tls13_handshake(ssl); + ret = tls13_handshake(hs); if (ret <= 0) { goto end; } @@ -503,10 +498,7 @@ int ssl3_accept(SSL *ssl) { ssl_free_wbio_buffer(ssl); ssl->s3->initial_handshake_complete = 1; - ssl_update_cache(ssl, SSL_SESS_CACHE_SERVER); - - ssl_handshake_free(ssl->s3->hs); - ssl->s3->hs = NULL; + ssl_update_cache(hs, SSL_SESS_CACHE_SERVER); ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_DONE, 1); ret = 1; @@ -532,8 +524,8 @@ end: return ret; } -int ssl_client_cipher_list_contains_cipher( - const struct ssl_early_callback_ctx *client_hello, uint16_t id) { +int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, + uint16_t id) { CBS cipher_suites; CBS_init(&cipher_suites, client_hello->cipher_suites, client_hello->cipher_suites_len); @@ -552,9 +544,9 @@ int ssl_client_cipher_list_contains_cipher( return 0; } -static int negotiate_version( - SSL *ssl, uint8_t *out_alert, - const struct ssl_early_callback_ctx *client_hello) { +static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { *out_alert = SSL_AD_PROTOCOL_VERSION; @@ -564,8 +556,8 @@ static int negotiate_version( uint16_t version = 0; /* 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)) { + if (ssl_client_hello_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 || @@ -644,7 +636,7 @@ static int negotiate_version( return 0; } - ssl->client_version = client_hello->version; + hs->client_version = client_hello->version; ssl->version = ssl->method->version_to_wire(version); ssl->s3->enc_method = ssl3_get_enc_method(version); assert(ssl->s3->enc_method != NULL); @@ -661,7 +653,171 @@ unsupported_protocol: return 0; } -static int ssl3_get_client_hello(SSL *ssl) { +static STACK_OF(SSL_CIPHER) * + ssl_parse_client_cipher_list(const SSL_CLIENT_HELLO *client_hello) { + CBS cipher_suites; + CBS_init(&cipher_suites, client_hello->cipher_suites, + client_hello->cipher_suites_len); + + STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null(); + if (sk == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + + while (CBS_len(&cipher_suites) > 0) { + uint16_t cipher_suite; + + if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + goto err; + } + + const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite); + if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + return sk; + +err: + sk_SSL_CIPHER_free(sk); + return NULL; +} + +/* ssl_get_compatible_server_ciphers determines the key exchange and + * authentication cipher suite masks compatible with the server configuration + * and current ClientHello parameters of |hs|. It sets |*out_mask_k| to the key + * exchange mask and |*out_mask_a| to the authentication mask. */ +static void ssl_get_compatible_server_ciphers(SSL_HANDSHAKE *hs, + uint32_t *out_mask_k, + uint32_t *out_mask_a) { + SSL *const ssl = hs->ssl; + 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; + + if (ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl)) { + int type = ssl_private_key_type(ssl); + if (type == NID_rsaEncryption) { + mask_k |= SSL_kRSA; + mask_a |= SSL_aRSA; + } else if (ssl_is_ecdsa_key_type(type)) { + mask_a |= SSL_aECDSA; + } + } + + if (ssl->cert->dh_tmp != NULL || ssl->cert->dh_tmp_cb != NULL) { + mask_k |= SSL_kDHE; + } + + /* Check for a shared group to consider ECDHE ciphers. */ + uint16_t unused; + if (tls1_get_shared_group(hs, &unused)) { + mask_k |= SSL_kECDHE; + } + + /* CECPQ1 ciphers are always acceptable if supported by both sides. */ + mask_k |= SSL_kCECPQ1; + + /* PSK requires a server callback. */ + if (ssl->psk_server_callback != NULL) { + mask_k |= SSL_kPSK; + mask_a |= SSL_aPSK; + } + + *out_mask_k = mask_k; + *out_mask_a = mask_a; +} + +static const SSL_CIPHER *ssl3_choose_cipher( + SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello, + const struct ssl_cipher_preference_list_st *server_pref) { + SSL *const ssl = hs->ssl; + const SSL_CIPHER *c, *ret = NULL; + STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; + int ok; + size_t cipher_index; + uint32_t alg_k, alg_a, mask_k, mask_a; + /* in_group_flags will either be NULL, or will point to an array of bytes + * which indicate equal-preference groups in the |prio| stack. See the + * comment about |in_group_flags| in the |ssl_cipher_preference_list_st| + * struct. */ + const uint8_t *in_group_flags; + /* group_min contains the minimal index so far found in a group, or -1 if no + * such value exists yet. */ + int group_min = -1; + + STACK_OF(SSL_CIPHER) *clnt = ssl_parse_client_cipher_list(client_hello); + if (clnt == NULL) { + return NULL; + } + + if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { + prio = srvr; + in_group_flags = server_pref->in_group_flags; + allow = clnt; + } else { + prio = clnt; + in_group_flags = NULL; + allow = srvr; + } + + ssl_get_compatible_server_ciphers(hs, &mask_k, &mask_a); + + for (size_t i = 0; i < sk_SSL_CIPHER_num(prio); i++) { + c = sk_SSL_CIPHER_value(prio, i); + + ok = 1; + + /* Check the TLS version. */ + if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) || + SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) { + ok = 0; + } + + alg_k = c->algorithm_mkey; + alg_a = c->algorithm_auth; + + ok = ok && (alg_k & mask_k) && (alg_a & mask_a); + + if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c)) { + if (in_group_flags != NULL && in_group_flags[i] == 1) { + /* This element of |prio| is in a group. Update the minimum index found + * so far and continue looking. */ + if (group_min == -1 || (size_t)group_min > cipher_index) { + group_min = cipher_index; + } + } else { + if (group_min != -1 && (size_t)group_min < cipher_index) { + cipher_index = group_min; + } + ret = sk_SSL_CIPHER_value(allow, cipher_index); + break; + } + } + + if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) { + /* We are about to leave a group, but we found a match in it, so that's + * our answer. */ + ret = sk_SSL_CIPHER_value(allow, group_min); + break; + } + } + + sk_SSL_CIPHER_free(clnt); + return ret; +} + +static int ssl3_get_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint8_t al = SSL_AD_INTERNAL_ERROR; int ret = -1; SSL_SESSION *session = NULL; @@ -677,9 +833,9 @@ static int ssl3_get_client_hello(SSL *ssl) { ssl->state = SSL3_ST_SR_CLNT_HELLO_B; } - struct ssl_early_callback_ctx client_hello; - if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg, - ssl->init_num)) { + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { al = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); goto f_err; @@ -711,12 +867,13 @@ static int ssl3_get_client_hello(SSL *ssl) { /* Negotiate the protocol version if we have not done so yet. */ if (!ssl->s3->have_version) { - if (!negotiate_version(ssl, &al, &client_hello)) { + if (!negotiate_version(hs, &al, &client_hello)) { goto f_err; } if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { ssl->state = SSL_ST_TLS13; + hs->do_tls13_handshake = tls13_server_handshake; return 1; } } @@ -739,7 +896,7 @@ static int ssl3_get_client_hello(SSL *ssl) { } /* TLS extensions. */ - if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) { + if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); goto err; } @@ -765,7 +922,7 @@ static int ssl3_get_client_hello(SSL *ssl) { /* Negotiate the cipher suite. This must be done after |cert_cb| so the * certificate is finalized. */ ssl->s3->tmp.new_cipher = - ssl3_choose_cipher(ssl, &client_hello, ssl_get_cipher_preferences(ssl)); + ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl)); if (ssl->s3->tmp.new_cipher == NULL) { al = SSL_AD_HANDSHAKE_FAILURE; OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); @@ -812,14 +969,14 @@ static int ssl3_get_client_hello(SSL *ssl) { if (session != NULL) { /* Use the old session. */ - ssl->s3->hs->ticket_expected = renew_ticket; + hs->ticket_expected = renew_ticket; ssl->session = session; session = NULL; ssl->s3->session_reused = 1; } else { - ssl->s3->hs->ticket_expected = tickets_supported; + hs->ticket_expected = tickets_supported; ssl_set_session(ssl, NULL); - if (!ssl_get_new_session(ssl, 1 /* server */)) { + if (!ssl_get_new_session(hs, 1 /* server */)) { goto err; } @@ -841,8 +998,8 @@ static int ssl3_get_client_hello(SSL *ssl) { ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher; /* On new sessions, stash the SNI value in the session. */ - if (ssl->s3->hs->hostname != NULL) { - ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname); + if (hs->hostname != NULL) { + ssl->s3->new_session->tlsext_hostname = BUF_strdup(hs->hostname); if (ssl->s3->new_session->tlsext_hostname == NULL) { al = SSL_AD_INTERNAL_ERROR; goto f_err; @@ -850,18 +1007,18 @@ static int ssl3_get_client_hello(SSL *ssl) { } /* Determine whether to request a client certificate. */ - ssl->s3->hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); + hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); /* Only request a certificate if Channel ID isn't negotiated. */ if ((ssl->verify_mode & SSL_VERIFY_PEER_IF_NO_OBC) && ssl->s3->tlsext_channel_id_valid) { - ssl->s3->hs->cert_request = 0; + hs->cert_request = 0; } /* CertificateRequest may only be sent in certificate-based ciphers. */ if (!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ssl->s3->hs->cert_request = 0; + hs->cert_request = 0; } - if (!ssl->s3->hs->cert_request) { + if (!hs->cert_request) { /* OpenSSL returns X509_V_OK when no certificates are requested. This is * classed by them as a bug, but it's assumed by at least NGINX. */ ssl->s3->new_session->verify_result = X509_V_OK; @@ -870,7 +1027,7 @@ static int ssl3_get_client_hello(SSL *ssl) { /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was * deferred. Complete it now. */ - if (!ssl_negotiate_alpn(ssl, &al, &client_hello)) { + if (!ssl_negotiate_alpn(hs, &al, &client_hello)) { goto f_err; } @@ -880,7 +1037,7 @@ static int ssl3_get_client_hello(SSL *ssl) { } /* Release the handshake buffer if client authentication isn't required. */ - if (!ssl->s3->hs->cert_request) { + if (!hs->cert_request) { ssl3_free_handshake_buffer(ssl); } @@ -896,7 +1053,8 @@ err: return ret; } -static int ssl3_send_server_hello(SSL *ssl) { +static int ssl3_send_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_SRVR_HELLO_B) { return ssl->method->write_message(ssl); } @@ -945,7 +1103,7 @@ static int ssl3_send_server_hello(SSL *ssl) { session->session_id_length) || !CBB_add_u16(&body, ssl_cipher_get_value(ssl->s3->tmp.new_cipher)) || !CBB_add_u8(&body, 0 /* no compression */) || - !ssl_add_serverhello_tlsext(ssl, &body) || + !ssl_add_serverhello_tlsext(hs, &body) || !ssl_complete_message(ssl, &cbb)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); CBB_cleanup(&cbb); @@ -956,7 +1114,8 @@ static int ssl3_send_server_hello(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_send_server_certificate(SSL *ssl) { +static int ssl3_send_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_CERT_B) { return ssl->method->write_message(ssl); } @@ -973,7 +1132,8 @@ static int ssl3_send_server_certificate(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_send_certificate_status(SSL *ssl) { +static int ssl3_send_certificate_status(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_CERT_STATUS_B) { return ssl->method->write_message(ssl); } @@ -995,7 +1155,8 @@ static int ssl3_send_certificate_status(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_send_server_key_exchange(SSL *ssl) { +static int ssl3_send_server_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_KEY_EXCH_C) { return ssl->method->write_message(ssl); } @@ -1043,19 +1204,19 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { goto err; } - SSL_ECDH_CTX_init_for_dhe(&ssl->s3->hs->ecdh_ctx, dh); + SSL_ECDH_CTX_init_for_dhe(&hs->ecdh_ctx, dh); if (!CBB_add_u16_length_prefixed(&cbb, &child) || !BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) || !CBB_add_u16_length_prefixed(&cbb, &child) || !BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) || !CBB_add_u16_length_prefixed(&cbb, &child) || - !SSL_ECDH_CTX_offer(&ssl->s3->hs->ecdh_ctx, &child)) { + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { goto err; } } else if (alg_k & SSL_kECDHE) { /* Determine the group to use. */ uint16_t group_id; - if (!tls1_get_shared_group(ssl, &group_id)) { + if (!tls1_get_shared_group(hs, &group_id)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_TMP_ECDH_KEY); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); goto err; @@ -1063,25 +1224,24 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { ssl->s3->new_session->key_exchange_info = group_id; /* Set up ECDH, generate a key, and emit the public half. */ - if (!SSL_ECDH_CTX_init(&ssl->s3->hs->ecdh_ctx, group_id) || + if (!SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || !CBB_add_u8(&cbb, NAMED_CURVE_TYPE) || !CBB_add_u16(&cbb, group_id) || !CBB_add_u8_length_prefixed(&cbb, &child) || - !SSL_ECDH_CTX_offer(&ssl->s3->hs->ecdh_ctx, &child)) { + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { goto err; } } else if (alg_k & SSL_kCECPQ1) { - SSL_ECDH_CTX_init_for_cecpq1(&ssl->s3->hs->ecdh_ctx); + SSL_ECDH_CTX_init_for_cecpq1(&hs->ecdh_ctx); if (!CBB_add_u16_length_prefixed(&cbb, &child) || - !SSL_ECDH_CTX_offer(&ssl->s3->hs->ecdh_ctx, &child)) { + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &child)) { goto err; } } else { assert(alg_k & SSL_kPSK); } - if (!CBB_finish(&cbb, &ssl->s3->hs->server_params, - &ssl->s3->hs->server_params_len)) { + if (!CBB_finish(&cbb, &hs->server_params, &hs->server_params_len)) { goto err; } } @@ -1090,8 +1250,7 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { CBB body; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_KEY_EXCHANGE) || - !CBB_add_bytes(&body, ssl->s3->hs->server_params, - ssl->s3->hs->server_params_len)) { + !CBB_add_bytes(&body, hs->server_params, hs->server_params_len)) { goto err; } @@ -1104,7 +1263,7 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { /* Determine the signature algorithm. */ uint16_t signature_algorithm; - if (!tls1_choose_signature_algorithm(ssl, &signature_algorithm)) { + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { goto err; } if (ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { @@ -1130,11 +1289,13 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { uint8_t *transcript_data; size_t transcript_len; if (!CBB_init(&transcript, - 2*SSL3_RANDOM_SIZE + ssl->s3->hs->server_params_len) || - !CBB_add_bytes(&transcript, ssl->s3->client_random, SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, ssl->s3->server_random, SSL3_RANDOM_SIZE) || - !CBB_add_bytes(&transcript, ssl->s3->hs->server_params, - ssl->s3->hs->server_params_len) || + 2 * SSL3_RANDOM_SIZE + hs->server_params_len) || + !CBB_add_bytes(&transcript, ssl->s3->client_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, ssl->s3->server_random, + SSL3_RANDOM_SIZE) || + !CBB_add_bytes(&transcript, hs->server_params, + hs->server_params_len) || !CBB_finish(&transcript, &transcript_data, &transcript_len)) { CBB_cleanup(&transcript); OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); @@ -1170,9 +1331,9 @@ static int ssl3_send_server_key_exchange(SSL *ssl) { goto err; } - OPENSSL_free(ssl->s3->hs->server_params); - ssl->s3->hs->server_params = NULL; - ssl->s3->hs->server_params_len = 0; + OPENSSL_free(hs->server_params); + hs->server_params = NULL; + hs->server_params_len = 0; ssl->state = SSL3_ST_SW_KEY_EXCH_C; return ssl->method->write_message(ssl); @@ -1220,7 +1381,8 @@ static int add_cert_types(SSL *ssl, CBB *cbb) { return 1; } -static int ssl3_send_certificate_request(SSL *ssl) { +static int ssl3_send_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_CERT_REQ_B) { return ssl->method->write_message(ssl); } @@ -1261,7 +1423,8 @@ err: return -1; } -static int ssl3_send_server_hello_done(SSL *ssl) { +static int ssl3_send_server_hello_done(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_SRVR_DONE_B) { return ssl->method->write_message(ssl); } @@ -1278,8 +1441,9 @@ static int ssl3_send_server_hello_done(SSL *ssl) { return ssl->method->write_message(ssl); } -static int ssl3_get_client_certificate(SSL *ssl) { - assert(ssl->s3->hs->cert_request); +static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + assert(hs->cert_request); int msg_ret = ssl->method->ssl_get_message(ssl, -1, ssl_hash_message); if (msg_ret <= 0) { @@ -1377,7 +1541,8 @@ err: return -1; } -static int ssl3_get_client_key_exchange(SSL *ssl) { +static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int al; CBS client_key_exchange; uint32_t alg_k; @@ -1544,9 +1709,9 @@ static int ssl3_get_client_key_exchange(SSL *ssl) { /* The premaster secret must begin with |client_version|. This too must be * checked in constant time (http://eprint.iacr.org/2003/052/). */ good &= constant_time_eq_8(decrypt_buf[padding_len], - (unsigned)(ssl->client_version >> 8)); + (unsigned)(hs->client_version >> 8)); good &= constant_time_eq_8(decrypt_buf[padding_len + 1], - (unsigned)(ssl->client_version & 0xff)); + (unsigned)(hs->client_version & 0xff)); /* Select, in constant time, either the decrypted premaster or the random * premaster based on |good|. */ @@ -1560,8 +1725,7 @@ static int ssl3_get_client_key_exchange(SSL *ssl) { } else if (alg_k & (SSL_kECDHE|SSL_kDHE|SSL_kCECPQ1)) { /* Parse the ClientKeyExchange. */ CBS peer_key; - if (!SSL_ECDH_CTX_get_key(&ssl->s3->hs->ecdh_ctx, &client_key_exchange, - &peer_key) || + if (!SSL_ECDH_CTX_get_key(&hs->ecdh_ctx, &client_key_exchange, &peer_key) || CBS_len(&client_key_exchange) != 0) { al = SSL_AD_DECODE_ERROR; OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); @@ -1570,7 +1734,7 @@ static int ssl3_get_client_key_exchange(SSL *ssl) { /* Compute the premaster. */ uint8_t alert; - if (!SSL_ECDH_CTX_finish(&ssl->s3->hs->ecdh_ctx, &premaster_secret, + if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, &premaster_secret, &premaster_secret_len, &alert, CBS_data(&peer_key), CBS_len(&peer_key))) { al = alert; @@ -1578,7 +1742,7 @@ static int ssl3_get_client_key_exchange(SSL *ssl) { } /* The key exchange state may now be discarded. */ - SSL_ECDH_CTX_cleanup(&ssl->s3->hs->ecdh_ctx); + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); } else if (alg_k & SSL_kPSK) { /* For plain PSK, other_secret is a block of 0s with the same length as the * pre-shared key. */ @@ -1646,7 +1810,8 @@ err: return -1; } -static int ssl3_get_cert_verify(SSL *ssl) { +static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int al, ret = 0; CBS certificate_verify, signature; X509 *peer = ssl->s3->new_session->x509_peer; @@ -1762,7 +1927,8 @@ err: /* ssl3_get_next_proto reads a Next Protocol Negotiation handshake message. It * sets the next_proto member in s if found */ -static int ssl3_get_next_proto(SSL *ssl) { +static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = ssl->method->ssl_get_message(ssl, SSL3_MT_NEXT_PROTO, ssl_hash_message); if (ret <= 0) { @@ -1788,7 +1954,8 @@ static int ssl3_get_next_proto(SSL *ssl) { } /* ssl3_get_channel_id reads and verifies a ClientID handshake message. */ -static int ssl3_get_channel_id(SSL *ssl) { +static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int msg_ret = ssl->method->ssl_get_message(ssl, SSL3_MT_CHANNEL_ID, ssl_dont_hash_message); if (msg_ret <= 0) { @@ -1802,7 +1969,8 @@ static int ssl3_get_channel_id(SSL *ssl) { return 1; } -static int ssl3_send_new_session_ticket(SSL *ssl) { +static int ssl3_send_new_session_ticket(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->state == SSL3_ST_SW_SESSION_TICKET_B) { return ssl->method->write_message(ssl); } diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 1d78ec17..995adcfd 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -509,12 +509,12 @@ struct ssl_custom_extension { void SSL_CUSTOM_EXTENSION_free(SSL_CUSTOM_EXTENSION *custom_extension); -int custom_ext_add_clienthello(SSL *ssl, CBB *extensions); -int custom_ext_parse_serverhello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_parse_clienthello(SSL *ssl, int *out_alert, uint16_t value, - const CBS *extension); -int custom_ext_add_serverhello(SSL *ssl, CBB *extensions); +int custom_ext_add_clienthello(SSL_HANDSHAKE *hs, CBB *extensions); +int custom_ext_parse_serverhello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension); +int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, + uint16_t value, const CBS *extension); +int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions); /* Handshake hash. @@ -798,11 +798,12 @@ int ssl_do_client_cert_cb(SSL *ssl, int *out_should_retry); /* tls13_init_key_schedule initializes the handshake hash and key derivation * state. The cipher suite and PRF hash must have been selected at this point. * It returns one on success and zero on error. */ -int tls13_init_key_schedule(SSL *ssl); +int tls13_init_key_schedule(SSL_HANDSHAKE *hs); /* tls13_advance_key_schedule incorporates |in| into the key schedule with * HKDF-Extract. It returns one on success and zero on error. */ -int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len); +int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in, + size_t len); /* tls13_get_context_hash writes Hash(Handshake Context) to |out| which must * have room for at least |EVP_MAX_MD_SIZE| bytes. On success, it returns one @@ -810,13 +811,6 @@ int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len); * zero. */ int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len); -enum tls_record_type_t { - type_early_handshake, - type_early_data, - type_handshake, - type_data, -}; - /* tls13_set_traffic_key sets the read or write traffic keys to * |traffic_secret|. It returns one on success and zero on error. */ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, @@ -826,7 +820,7 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, /* tls13_set_handshake_traffic derives the handshake traffic secret and * switches both read and write traffic to it. It returns one on success and * zero on error. */ -int tls13_set_handshake_traffic(SSL *ssl); +int tls13_set_handshake_traffic(SSL_HANDSHAKE *hs); /* tls13_rotate_traffic_key derives the next read or write traffic secret. It * returns one on success and zero on error. */ @@ -835,10 +829,10 @@ int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction); /* tls13_derive_application_secrets derives the initial application data traffic * and exporter secrets based on the handshake transcripts and |master_secret|. * It returns one on success and zero on error. */ -int tls13_derive_application_secrets(SSL *ssl); +int tls13_derive_application_secrets(SSL_HANDSHAKE *hs); /* tls13_derive_resumption_secret derives the |resumption_secret|. */ -int tls13_derive_resumption_secret(SSL *ssl); +int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs); /* tls13_export_keying_material provides an exporter interface to use the * |exporter_secret|. */ @@ -851,7 +845,8 @@ int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, * the integrity of the Finished message, and stores the result in |out| and * length in |out_len|. |is_server| is 1 if this is for the Server Finished and * 0 for the Client Finished. */ -int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server); +int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, + size_t *out_len, int is_server); /* tls13_write_psk_binder calculates the PSK binder value and replaces the last * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on @@ -878,15 +873,18 @@ enum ssl_hs_wait_t { ssl_hs_private_key_operation, }; -typedef struct ssl_handshake_st { - /* wait contains the operation |do_handshake| is currently blocking on or - * |ssl_hs_ok| if none. */ - enum ssl_hs_wait_t wait; +struct ssl_handshake_st { + /* ssl is a non-owning pointer to the parent |SSL| object. */ + SSL *ssl; - /* do_handshake runs the handshake. On completion, it returns |ssl_hs_ok|. - * Otherwise, it returns a value corresponding to what operation is needed to - * progress. */ - enum ssl_hs_wait_t (*do_handshake)(SSL *ssl); + /* do_tls13_handshake runs the TLS 1.3 handshake. On completion, it returns + * |ssl_hs_ok|. Otherwise, it returns a value corresponding to what operation + * is needed to progress. */ + enum ssl_hs_wait_t (*do_tls13_handshake)(SSL_HANDSHAKE *hs); + + /* wait contains the operation |do_tls13_handshake| is currently blocking on + * or |ssl_hs_ok| if none. */ + enum ssl_hs_wait_t wait; int state; @@ -916,26 +914,13 @@ typedef struct ssl_handshake_st { uint16_t received; } custom_extensions; - /* ecdh_ctx is the current ECDH instance. */ - SSL_ECDH_CTX ecdh_ctx; - - /* scts_requested is one if the SCT extension is in the ClientHello. */ - unsigned scts_requested:1; - - /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be - * filled in. */ - unsigned needs_psk_binder:1; - - unsigned received_hello_retry_request:1; - - /* accept_psk_mode stores whether the client's PSK mode is compatible with our - * preferences. */ - unsigned accept_psk_mode:1; - /* retry_group is the group ID selected by the server in HelloRetryRequest in * TLS 1.3. */ uint16_t retry_group; + /* ecdh_ctx is the current ECDH instance. */ + SSL_ECDH_CTX ecdh_ctx; + /* cookie is the value of the cookie received from the server, if any. */ uint8_t *cookie; size_t cookie_len; @@ -972,10 +957,43 @@ typedef struct ssl_handshake_st { uint8_t *server_params; size_t server_params_len; + /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the + * server when using a TLS 1.2 PSK key exchange. */ + char *peer_psk_identity_hint; + + /* ca_names, on the client, contains the list of CAs received in a + * CertificateRequest message. */ + STACK_OF(X509_NAME) *ca_names; + + /* certificate_types, on the client, contains the set of certificate types + * received in a CertificateRequest message. */ + uint8_t *certificate_types; + size_t num_certificate_types; + + /* hostname, on the server, is the value of the SNI extension. */ + char *hostname; + + /* key_block is the record-layer key block for TLS 1.2 and earlier. */ + uint8_t *key_block; + uint8_t key_block_len; + /* session_tickets_sent, in TLS 1.3, is the number of tickets the server has * sent. */ uint8_t session_tickets_sent; + /* scts_requested is one if the SCT extension is in the ClientHello. */ + unsigned scts_requested:1; + + /* needs_psk_binder if the ClientHello has a placeholder PSK binder to be + * filled in. */ + unsigned needs_psk_binder:1; + + unsigned received_hello_retry_request:1; + + /* accept_psk_mode stores whether the client's PSK mode is compatible with our + * preferences. */ + unsigned accept_psk_mode:1; + /* cert_request is one if a client certificate was requested and zero * otherwise. */ unsigned cert_request:1; @@ -1003,40 +1021,23 @@ typedef struct ssl_handshake_st { * or received. */ unsigned ticket_expected:1; - /* peer_psk_identity_hint, on the client, is the psk_identity_hint sent by the - * server when using a TLS 1.2 PSK key exchange. */ - char *peer_psk_identity_hint; + /* client_version is the value sent or received in the ClientHello version. */ + uint16_t client_version; +} /* SSL_HANDSHAKE */; - /* ca_names, on the client, contains the list of CAs received in a - * CertificateRequest message. */ - STACK_OF(X509_NAME) *ca_names; - - /* certificate_types, on the client, contains the set of certificate types - * received in a CertificateRequest message. */ - uint8_t *certificate_types; - size_t num_certificate_types; - - /* key_block is the record-layer key block for TLS 1.2 and earlier. */ - uint8_t *key_block; - uint8_t key_block_len; - - /* hostname, on the server, is the value of the SNI extension. */ - char *hostname; -} SSL_HANDSHAKE; - -SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl)); +SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl); /* ssl_handshake_free releases all memory associated with |hs|. */ void ssl_handshake_free(SSL_HANDSHAKE *hs); /* tls13_handshake runs the TLS 1.3 handshake. It returns one on success and <= * 0 on error. */ -int tls13_handshake(SSL *ssl); +int tls13_handshake(SSL_HANDSHAKE *hs); -/* The following are implementations of |do_handshake| for the client and +/* The following are implementations of |do_tls13_handshake| for the client and * server. */ -enum ssl_hs_wait_t tls13_client_handshake(SSL *ssl); -enum ssl_hs_wait_t tls13_server_handshake(SSL *ssl); +enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs); +enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs); /* tls13_post_handshake processes a post-handshake message. It returns one on * success and zero on failure. */ @@ -1048,40 +1049,40 @@ int tls13_check_message_type(SSL *ssl, int type); int tls13_process_certificate(SSL *ssl, int allow_anonymous); int tls13_process_certificate_verify(SSL *ssl); -int tls13_process_finished(SSL *ssl); +int tls13_process_finished(SSL_HANDSHAKE *hs); -int tls13_prepare_certificate(SSL *ssl); +int tls13_prepare_certificate(SSL_HANDSHAKE *hs); enum ssl_private_key_result_t tls13_prepare_certificate_verify( - SSL *ssl, int is_first_run); -int tls13_prepare_finished(SSL *ssl); + SSL_HANDSHAKE *hs, int is_first_run); +int tls13_prepare_finished(SSL_HANDSHAKE *hs); int tls13_process_new_session_ticket(SSL *ssl); -int ssl_ext_key_share_parse_serverhello(SSL *ssl, uint8_t **out_secret, +int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, CBS *contents); -int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, +int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found, uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, CBS *contents); -int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out); +int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); -int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents); -int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl, +int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents); +int ssl_ext_pre_shared_key_parse_clienthello(SSL_HANDSHAKE *hs, SSL_SESSION **out_session, CBS *out_binders, uint8_t *out_alert, CBS *contents); -int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out); +int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); /* ssl_is_sct_list_valid does a shallow parse of the SCT list in |contents| and * returns one iff it's valid. */ int ssl_is_sct_list_valid(const CBS *contents); -int ssl_write_client_hello(SSL *ssl); +int ssl_write_client_hello(SSL_HANDSHAKE *hs); /* ssl_clear_tls13_state releases client state only needed for TLS 1.3. It * should be called once the version is known to be TLS 1.2 or earlier. */ -void ssl_clear_tls13_state(SSL *ssl); +void ssl_clear_tls13_state(SSL_HANDSHAKE *hs); enum ssl_cert_verify_context_t { ssl_cert_verify_server, @@ -1101,8 +1102,8 @@ int tls13_get_cert_verify_signature_input( /* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns * one on successful negotiation or if nothing was negotiated. It returns zero * and sets |*out_alert| to an alert on error. */ -int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert, - const struct ssl_early_callback_ctx *client_hello); +int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello); typedef struct { uint16_t type; @@ -1139,17 +1140,14 @@ int ssl_log_secret(const SSL *ssl, const char *label, const uint8_t *secret, /* ClientHello functions. */ -int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx, - const uint8_t *in, size_t in_len); +int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in, + size_t in_len); -int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx, - CBS *out, uint16_t extension_type); - -STACK_OF(SSL_CIPHER) * - ssl_parse_client_cipher_list(const struct ssl_early_callback_ctx *ctx); +int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, + CBS *out, uint16_t extension_type); -int ssl_client_cipher_list_contains_cipher( - const struct ssl_early_callback_ctx *client_hello, uint16_t id); +int ssl_client_cipher_list_contains_cipher(const SSL_CLIENT_HELLO *client_hello, + uint16_t id); /* GREASE. */ @@ -1173,13 +1171,14 @@ uint16_t ssl_get_grease_value(const SSL *ssl, enum ssl_grease_index_t index); /* Signature algorithms. */ /* tls1_parse_peer_sigalgs parses |sigalgs| as the list of peer signature - * algorithms and them on |ssl|. It returns one on success and zero on error. */ -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *sigalgs); + * algorithms and saves them on |hs|. It returns one on success and zero on + * error. */ +int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *sigalgs); /* tls1_choose_signature_algorithm sets |*out| to a signature algorithm for use - * with |ssl|'s private key based on the peer's preferences and the algorithms + * with |hs|'s private key based on the peer's preferences and the algorithms * supported. It returns one on success and zero on error. */ -int tls1_choose_signature_algorithm(SSL *ssl, uint16_t *out); +int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out); /* tls12_get_verify_sigalgs sets |*out| to the signature algorithms acceptable * for the peer signature and returns the length of the list. */ @@ -1381,18 +1380,6 @@ typedef struct ssl3_state_st { uint8_t server_random[SSL3_RANDOM_SIZE]; uint8_t client_random[SSL3_RANDOM_SIZE]; - /* have_version is true if the connection's final version is known. Otherwise - * the version has not been negotiated yet. */ - unsigned have_version:1; - - /* v2_hello_done is true if the peer's V2ClientHello, if any, has been handled - * and future messages should use the record layer. */ - unsigned v2_hello_done:1; - - /* initial_handshake_complete is true if the initial handshake has - * completed. */ - unsigned initial_handshake_complete:1; - /* read_buffer holds data from the transport to be processed. */ SSL3_BUFFER read_buffer; /* write_buffer holds data to be written to the transport. */ @@ -1424,10 +1411,13 @@ typedef struct ssl3_state_st { enum ssl_shutdown_t send_shutdown; int alert_dispatch; - uint8_t send_alert[2]; int total_renegotiations; + /* early_data_skipped is the amount of early data that has been skipped by the + * record layer. */ + uint16_t early_data_skipped; + /* empty_record_count is the number of consecutive empty records received. */ uint8_t empty_record_count; @@ -1438,6 +1428,39 @@ typedef struct ssl3_state_st { /* key_update_count is the number of consecutive KeyUpdates received. */ uint8_t key_update_count; + /* skip_early_data instructs the record layer to skip unexpected early data + * messages when 0RTT is rejected. */ + unsigned skip_early_data:1; + + /* have_version is true if the connection's final version is known. Otherwise + * the version has not been negotiated yet. */ + unsigned have_version:1; + + /* v2_hello_done is true if the peer's V2ClientHello, if any, has been handled + * and future messages should use the record layer. */ + unsigned v2_hello_done:1; + + /* initial_handshake_complete is true if the initial handshake has + * completed. */ + unsigned initial_handshake_complete:1; + + /* session_reused indicates whether a session was resumed. */ + unsigned session_reused:1; + + unsigned send_connection_binding:1; + + /* In a client, this means that the server supported Channel ID and that a + * Channel ID was sent. In a server it means that we echoed support for + * Channel IDs and that tlsext_channel_id will be valid after the + * handshake. */ + unsigned tlsext_channel_id_valid:1; + + uint8_t send_alert[2]; + + /* pending_message is the current outgoing handshake message. */ + uint8_t *pending_message; + uint32_t pending_message_len; + /* aead_read_ctx is the current read cipher state. */ SSL_AEAD_CTX *aead_read_ctx; @@ -1448,31 +1471,33 @@ typedef struct ssl3_state_st { * version. */ const SSL3_ENC_METHOD *enc_method; - /* pending_message is the current outgoing handshake message. */ - uint8_t *pending_message; - uint32_t pending_message_len; - /* hs is the handshake state for the current handshake or NULL if there isn't * one. */ SSL_HANDSHAKE *hs; uint8_t write_traffic_secret[EVP_MAX_MD_SIZE]; - uint8_t write_traffic_secret_len; uint8_t read_traffic_secret[EVP_MAX_MD_SIZE]; - uint8_t read_traffic_secret_len; uint8_t exporter_secret[EVP_MAX_MD_SIZE]; + uint8_t write_traffic_secret_len; + uint8_t read_traffic_secret_len; uint8_t exporter_secret_len; + /* Connection binding to prevent renegotiation attacks */ + uint8_t previous_client_finished[12]; + uint8_t previous_client_finished_len; + uint8_t previous_server_finished_len; + uint8_t previous_server_finished[12]; + /* State pertaining to the pending handshake. * * TODO(davidben): Move everything not needed after the handshake completes to * |hs| and remove this. */ struct { - int message_type; - /* used to hold the new cipher we are going to use */ const SSL_CIPHER *new_cipher; + int message_type; + /* used when SSL_ST_FLUSH_DATA is entered */ int next_state; @@ -1504,16 +1529,6 @@ typedef struct ssl3_state_st { * immutable. */ SSL_SESSION *established_session; - /* session_reused indicates whether a session was resumed. */ - unsigned session_reused:1; - - /* Connection binding to prevent renegotiation attacks */ - uint8_t previous_client_finished[12]; - uint8_t previous_client_finished_len; - uint8_t previous_server_finished[12]; - uint8_t previous_server_finished_len; - int send_connection_binding; - /* Next protocol negotiation. For the client, this is the protocol that we * sent in NextProtocol and is set when handling ServerHello extensions. * @@ -1532,11 +1547,6 @@ typedef struct ssl3_state_st { uint8_t *alpn_selected; size_t alpn_selected_len; - /* In a client, this means that the server supported Channel ID and that a - * Channel ID was sent. In a server it means that we echoed support for - * Channel IDs and that tlsext_channel_id will be valid after the - * handshake. */ - char tlsext_channel_id_valid; /* For a server: * If |tlsext_channel_id_valid| is true, then this contains the * verified Channel ID from the client: a P256 point, (x,y), where @@ -1642,7 +1652,7 @@ CERT *ssl_cert_new(void); CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); -int ssl_get_new_session(SSL *ssl, int is_server); +int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); /* ssl_session_is_context_valid returns one if |session|'s session ID context @@ -1665,14 +1675,14 @@ enum ssl_session_result_t { ssl_session_retry, }; -/* ssl_get_prev_session looks up the previous session based on |ctx|. On - * success, it sets |*out_session| to the session or NULL if none was found. If - * the session could not be looked up synchronously, it returns +/* ssl_get_prev_session looks up the previous session based on |client_hello|. + * On success, it sets |*out_session| to the session or NULL if none was found. + * If the session could not be looked up synchronously, it returns * |ssl_session_retry| and should be called again. Otherwise, it returns * |ssl_session_error|. */ enum ssl_session_result_t ssl_get_prev_session( SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, - int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx); + int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello); /* The following flags determine which parts of the session are duplicated. */ #define SSL_SESSION_DUP_AUTH_ONLY 0x0 @@ -1699,27 +1709,13 @@ void ssl_cipher_preference_list_free( const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( const SSL *ssl); -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain); -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509); -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509); -void ssl_cert_set_cert_cb(CERT *cert, - int (*cb)(SSL *ssl, void *arg), void *arg); - int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result, STACK_OF(X509) * cert_chain); -void ssl_update_cache(SSL *ssl, int mode); - -/* ssl_get_compatible_server_ciphers determines the key exchange and - * authentication cipher suite masks compatible with the server configuration - * and current ClientHello parameters of |ssl|. It sets |*out_mask_k| to the key - * exchange mask and |*out_mask_a| to the authentication mask. */ -void ssl_get_compatible_server_ciphers(SSL *ssl, uint32_t *out_mask_k, - uint32_t *out_mask_a); +void ssl_update_cache(SSL_HANDSHAKE *hs, int mode); int ssl_verify_alarm_type(long type); -int ssl3_get_finished(SSL *ssl); +int ssl3_get_finished(SSL_HANDSHAKE *hs); int ssl3_send_change_cipher_spec(SSL *ssl); int ssl3_send_alert(SSL *ssl, int level, int desc); int ssl3_get_message(SSL *ssl, int msg_type, @@ -1734,8 +1730,7 @@ void ssl3_release_current_message(SSL *ssl, int free_buffer); int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out, size_t *out_len, uint16_t signature_algorithm); -int ssl3_send_finished(SSL *ssl, int a, int b); -int ssl3_supports_cipher(const SSL_CIPHER *cipher); +int ssl3_send_finished(SSL_HANDSHAKE *hs, int a, int b); int ssl3_dispatch_alert(SSL *ssl); int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, int peek); @@ -1746,23 +1741,16 @@ int ssl3_write_app_data(SSL *ssl, const void *buf, int len); int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len); int ssl3_output_cert_chain(SSL *ssl); -const SSL_CIPHER *ssl3_choose_cipher( - SSL *ssl, const struct ssl_early_callback_ctx *client_hello, - const struct ssl_cipher_preference_list_st *srvr); - int ssl3_new(SSL *ssl); void ssl3_free(SSL *ssl); -int ssl3_accept(SSL *ssl); -int ssl3_connect(SSL *ssl); +int ssl3_accept(SSL_HANDSHAKE *hs); +int ssl3_connect(SSL_HANDSHAKE *hs); int ssl3_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); int ssl3_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); int ssl3_queue_message(SSL *ssl, uint8_t *msg, size_t len); int ssl3_write_message(SSL *ssl); -void ssl3_expect_flight(SSL *ssl); -void ssl3_received_flight(SSL *ssl); - int dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); int dtls1_finish_message(SSL *ssl, CBB *cbb, uint8_t **out_msg, size_t *out_len); @@ -1802,10 +1790,7 @@ int dtls1_parse_fragment(CBS *cbs, struct hm_header_st *out_hdr, CBS *out_body); int dtls1_check_timeout_num(SSL *ssl); int dtls1_handshake_write(SSL *ssl); -void dtls1_expect_flight(SSL *ssl); -void dtls1_received_flight(SSL *ssl); -int dtls1_supports_cipher(const SSL_CIPHER *cipher); void dtls1_start_timer(SSL *ssl); void dtls1_stop_timer(SSL *ssl); int dtls1_is_timer_expired(SSL *ssl); @@ -1829,7 +1814,7 @@ int ssl_is_wbio_buffered(const SSL *ssl); int ssl_init_wbio_buffer(SSL *ssl); void ssl_free_wbio_buffer(SSL *ssl); -int tls1_change_cipher_state(SSL *ssl, int which); +int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which); int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len); int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster, size_t premaster_len); @@ -1846,7 +1831,7 @@ int tls1_check_group_id(SSL *ssl, uint16_t group_id); /* tls1_get_shared_group sets |*out_group_id| to the first preferred shared * group between client and server preferences and returns one. If none may be * found, it returns zero. */ -int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id); +int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id); /* tls1_set_curves converts the array of |ncurves| NIDs pointed to by |curves| * into a newly allocated array of TLS group IDs. On success, the function @@ -1866,12 +1851,12 @@ int tls1_set_curves_list(uint16_t **out_group_ids, size_t *out_group_ids_len, * returns one on success and zero on failure. The |header_len| argument is the * length of the ClientHello written so far and is used to compute the padding * length. (It does not include the record header.) */ -int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len); +int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len); -int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out); -int ssl_parse_clienthello_tlsext( - SSL *ssl, const struct ssl_early_callback_ctx *client_hello); -int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs); +int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out); +int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello); +int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs); #define tlsext_tick_md EVP_sha256 diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c index d8720205..d775ccaa 100644 --- a/src/ssl/s3_both.c +++ b/src/ssl/s3_both.c @@ -130,14 +130,14 @@ #include "internal.h" -SSL_HANDSHAKE *ssl_handshake_new(enum ssl_hs_wait_t (*do_handshake)(SSL *ssl)) { +SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { SSL_HANDSHAKE *hs = OPENSSL_malloc(sizeof(SSL_HANDSHAKE)); if (hs == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } memset(hs, 0, sizeof(SSL_HANDSHAKE)); - hs->do_handshake = do_handshake; + hs->ssl = ssl; hs->wait = ssl_hs_ok; return hs; } @@ -260,7 +260,8 @@ int ssl3_write_message(SSL *ssl) { return 1; } -int ssl3_send_finished(SSL *ssl, int a, int b) { +int ssl3_send_finished(SSL_HANDSHAKE *hs, int a, int b) { + SSL *const ssl = hs->ssl; if (ssl->state == b) { return ssl->method->write_message(ssl); } @@ -309,7 +310,8 @@ int ssl3_send_finished(SSL *ssl, int a, int b) { return ssl->method->write_message(ssl); } -int ssl3_get_finished(SSL *ssl) { +int ssl3_get_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = ssl->method->ssl_get_message(ssl, SSL3_MT_FINISHED, ssl_dont_hash_message); if (ret <= 0) { diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c index 901b8afe..1aad8e65 100644 --- a/src/ssl/s3_lib.c +++ b/src/ssl/s3_lib.c @@ -162,14 +162,6 @@ #include "internal.h" -int ssl3_supports_cipher(const SSL_CIPHER *cipher) { - return 1; -} - -void ssl3_expect_flight(SSL *ssl) {} - -void ssl3_received_flight(SSL *ssl) {} - int ssl3_new(SSL *ssl) { SSL3_STATE *s3; @@ -240,84 +232,6 @@ const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( return NULL; } -const SSL_CIPHER *ssl3_choose_cipher( - SSL *ssl, const struct ssl_early_callback_ctx *client_hello, - const struct ssl_cipher_preference_list_st *server_pref) { - const SSL_CIPHER *c, *ret = NULL; - STACK_OF(SSL_CIPHER) *srvr = server_pref->ciphers, *prio, *allow; - int ok; - size_t cipher_index; - uint32_t alg_k, alg_a, mask_k, mask_a; - /* in_group_flags will either be NULL, or will point to an array of bytes - * which indicate equal-preference groups in the |prio| stack. See the - * comment about |in_group_flags| in the |ssl_cipher_preference_list_st| - * struct. */ - const uint8_t *in_group_flags; - /* group_min contains the minimal index so far found in a group, or -1 if no - * such value exists yet. */ - int group_min = -1; - - STACK_OF(SSL_CIPHER) *clnt = ssl_parse_client_cipher_list(client_hello); - if (clnt == NULL) { - return NULL; - } - - if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { - prio = srvr; - in_group_flags = server_pref->in_group_flags; - allow = clnt; - } else { - prio = clnt; - in_group_flags = NULL; - allow = srvr; - } - - ssl_get_compatible_server_ciphers(ssl, &mask_k, &mask_a); - - for (size_t i = 0; i < sk_SSL_CIPHER_num(prio); i++) { - c = sk_SSL_CIPHER_value(prio, i); - - ok = 1; - - /* Check the TLS version. */ - if (SSL_CIPHER_get_min_version(c) > ssl3_protocol_version(ssl) || - SSL_CIPHER_get_max_version(c) < ssl3_protocol_version(ssl)) { - ok = 0; - } - - alg_k = c->algorithm_mkey; - alg_a = c->algorithm_auth; - - ok = ok && (alg_k & mask_k) && (alg_a & mask_a); - - if (ok && sk_SSL_CIPHER_find(allow, &cipher_index, c)) { - if (in_group_flags != NULL && in_group_flags[i] == 1) { - /* This element of |prio| is in a group. Update the minimum index found - * so far and continue looking. */ - if (group_min == -1 || (size_t)group_min > cipher_index) { - group_min = cipher_index; - } - } else { - if (group_min != -1 && (size_t)group_min < cipher_index) { - cipher_index = group_min; - } - ret = sk_SSL_CIPHER_value(allow, cipher_index); - break; - } - } - - if (in_group_flags != NULL && in_group_flags[i] == 0 && group_min != -1) { - /* We are about to leave a group, but we found a match in it, so that's - * our answer. */ - ret = sk_SSL_CIPHER_value(allow, group_min); - break; - } - } - - sk_SSL_CIPHER_free(clnt); - return ret; -} - /* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and * handshake macs if required. */ uint32_t ssl_get_algorithm_prf(const SSL *ssl) { diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index 2a7b7d4b..aab6052c 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -473,7 +473,7 @@ static int SSL_SESSION_parse_octet_string(CBS *cbs, uint8_t **out_ptr, /* SSL_SESSION_parse_bounded_octet_string parses an optional ASN.1 OCTET STRING * explicitly tagged with |tag| of size at most |max_out|. */ static int SSL_SESSION_parse_bounded_octet_string( - CBS *cbs, uint8_t *out, unsigned *out_len, unsigned max_out, unsigned tag) { + CBS *cbs, uint8_t *out, uint8_t *out_len, uint8_t max_out, unsigned tag) { CBS value; if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag) || CBS_len(&value) > max_out) { @@ -481,7 +481,7 @@ static int SSL_SESSION_parse_bounded_octet_string( return 0; } memcpy(out, CBS_data(&value), CBS_len(&value)); - *out_len = (unsigned)CBS_len(&value); + *out_len = (uint8_t)CBS_len(&value); return 1; } diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c index 7f6cf636..c0bdb5c6 100644 --- a/src/ssl/ssl_cert.c +++ b/src/ssl/ssl_cert.c @@ -244,13 +244,13 @@ void ssl_cert_free(CERT *c) { OPENSSL_free(c); } -int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { +static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { sk_X509_pop_free(cert->x509_chain, X509_free); cert->x509_chain = chain; return 1; } -int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { +static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { STACK_OF(X509) *dchain; if (chain == NULL) { return ssl_cert_set0_chain(cert, NULL); @@ -269,7 +269,7 @@ int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { return 1; } -int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { +static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { if (cert->x509_chain == NULL) { cert->x509_chain = sk_X509_new_null(); } @@ -280,7 +280,7 @@ int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { return 1; } -int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { +static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { if (!ssl_cert_add0_chain_cert(cert, x509)) { return 0; } @@ -289,7 +289,8 @@ int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { return 1; } -void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), void *arg) { +static void ssl_cert_set_cert_cb(CERT *c, int (*cb)(SSL *ssl, void *arg), + void *arg) { c->cert_cb = cb; c->cert_cb_arg = arg; } @@ -775,6 +776,15 @@ int SSL_clear_chain_certs(SSL *ssl) { return SSL_set0_chain(ssl, NULL); } +void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), + void *arg) { + ssl_cert_set_cert_cb(ctx->cert, cb, arg); +} + +void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { + ssl_cert_set_cert_cb(ssl->cert, cb, arg); +} + int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { *out_chain = ctx->cert->x509_chain; return 1; diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 70a39ea4..b0c09065 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -477,6 +477,13 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->ctx->signed_cert_timestamps_enabled; ssl->ocsp_stapling_enabled = ssl->ctx->ocsp_stapling_enabled; + ssl->session_timeout = SSL_DEFAULT_SESSION_TIMEOUT; + + /* If the context has a default timeout, use it over the default. */ + if (ctx->session_timeout != 0) { + ssl->session_timeout = ctx->session_timeout; + } + return ssl; err: @@ -617,7 +624,28 @@ int SSL_do_handshake(SSL *ssl) { return 1; } - return ssl->handshake_func(ssl); + /* Set up a new handshake if necessary. */ + if (ssl->state == SSL_ST_INIT && ssl->s3->hs == NULL) { + ssl->s3->hs = ssl_handshake_new(ssl); + if (ssl->s3->hs == NULL) { + return -1; + } + } + + /* Run the handshake. */ + assert(ssl->s3->hs != NULL); + int ret = ssl->handshake_func(ssl->s3->hs); + if (ret <= 0) { + return ret; + } + + /* Destroy the handshake object if the handshake has completely finished. */ + if (!SSL_in_init(ssl)) { + ssl_handshake_free(ssl->s3->hs); + ssl->s3->hs = NULL; + } + + return 1; } int SSL_connect(SSL *ssl) { @@ -1106,24 +1134,28 @@ err: } int SSL_CTX_set_session_id_context(SSL_CTX *ctx, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { + size_t sid_ctx_len) { if (sid_ctx_len > sizeof(ctx->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } - ctx->sid_ctx_length = sid_ctx_len; + + assert(sizeof(ctx->sid_ctx) < 256); + ctx->sid_ctx_length = (uint8_t)sid_ctx_len; memcpy(ctx->sid_ctx, sid_ctx, sid_ctx_len); return 1; } int SSL_set_session_id_context(SSL *ssl, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + size_t sid_ctx_len) { + if (sid_ctx_len > sizeof(ssl->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } - ssl->sid_ctx_length = sid_ctx_len; + + assert(sizeof(ssl->sid_ctx) < 256); + ssl->sid_ctx_length = (uint8_t)sid_ctx_len; memcpy(ssl->sid_ctx, sid_ctx, sid_ctx_len); return 1; @@ -1664,39 +1696,6 @@ int SSL_set_cipher_list(SSL *ssl, const char *str) { return 1; } -STACK_OF(SSL_CIPHER) * - ssl_parse_client_cipher_list(const struct ssl_early_callback_ctx *ctx) { - CBS cipher_suites; - CBS_init(&cipher_suites, ctx->cipher_suites, ctx->cipher_suites_len); - - STACK_OF(SSL_CIPHER) *sk = sk_SSL_CIPHER_new_null(); - if (sk == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - - while (CBS_len(&cipher_suites) > 0) { - uint16_t cipher_suite; - - if (!CBS_get_u16(&cipher_suites, &cipher_suite)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); - goto err; - } - - const SSL_CIPHER *c = SSL_get_cipher_by_value(cipher_suite); - if (c != NULL && !sk_SSL_CIPHER_push(sk, c)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - - return sk; - -err: - sk_SSL_CIPHER_free(sk); - return NULL; -} - const char *SSL_get_servername(const SSL *ssl, const int type) { if (type != TLSEXT_NAMETYPE_host_name) { return NULL; @@ -1942,13 +1941,21 @@ void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data, } +void SSL_CTX_set_tls_channel_id_enabled(SSL_CTX *ctx, int enabled) { + ctx->tlsext_channel_id_enabled = !!enabled; +} + int SSL_CTX_enable_tls_channel_id(SSL_CTX *ctx) { - ctx->tlsext_channel_id_enabled = 1; + SSL_CTX_set_tls_channel_id_enabled(ctx, 1); return 1; } +void SSL_set_tls_channel_id_enabled(SSL *ssl, int enabled) { + ssl->tlsext_channel_id_enabled = !!enabled; +} + int SSL_enable_tls_channel_id(SSL *ssl) { - ssl->tlsext_channel_id_enabled = 1; + SSL_set_tls_channel_id_enabled(ssl, 1); return 1; } @@ -2013,15 +2020,6 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { X509_VERIFY_PARAM_set_depth(ctx->param, depth); } -void SSL_CTX_set_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, void *arg), - void *arg) { - ssl_cert_set_cert_cb(ctx->cert, cb, arg); -} - -void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { - ssl_cert_set_cert_cb(ssl->cert, cb, arg); -} - size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { if (ssl->server || ssl->s3->hs == NULL) { *out_types = NULL; @@ -2031,51 +2029,8 @@ size_t SSL_get0_certificate_types(SSL *ssl, const uint8_t **out_types) { return ssl->s3->hs->num_certificate_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; - - if (ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl)) { - int type = ssl_private_key_type(ssl); - if (type == NID_rsaEncryption) { - mask_k |= SSL_kRSA; - mask_a |= SSL_aRSA; - } else if (ssl_is_ecdsa_key_type(type)) { - mask_a |= SSL_aECDSA; - } - } - - if (ssl->cert->dh_tmp != NULL || ssl->cert->dh_tmp_cb != NULL) { - mask_k |= SSL_kDHE; - } - - /* Check for a shared group to consider ECDHE ciphers. */ - uint16_t unused; - if (tls1_get_shared_group(ssl, &unused)) { - mask_k |= SSL_kECDHE; - } - - /* CECPQ1 ciphers are always acceptable if supported by both sides. */ - mask_k |= SSL_kCECPQ1; - - /* PSK requires a server callback. */ - if (ssl->psk_server_callback != NULL) { - mask_k |= SSL_kPSK; - mask_a |= SSL_aPSK; - } - - *out_mask_k = mask_k; - *out_mask_a = mask_a; -} - -void ssl_update_cache(SSL *ssl, int mode) { +void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) { + SSL *const ssl = hs->ssl; SSL_CTX *ctx = ssl->initial_ctx; /* Never cache sessions with empty session IDs. */ if (ssl->s3->established_session->session_id_length == 0 || @@ -2091,7 +2046,7 @@ void ssl_update_cache(SSL *ssl, int mode) { * decides to renew the ticket. Once the handshake is completed, it should be * inserted into the cache. */ if (ssl->s3->established_session != ssl->session || - (!ssl->server && ssl->s3->hs->ticket_expected)) { + (!ssl->server && hs->ticket_expected)) { if (use_internal_cache) { SSL_CTX_add_session(ctx, ssl->s3->established_session); } @@ -2813,13 +2768,13 @@ int SSL_is_server(const SSL *ssl) { return ssl->server; } int SSL_is_dtls(const SSL *ssl) { return ssl->method->is_dtls; } -void SSL_CTX_set_select_certificate_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) { +void SSL_CTX_set_select_certificate_cb(SSL_CTX *ctx, + int (*cb)(const SSL_CLIENT_HELLO *)) { ctx->select_certificate_cb = cb; } -void SSL_CTX_set_dos_protection_cb( - SSL_CTX *ctx, int (*cb)(const struct ssl_early_callback_ctx *)) { +void SSL_CTX_set_dos_protection_cb(SSL_CTX *ctx, + int (*cb)(const SSL_CLIENT_HELLO *)) { ctx->dos_protection_cb = cb; } @@ -2827,11 +2782,6 @@ void SSL_set_renegotiate_mode(SSL *ssl, enum ssl_renegotiate_mode_t mode) { ssl->renegotiate_mode = mode; } -void SSL_set_reject_peer_renegotiations(SSL *ssl, int reject) { - SSL_set_renegotiate_mode( - ssl, reject ? ssl_renegotiate_never : ssl_renegotiate_freely); -} - int SSL_get_ivs(const SSL *ssl, const uint8_t **out_read_iv, const uint8_t **out_write_iv, size_t *out_iv_len) { if (ssl->s3->aead_read_ctx == NULL || ssl->s3->aead_write_ctx == NULL) { @@ -2922,9 +2872,13 @@ void SSL_CTX_set_grease_enabled(SSL_CTX *ctx, int enabled) { } int SSL_clear(SSL *ssl) { - if (ssl->method == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_METHOD_SPECIFIED); - return 0; + /* In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously + * established session to be offered the next time around. wpa_supplicant + * depends on this behavior, so emulate it. */ + SSL_SESSION *session = NULL; + if (!ssl->server && ssl->s3->established_session != NULL) { + session = ssl->s3->established_session; + SSL_SESSION_up_ref(session); } /* TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and @@ -2952,6 +2906,7 @@ int SSL_clear(SSL *ssl) { ssl->method->ssl_free(ssl); if (!ssl->method->ssl_new(ssl)) { + SSL_SESSION_free(session); return 0; } @@ -2959,7 +2914,10 @@ int SSL_clear(SSL *ssl) { ssl->d1->mtu = mtu; } - ssl->client_version = ssl->version; + if (session != NULL) { + SSL_set_session(ssl, session); + SSL_SESSION_free(session); + } return 1; } diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c index a6b669d0..67e809d9 100644 --- a/src/ssl/ssl_session.c +++ b/src/ssl/ssl_session.c @@ -392,13 +392,14 @@ long SSL_SESSION_set_timeout(SSL_SESSION *session, long timeout) { } int SSL_SESSION_set1_id_context(SSL_SESSION *session, const uint8_t *sid_ctx, - unsigned sid_ctx_len) { - if (sid_ctx_len > SSL_MAX_SID_CTX_LENGTH) { + size_t sid_ctx_len) { + if (sid_ctx_len > sizeof(session->sid_ctx)) { OPENSSL_PUT_ERROR(SSL, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG); return 0; } - session->sid_ctx_length = sid_ctx_len; + assert(sizeof(session->sid_ctx) < 256); + session->sid_ctx_length = (uint8_t)sid_ctx_len; memcpy(session->sid_ctx, sid_ctx, sid_ctx_len); return 1; @@ -449,7 +450,8 @@ void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { return CRYPTO_get_ex_data(&session->ex_data, idx); } -int ssl_get_new_session(SSL *ssl, int is_server) { +int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { + SSL *const ssl = hs->ssl; if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) { OPENSSL_PUT_ERROR(SSL, SSL_R_SESSION_MAY_NOT_BE_CREATED); return 0; @@ -465,15 +467,12 @@ int ssl_get_new_session(SSL *ssl, int is_server) { ssl_get_current_time(ssl, &now); session->time = now.tv_sec; - /* If the context has a default timeout, use it over the default. */ - if (ssl->initial_ctx->session_timeout != 0) { - session->timeout = ssl->initial_ctx->session_timeout; - } + session->timeout = ssl->session_timeout; session->ssl_version = ssl->version; if (is_server) { - if (ssl->s3->hs->ticket_expected) { + if (hs->ticket_expected) { /* Don't set session IDs for sessions resumed with tickets. This will keep * them out of the session cache. */ session->session_id_length = 0; @@ -724,7 +723,7 @@ static enum ssl_session_result_t ssl_lookup_session( enum ssl_session_result_t ssl_get_prev_session( SSL *ssl, SSL_SESSION **out_session, int *out_tickets_supported, - int *out_renew_ticket, const struct ssl_early_callback_ctx *ctx) { + int *out_renew_ticket, const SSL_CLIENT_HELLO *client_hello) { /* This is used only by servers. */ assert(ssl->server); SSL_SESSION *session = NULL; @@ -736,17 +735,18 @@ enum ssl_session_result_t ssl_get_prev_session( const int tickets_supported = !(SSL_get_options(ssl) & SSL_OP_NO_TICKET) && ssl->version > SSL3_VERSION && - SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_session_ticket, - &ticket, &ticket_len); + SSL_early_callback_ctx_extension_get( + client_hello, TLSEXT_TYPE_session_ticket, &ticket, &ticket_len); if (tickets_supported && ticket_len > 0) { if (!tls_process_ticket(ssl, &session, &renew_ticket, ticket, ticket_len, - ctx->session_id, ctx->session_id_len)) { + client_hello->session_id, + client_hello->session_id_len)) { return ssl_session_error; } } else { /* The client didn't send a ticket, so the session ID is a real ID. */ enum ssl_session_result_t lookup_ret = ssl_lookup_session( - ssl, &session, ctx->session_id, ctx->session_id_len); + ssl, &session, client_hello->session_id, client_hello->session_id_len); if (lookup_ret != ssl_session_success) { return lookup_ret; } @@ -875,6 +875,12 @@ long SSL_CTX_get_timeout(const SSL_CTX *ctx) { return ctx->session_timeout; } +long SSL_set_session_timeout(SSL *ssl, long timeout) { + long old_timeout = ssl->session_timeout; + ssl->session_timeout = timeout; + return old_timeout; +} + typedef struct timeout_param_st { SSL_CTX *ctx; long time; diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index ae9d5ca4..9bdaad2c 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -1246,30 +1246,11 @@ static bssl::UniquePtr<EVP_PKEY> GetECDSATestKey() { PEM_read_bio_PrivateKey(bio.get(), nullptr, nullptr, nullptr)); } -static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, bssl::UniquePtr<SSL> *out_server, - SSL_CTX *client_ctx, SSL_CTX *server_ctx, - SSL_SESSION *session) { - bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx)); - if (!client || !server) { - return false; - } - SSL_set_connect_state(client.get()); - SSL_set_accept_state(server.get()); - - SSL_set_session(client.get(), session); - - BIO *bio1, *bio2; - if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) { - return false; - } - // SSL_set_bio takes ownership. - SSL_set_bio(client.get(), bio1, bio1); - SSL_set_bio(server.get(), bio2, bio2); - +static bool CompleteHandshakes(SSL *client, SSL *server) { // Drive both their handshakes to completion. for (;;) { - int client_ret = SSL_do_handshake(client.get()); - int client_err = SSL_get_error(client.get(), client_ret); + int client_ret = SSL_do_handshake(client); + int client_err = SSL_get_error(client, client_ret); if (client_err != SSL_ERROR_NONE && client_err != SSL_ERROR_WANT_READ && client_err != SSL_ERROR_WANT_WRITE) { @@ -1277,8 +1258,8 @@ static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, bssl::Uniqu return false; } - int server_ret = SSL_do_handshake(server.get()); - int server_err = SSL_get_error(server.get(), server_ret); + int server_ret = SSL_do_handshake(server); + int server_err = SSL_get_error(server, server_ret); if (server_err != SSL_ERROR_NONE && server_err != SSL_ERROR_WANT_READ && server_err != SSL_ERROR_WANT_WRITE) { @@ -1291,6 +1272,34 @@ static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, bssl::Uniqu } } + return true; +} + +static bool ConnectClientAndServer(bssl::UniquePtr<SSL> *out_client, + bssl::UniquePtr<SSL> *out_server, + SSL_CTX *client_ctx, SSL_CTX *server_ctx, + SSL_SESSION *session) { + bssl::UniquePtr<SSL> client(SSL_new(client_ctx)), server(SSL_new(server_ctx)); + if (!client || !server) { + return false; + } + SSL_set_connect_state(client.get()); + SSL_set_accept_state(server.get()); + + SSL_set_session(client.get(), session); + + BIO *bio1, *bio2; + if (!BIO_new_bio_pair(&bio1, 0, &bio2, 0)) { + return false; + } + // SSL_set_bio takes ownership. + SSL_set_bio(client.get(), bio1, bio1); + SSL_set_bio(server.get(), bio2, bio2); + + if (!CompleteHandshakes(client.get(), server.get())) { + return false; + } + *out_client = std::move(client); *out_server = std::move(server); return true; @@ -2030,11 +2039,11 @@ static int SwitchSessionIDContextSNI(SSL *ssl, int *out_alert, void *arg) { return SSL_TLSEXT_ERR_OK; } -static int SwitchSessionIDContextEarly( - const struct ssl_early_callback_ctx *ctx) { +static int SwitchSessionIDContextEarly(const SSL_CLIENT_HELLO *client_hello) { static const uint8_t kContext[] = {3}; - if (!SSL_set_session_id_context(ctx->ssl, kContext, sizeof(kContext))) { + if (!SSL_set_session_id_context(client_hello->ssl, kContext, + sizeof(kContext))) { return -1; } @@ -2319,6 +2328,131 @@ static bool TestSessionTimeout(bool is_dtls, const SSL_METHOD *method, return true; } +static int SetSessionTimeoutCallback(SSL *ssl, void *arg) { + long timeout = *(long *) arg; + SSL_set_session_timeout(ssl, timeout); + return 1; +} + +static bool TestSessionTimeoutCertCallback(bool is_dtls, + const SSL_METHOD *method, + uint16_t version) { + static const int kStartTime = 1000; + g_current_time.tv_sec = kStartTime; + + bssl::UniquePtr<X509> cert = GetTestCertificate(); + bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); + if (!cert || !key) { + return false; + } + + bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); + bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); + if (!server_ctx || !client_ctx || + !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || + !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get()) || + !SSL_CTX_set_min_proto_version(client_ctx.get(), version) || + !SSL_CTX_set_max_proto_version(client_ctx.get(), version) || + !SSL_CTX_set_min_proto_version(server_ctx.get(), version) || + !SSL_CTX_set_max_proto_version(server_ctx.get(), version)) { + return false; + } + + SSL_CTX_set_session_cache_mode(client_ctx.get(), SSL_SESS_CACHE_BOTH); + SSL_CTX_set_session_cache_mode(server_ctx.get(), SSL_SESS_CACHE_BOTH); + + SSL_CTX_set_current_time_cb(server_ctx.get(), CurrentTimeCallback); + + long timeout = 25; + SSL_CTX_set_cert_cb(server_ctx.get(), SetSessionTimeoutCallback, &timeout); + + bssl::UniquePtr<SSL_SESSION> session = + CreateClientSession(client_ctx.get(), server_ctx.get()); + if (!session) { + fprintf(stderr, "Error getting session.\n"); + return false; + } + + // Advance the clock just behind the timeout. + g_current_time.tv_sec += timeout - 1; + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), + true /* expect session reused */)) { + fprintf(stderr, "Error resuming session.\n"); + return false; + } + + // Advance the clock one more second. + g_current_time.tv_sec++; + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), session.get(), + false /* expect session not reused */)) { + fprintf(stderr, "Error resuming session.\n"); + return false; + } + + // Set session timeout to 0 to disable resumption. + timeout = 0; + g_current_time.tv_sec = kStartTime; + + bssl::UniquePtr<SSL_SESSION> not_resumable_session = + CreateClientSession(client_ctx.get(), server_ctx.get()); + if (!not_resumable_session) { + fprintf(stderr, "Error getting session.\n"); + return false; + } + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), + not_resumable_session.get(), + false /* expect session not reused */)) { + fprintf(stderr, "Error resuming session with timeout of 0.\n"); + return false; + } + + // Set both context and connection (via callback) default session timeout. + // The connection one is the one that ends up being used. + timeout = 25; + g_current_time.tv_sec = kStartTime; + + SSL_CTX_set_timeout(server_ctx.get(), timeout - 10); + + bssl::UniquePtr<SSL_SESSION> ctx_and_cb_session = + CreateClientSession(client_ctx.get(), server_ctx.get()); + if (!ctx_and_cb_session) { + fprintf(stderr, "Error getting session.\n"); + return false; + } + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), + ctx_and_cb_session.get(), + true /* expect session reused */)) { + fprintf(stderr, "Error resuming session with timeout of 0.\n"); + return false; + } + + // Advance the clock just behind the timeout. + g_current_time.tv_sec += timeout - 1; + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), + ctx_and_cb_session.get(), + true /* expect session reused */)) { + fprintf(stderr, "Error resuming session.\n"); + return false; + } + + // Advance the clock one more second. + g_current_time.tv_sec++; + + if (!ExpectSessionReused(client_ctx.get(), server_ctx.get(), + ctx_and_cb_session.get(), + false /* expect session not reused */)) { + fprintf(stderr, "Error resuming session.\n"); + return false; + } + + return true; +} + static int SwitchContext(SSL *ssl, int *out_alert, void *arg) { SSL_CTX *ctx = reinterpret_cast<SSL_CTX*>(arg); SSL_set_SSL_CTX(ssl, ctx); @@ -2386,8 +2520,8 @@ static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method, return true; } -static int SetMaxVersion(const struct ssl_early_callback_ctx *ctx) { - if (!SSL_set_max_proto_version(ctx->ssl, TLS1_2_VERSION)) { +static int SetMaxVersion(const SSL_CLIENT_HELLO *client_hello) { + if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) { return -1; } @@ -2594,6 +2728,65 @@ static bool TestALPNCipherAvailable(bool is_dtls, const SSL_METHOD *method, return true; } +static bool TestSSLClearSessionResumption(bool is_dtls, + const SSL_METHOD *method, + uint16_t version) { + // Skip this for TLS 1.3. TLS 1.3's ticket mechanism is incompatible with this + // API pattern. + if (version == TLS1_3_VERSION) { + return true; + } + + bssl::UniquePtr<X509> cert = GetTestCertificate(); + bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); + bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(method)); + bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(method)); + if (!cert || !key || !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)) { + return false; + } + + // Connect a client and a server. + bssl::UniquePtr<SSL> client, server; + if (!ConnectClientAndServer(&client, &server, client_ctx.get(), + server_ctx.get(), nullptr /* no session */)) { + return false; + } + + if (SSL_session_reused(client.get()) || + SSL_session_reused(server.get())) { + fprintf(stderr, "Session unexpectedly reused.\n"); + return false; + } + + // Reset everything. + if (!SSL_clear(client.get()) || + !SSL_clear(server.get())) { + fprintf(stderr, "SSL_clear failed.\n"); + return false; + } + + // Attempt to connect a second time. + if (!CompleteHandshakes(client.get(), server.get())) { + fprintf(stderr, "Could not reuse SSL objects.\n"); + return false; + } + + // |SSL_clear| should implicitly offer the previous session to the server. + if (!SSL_session_reused(client.get()) || + !SSL_session_reused(server.get())) { + fprintf(stderr, "Session was not reused in second try.\n"); + return false; + } + + return true; +} + static bool ForEachVersion(bool (*test_func)(bool is_dtls, const SSL_METHOD *method, uint16_t version)) { @@ -2664,11 +2857,13 @@ int main() { !TestClientHello() || !ForEachVersion(TestSessionIDContext) || !ForEachVersion(TestSessionTimeout) || + !ForEachVersion(TestSessionTimeoutCertCallback) || !ForEachVersion(TestSNICallback) || !TestEarlyCallbackVersionSwitch() || !TestSetVersion() || !ForEachVersion(TestVersion) || - !ForEachVersion(TestALPNCipherAvailable)) { + !ForEachVersion(TestALPNCipherAvailable) || + !ForEachVersion(TestSSLClearSessionResumption)) { ERR_print_errors_fp(stderr); return 1; } diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c index 4c7d3ee3..70907e18 100644 --- a/src/ssl/t1_enc.c +++ b/src/ssl/t1_enc.c @@ -258,8 +258,9 @@ static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len, return 1; } -static int tls1_setup_key_block(SSL *ssl) { - if (ssl->s3->hs->key_block_len != 0) { +static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (hs->key_block_len != 0) { return 1; } @@ -310,14 +311,15 @@ static int tls1_setup_key_block(SSL *ssl) { } assert(key_block_len < 256); - ssl->s3->hs->key_block_len = (uint8_t)key_block_len; - ssl->s3->hs->key_block = keyblock; + hs->key_block_len = (uint8_t)key_block_len; + hs->key_block = keyblock; return 1; } -int tls1_change_cipher_state(SSL *ssl, int which) { +int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which) { + SSL *const ssl = hs->ssl; /* Ensure the key block is set up. */ - if (!tls1_setup_key_block(ssl)) { + if (!tls1_setup_key_block(hs)) { return 0; } @@ -333,9 +335,9 @@ int tls1_change_cipher_state(SSL *ssl, int which) { size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len; size_t key_len = ssl->s3->tmp.new_key_len; size_t iv_len = ssl->s3->tmp.new_fixed_iv_len; - assert((mac_secret_len + key_len + iv_len) * 2 == ssl->s3->hs->key_block_len); + assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block_len); - const uint8_t *key_data = ssl->s3->hs->key_block; + const uint8_t *key_data = hs->key_block; const uint8_t *client_write_mac_secret = key_data; key_data += mac_secret_len; const uint8_t *server_write_mac_secret = key_data; diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index 421232f1..3530ff5d 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -127,8 +127,8 @@ #include "../crypto/internal.h" -static int ssl_check_clienthello_tlsext(SSL *ssl); -static int ssl_check_serverhello_tlsext(SSL *ssl); +static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs); +static int ssl_check_serverhello_tlsext(SSL_HANDSHAKE *hs); static int compare_uint16_t(const void *p1, const void *p2) { uint16_t u1 = *((const uint16_t *)p1); @@ -203,29 +203,29 @@ done: return ret; } -int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx, - const uint8_t *in, size_t in_len) { - memset(ctx, 0, sizeof(*ctx)); - ctx->ssl = ssl; - ctx->client_hello = in; - ctx->client_hello_len = in_len; +int ssl_client_hello_init(SSL *ssl, SSL_CLIENT_HELLO *out, const uint8_t *in, + size_t in_len) { + memset(out, 0, sizeof(*out)); + out->ssl = ssl; + out->client_hello = in; + out->client_hello_len = in_len; CBS client_hello, random, session_id; - CBS_init(&client_hello, ctx->client_hello, ctx->client_hello_len); - if (!CBS_get_u16(&client_hello, &ctx->version) || + CBS_init(&client_hello, out->client_hello, out->client_hello_len); + if (!CBS_get_u16(&client_hello, &out->version) || !CBS_get_bytes(&client_hello, &random, SSL3_RANDOM_SIZE) || !CBS_get_u8_length_prefixed(&client_hello, &session_id) || CBS_len(&session_id) > SSL_MAX_SSL_SESSION_ID_LENGTH) { return 0; } - ctx->random = CBS_data(&random); - ctx->random_len = CBS_len(&random); - ctx->session_id = CBS_data(&session_id); - ctx->session_id_len = CBS_len(&session_id); + out->random = CBS_data(&random); + out->random_len = CBS_len(&random); + out->session_id = CBS_data(&session_id); + out->session_id_len = CBS_len(&session_id); /* Skip past DTLS cookie */ - if (SSL_is_dtls(ctx->ssl)) { + if (SSL_is_dtls(out->ssl)) { CBS cookie; if (!CBS_get_u8_length_prefixed(&client_hello, &cookie) || CBS_len(&cookie) > DTLS1_COOKIE_LENGTH) { @@ -241,16 +241,16 @@ int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx, return 0; } - ctx->cipher_suites = CBS_data(&cipher_suites); - ctx->cipher_suites_len = CBS_len(&cipher_suites); - ctx->compression_methods = CBS_data(&compression_methods); - ctx->compression_methods_len = CBS_len(&compression_methods); + out->cipher_suites = CBS_data(&cipher_suites); + out->cipher_suites_len = CBS_len(&cipher_suites); + out->compression_methods = CBS_data(&compression_methods); + out->compression_methods_len = CBS_len(&compression_methods); /* If the ClientHello ends here then it's valid, but doesn't have any * extensions. (E.g. SSLv3.) */ if (CBS_len(&client_hello) == 0) { - ctx->extensions = NULL; - ctx->extensions_len = 0; + out->extensions = NULL; + out->extensions_len = 0; return 1; } @@ -262,16 +262,16 @@ int ssl_early_callback_init(SSL *ssl, struct ssl_early_callback_ctx *ctx, return 0; } - ctx->extensions = CBS_data(&extensions); - ctx->extensions_len = CBS_len(&extensions); + out->extensions = CBS_data(&extensions); + out->extensions_len = CBS_len(&extensions); return 1; } -int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx, - CBS *out, uint16_t extension_type) { +int ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, + CBS *out, uint16_t extension_type) { CBS extensions; - CBS_init(&extensions, ctx->extensions, ctx->extensions_len); + CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len); while (CBS_len(&extensions) != 0) { /* Decode the next extension. */ uint16_t type; @@ -290,11 +290,12 @@ int ssl_early_callback_get_extension(const struct ssl_early_callback_ctx *ctx, return 0; } -int SSL_early_callback_ctx_extension_get( - const struct ssl_early_callback_ctx *ctx, uint16_t extension_type, - const uint8_t **out_data, size_t *out_len) { +int SSL_early_callback_ctx_extension_get(const SSL_CLIENT_HELLO *client_hello, + uint16_t extension_type, + const uint8_t **out_data, + size_t *out_len) { CBS cbs; - if (!ssl_early_callback_get_extension(ctx, &cbs, extension_type)) { + if (!ssl_client_hello_get_extension(client_hello, &cbs, extension_type)) { return 0; } @@ -322,7 +323,8 @@ void tls1_get_grouplist(SSL *ssl, const uint16_t **out_group_ids, } } -int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id) { +int tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id) { + SSL *const ssl = hs->ssl; assert(ssl->server); const uint16_t *groups, *pref, *supp; @@ -341,11 +343,11 @@ int tls1_get_shared_group(SSL *ssl, uint16_t *out_group_id) { if (ssl->options & SSL_OP_CIPHER_SERVER_PREFERENCE) { pref = groups; pref_len = groups_len; - supp = ssl->s3->hs->peer_supported_group_list; - supp_len = ssl->s3->hs->peer_supported_group_list_len; + supp = hs->peer_supported_group_list; + supp_len = hs->peer_supported_group_list_len; } else { - pref = ssl->s3->hs->peer_supported_group_list; - pref_len = ssl->s3->hs->peer_supported_group_list_len; + pref = hs->peer_supported_group_list; + pref_len = hs->peer_supported_group_list_len; supp = groups; supp_len = groups_len; } @@ -597,16 +599,19 @@ void ssl_set_client_disabled(SSL *ssl) { * |*out_alert| isn't set, then a |decode_error| alert will be sent. */ struct tls_extension { uint16_t value; - void (*init)(SSL *ssl); + void (*init)(SSL_HANDSHAKE *hs); - int (*add_clienthello)(SSL *ssl, CBB *out); - int (*parse_serverhello)(SSL *ssl, uint8_t *out_alert, CBS *contents); + int (*add_clienthello)(SSL_HANDSHAKE *hs, CBB *out); + int (*parse_serverhello)(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents); - int (*parse_clienthello)(SSL *ssl, uint8_t *out_alert, CBS *contents); - int (*add_serverhello)(SSL *ssl, CBB *out); + int (*parse_clienthello)(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents); + int (*add_serverhello)(SSL_HANDSHAKE *hs, CBB *out); }; -static int forbid_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) { +static int forbid_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents) { if (contents != NULL) { /* Servers MUST NOT send this extension. */ *out_alert = SSL_AD_UNSUPPORTED_EXTENSION; @@ -617,12 +622,13 @@ static int forbid_parse_serverhello(SSL *ssl, uint8_t *out_alert, CBS *contents) return 1; } -static int ignore_parse_clienthello(SSL *ssl, uint8_t *out_alert, CBS *contents) { +static int ignore_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, + CBS *contents) { /* This extension from the client is handled elsewhere. */ return 1; } -static int dont_add_serverhello(SSL *ssl, CBB *out) { +static int dont_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { return 1; } @@ -630,7 +636,8 @@ static int dont_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc6066#section-3. */ -static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { +static int ext_sni_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->tlsext_hostname == NULL) { return 1; } @@ -650,8 +657,9 @@ static int ext_sni_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_sni_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -674,7 +682,7 @@ static int ext_sni_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sni_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; @@ -706,18 +714,18 @@ static int ext_sni_parse_clienthello(SSL *ssl, uint8_t *out_alert, } /* Copy the hostname as a string. */ - if (!CBS_strdup(&host_name, &ssl->s3->hs->hostname)) { + if (!CBS_strdup(&host_name, &hs->hostname)) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } - ssl->s3->hs->should_ack_sni = 1; + hs->should_ack_sni = 1; return 1; } -static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { - if (ssl->s3->session_reused || - !ssl->s3->hs->should_ack_sni) { +static int ext_sni_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (hs->ssl->s3->session_reused || + !hs->should_ack_sni) { return 1; } @@ -734,7 +742,8 @@ static int ext_sni_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5746 */ -static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ri_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -761,8 +770,9 @@ static int ext_ri_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ri_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents != NULL && ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { return 0; } @@ -834,8 +844,9 @@ static int ext_ri_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ri_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; /* Renegotiation isn't supported as a server so this function should never be * called after the initial handshake. */ assert(!ssl->s3->initial_handshake_complete); @@ -868,7 +879,8 @@ static int ext_ri_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { +static int ext_ri_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; /* Renegotiation isn't supported as a server so this function should never be * called after the initial handshake. */ assert(!ssl->s3->initial_handshake_complete); @@ -891,9 +903,9 @@ static int ext_ri_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc7627 */ -static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ems_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { uint16_t min_version, max_version; - if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) { return 0; } @@ -910,8 +922,9 @@ static int ext_ems_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ems_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; /* Whether EMS is negotiated may not change on renegotation. */ if (ssl->s3->initial_handshake_complete) { if ((contents != NULL) != ssl->s3->tmp.extended_master_secret) { @@ -940,10 +953,12 @@ static int ext_ems_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ems_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || - ssl->version == SSL3_VERSION) { + SSL *const ssl = hs->ssl; + uint16_t version = ssl3_protocol_version(ssl); + if (version >= TLS1_3_VERSION || + version == SSL3_VERSION) { return 1; } @@ -959,8 +974,8 @@ static int ext_ems_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->tmp.extended_master_secret) { +static int ext_ems_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->ssl->s3->tmp.extended_master_secret) { return 1; } @@ -977,7 +992,8 @@ static int ext_ems_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5077 */ -static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ticket_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -1019,8 +1035,9 @@ static int ext_ticket_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ticket_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1038,17 +1055,17 @@ static int ext_ticket_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } - ssl->s3->hs->ticket_expected = 1; + hs->ticket_expected = 1; return 1; } -static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->hs->ticket_expected) { +static int ext_ticket_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->ticket_expected) { return 1; } /* If |SSL_OP_NO_TICKET| is set, |ticket_expected| should never be true. */ - assert((SSL_get_options(ssl) & SSL_OP_NO_TICKET) == 0); + assert((SSL_get_options(hs->ssl) & SSL_OP_NO_TICKET) == 0); if (!CBB_add_u16(out, TLSEXT_TYPE_session_ticket) || !CBB_add_u16(out, 0 /* length */)) { @@ -1063,7 +1080,8 @@ static int ext_ticket_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ -static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { +static int ext_sigalgs_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -1096,11 +1114,11 @@ static int ext_sigalgs_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sigalgs_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - OPENSSL_free(ssl->s3->hs->peer_sigalgs); - ssl->s3->hs->peer_sigalgs = NULL; - ssl->s3->hs->num_peer_sigalgs = 0; + OPENSSL_free(hs->peer_sigalgs); + hs->peer_sigalgs = NULL; + hs->num_peer_sigalgs = 0; if (contents == NULL) { return 1; @@ -1110,7 +1128,7 @@ static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, if (!CBS_get_u16_length_prefixed(contents, &supported_signature_algorithms) || CBS_len(contents) != 0 || CBS_len(&supported_signature_algorithms) == 0 || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { return 0; } @@ -1122,11 +1140,12 @@ static int ext_sigalgs_parse_clienthello(SSL *ssl, uint8_t *out_alert, * * https://tools.ietf.org/html/rfc6066#section-8 */ -static void ext_ocsp_init(SSL *ssl) { - ssl->tlsext_status_type = -1; +static void ext_ocsp_init(SSL_HANDSHAKE *hs) { + hs->ssl->tlsext_status_type = -1; } -static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ocsp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->ocsp_stapling_enabled) { return 1; } @@ -1145,8 +1164,9 @@ static int ext_ocsp_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ocsp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1166,11 +1186,11 @@ static int ext_ocsp_parse_serverhello(SSL *ssl, uint8_t *out_alert, * status_request here does not make sense, but OpenSSL does so and the * specification does not say anything. Tolerate it but ignore it. */ - ssl->s3->hs->certificate_status_expected = 1; + hs->certificate_status_expected = 1; return 1; } -static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ocsp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; @@ -1183,21 +1203,22 @@ static int ext_ocsp_parse_clienthello(SSL *ssl, uint8_t *out_alert, /* We cannot decide whether OCSP stapling will occur yet because the correct * SSL_CTX might not have been selected. */ - ssl->s3->hs->ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; + hs->ocsp_stapling_requested = status_type == TLSEXT_STATUSTYPE_ocsp; return 1; } -static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { +static int ext_ocsp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || - !ssl->s3->hs->ocsp_stapling_requested || + !hs->ocsp_stapling_requested || ssl->ctx->ocsp_response_length == 0 || ssl->s3->session_reused || !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { return 1; } - ssl->s3->hs->certificate_status_expected = 1; + hs->certificate_status_expected = 1; return CBB_add_u16(out, TLSEXT_TYPE_status_request) && CBB_add_u16(out, 0 /* length */); @@ -1208,10 +1229,10 @@ static int ext_ocsp_add_serverhello(SSL *ssl, CBB *out) { * * https://htmlpreview.github.io/?https://github.com/agl/technotes/blob/master/nextprotoneg.html */ -static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { +static int ext_npn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->s3->initial_handshake_complete || ssl->ctx->next_proto_select_cb == NULL || - (ssl->options & SSL_OP_DISABLE_NPN) || SSL_is_dtls(ssl)) { return 1; } @@ -1224,8 +1245,9 @@ static int ext_npn_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_npn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1240,7 +1262,6 @@ static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, assert(!ssl->s3->initial_handshake_complete); assert(!SSL_is_dtls(ssl)); assert(ssl->ctx->next_proto_select_cb != NULL); - assert(!(ssl->options & SSL_OP_DISABLE_NPN)); if (ssl->s3->alpn_selected != NULL) { /* NPN and ALPN may not be negotiated in the same connection. */ @@ -1277,13 +1298,14 @@ static int ext_npn_parse_serverhello(SSL *ssl, uint8_t *out_alert, } ssl->s3->next_proto_negotiated_len = selected_len; - ssl->s3->hs->next_proto_neg_seen = 1; + hs->next_proto_neg_seen = 1; return 1; } -static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_npn_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { return 1; } @@ -1299,14 +1321,15 @@ static int ext_npn_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } - ssl->s3->hs->next_proto_neg_seen = 1; + hs->next_proto_neg_seen = 1; return 1; } -static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { +static int ext_npn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; /* |next_proto_neg_seen| might have been cleared when an ALPN extension was * parsed. */ - if (!ssl->s3->hs->next_proto_neg_seen) { + if (!hs->next_proto_neg_seen) { return 1; } @@ -1316,7 +1339,7 @@ static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { if (ssl->ctx->next_protos_advertised_cb( ssl, &npa, &npa_len, ssl->ctx->next_protos_advertised_cb_arg) != SSL_TLSEXT_ERR_OK) { - ssl->s3->hs->next_proto_neg_seen = 0; + hs->next_proto_neg_seen = 0; return 1; } @@ -1336,7 +1359,8 @@ static int ext_npn_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc6962#section-3.3.1 */ -static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { +static int ext_sct_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->signed_cert_timestamps_enabled) { return 1; } @@ -1349,8 +1373,9 @@ static int ext_sct_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_sct_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1387,7 +1412,7 @@ static int ext_sct_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_sct_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; @@ -1397,11 +1422,12 @@ static int ext_sct_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 0; } - ssl->s3->hs->scts_requested = 1; + hs->scts_requested = 1; return 1; } -static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { +static int ext_sct_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; /* The extension shouldn't be sent when resuming sessions. */ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || ssl->s3->session_reused || @@ -1422,7 +1448,8 @@ static int ext_sct_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc7301 */ -static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { +static int ext_alpn_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->alpn_client_proto_list == NULL || ssl->s3->initial_handshake_complete) { return 1; @@ -1441,8 +1468,9 @@ static int ext_alpn_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1450,7 +1478,7 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, assert(!ssl->s3->initial_handshake_complete); assert(ssl->alpn_client_proto_list != NULL); - if (ssl->s3->hs->next_proto_neg_seen) { + if (hs->next_proto_neg_seen) { /* NPN and ALPN may not be negotiated in the same connection. */ *out_alert = SSL_AD_ILLEGAL_PARAMETER; OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); @@ -1504,11 +1532,12 @@ static int ext_alpn_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert, - const struct ssl_early_callback_ctx *client_hello) { +int ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; CBS contents; if (ssl->ctx->alpn_select_cb == NULL || - !ssl_early_callback_get_extension( + !ssl_client_hello_get_extension( client_hello, &contents, TLSEXT_TYPE_application_layer_protocol_negotiation)) { /* Ignore ALPN if not configured or no extension was supplied. */ @@ -1516,7 +1545,7 @@ int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert, } /* ALPN takes precedence over NPN. */ - ssl->s3->hs->next_proto_neg_seen = 0; + hs->next_proto_neg_seen = 0; CBS protocol_name_list; if (!CBS_get_u16_length_prefixed(&contents, &protocol_name_list) || @@ -1559,7 +1588,8 @@ int ssl_negotiate_alpn(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { +static int ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->s3->alpn_selected == NULL) { return 1; } @@ -1583,11 +1613,12 @@ static int ext_alpn_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 */ -static void ext_channel_id_init(SSL *ssl) { - ssl->s3->tlsext_channel_id_valid = 0; +static void ext_channel_id_init(SSL_HANDSHAKE *hs) { + hs->ssl->s3->tlsext_channel_id_valid = 0; } -static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { +static int ext_channel_id_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->tlsext_channel_id_enabled || SSL_is_dtls(ssl)) { return 1; @@ -1601,8 +1632,9 @@ static int ext_channel_id_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { +static int ext_channel_id_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1618,8 +1650,9 @@ static int ext_channel_id_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, - CBS *contents) { +static int ext_channel_id_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL || !ssl->tlsext_channel_id_enabled || SSL_is_dtls(ssl)) { @@ -1634,7 +1667,8 @@ static int ext_channel_id_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { +static int ext_channel_id_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (!ssl->s3->tlsext_channel_id_valid) { return 1; } @@ -1653,11 +1687,12 @@ static int ext_channel_id_add_serverhello(SSL *ssl, CBB *out) { * https://tools.ietf.org/html/rfc5764 */ -static void ext_srtp_init(SSL *ssl) { - ssl->srtp_profile = NULL; +static void ext_srtp_init(SSL_HANDSHAKE *hs) { + hs->ssl->srtp_profile = NULL; } -static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { +static int ext_srtp_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; STACK_OF(SRTP_PROTECTION_PROFILE) *profiles = SSL_get_srtp_profiles(ssl); if (profiles == NULL) { return 1; @@ -1689,8 +1724,9 @@ static int ext_srtp_add_clienthello(SSL *ssl, CBB *out) { return 1; } -static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_srtp_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1736,8 +1772,9 @@ static int ext_srtp_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 0; } -static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_srtp_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; if (contents == NULL) { return 1; } @@ -1779,7 +1816,8 @@ static int ext_srtp_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { +static int ext_srtp_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl->srtp_profile == NULL) { return 1; } @@ -1802,7 +1840,7 @@ static int ext_srtp_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/rfc4492#section-5.1.2 */ -static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { +static int ext_ec_point_add_extension(SSL_HANDSHAKE *hs, CBB *out) { CBB contents, formats; if (!CBB_add_u16(out, TLSEXT_TYPE_ec_point_formats) || !CBB_add_u16_length_prefixed(out, &contents) || @@ -1815,9 +1853,9 @@ static int ext_ec_point_add_extension(SSL *ssl, CBB *out) { return 1; } -static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) { +static int ext_ec_point_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { uint16_t min_version, max_version; - if (!ssl_get_version_range(ssl, &min_version, &max_version)) { + if (!ssl_get_version_range(hs->ssl, &min_version, &max_version)) { return 0; } @@ -1826,16 +1864,16 @@ static int ext_ec_point_add_clienthello(SSL *ssl, CBB *out) { return 1; } - return ext_ec_point_add_extension(ssl, out); + return ext_ec_point_add_extension(hs, out); } -static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_ec_point_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; } - if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) { return 0; } @@ -1856,16 +1894,17 @@ static int ext_ec_point_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -static int ext_ec_point_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_ec_point_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { - if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + if (ssl3_protocol_version(hs->ssl) >= TLS1_3_VERSION) { return 1; } - return ext_ec_point_parse_serverhello(ssl, out_alert, contents); + return ext_ec_point_parse_serverhello(hs, out_alert, contents); } -static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { +static int ext_ec_point_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { return 1; } @@ -1878,7 +1917,7 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { return 1; } - return ext_ec_point_add_extension(ssl, out); + return ext_ec_point_add_extension(hs, out); } @@ -1886,7 +1925,8 @@ static int ext_ec_point_add_serverhello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.6 */ -static size_t ext_pre_shared_key_clienthello_length(SSL *ssl) { +static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -1906,7 +1946,8 @@ static size_t ext_pre_shared_key_clienthello_length(SSL *ssl) { return 15 + ssl->session->tlsext_ticklen + binder_len; } -static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) { +static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -1946,11 +1987,12 @@ static int ext_pre_shared_key_add_clienthello(SSL *ssl, CBB *out) { return 0; } - ssl->s3->hs->needs_psk_binder = 1; + hs->needs_psk_binder = 1; return CBB_flush(out); } -int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert, +int ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { uint16_t psk_id; if (!CBS_get_u16(contents, &psk_id) || @@ -1970,18 +2012,20 @@ int ssl_ext_pre_shared_key_parse_serverhello(SSL *ssl, uint8_t *out_alert, return 1; } -int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl, +int ssl_ext_pre_shared_key_parse_clienthello(SSL_HANDSHAKE *hs, SSL_SESSION **out_session, CBS *out_binders, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; /* We only process the first PSK identity since we don't support pure PSK. */ uint32_t obfuscated_ticket_age; - CBS identity, ticket, binders; - if (!CBS_get_u16_length_prefixed(contents, &identity) || - !CBS_get_u16_length_prefixed(&identity, &ticket) || - !CBS_get_u32(&identity, &obfuscated_ticket_age) || + CBS identities, ticket, binders; + if (!CBS_get_u16_length_prefixed(contents, &identities) || + !CBS_get_u16_length_prefixed(&identities, &ticket) || + !CBS_get_u32(&identities, &obfuscated_ticket_age) || !CBS_get_u16_length_prefixed(contents, &binders) || + CBS_len(&binders) == 0 || CBS_len(contents) != 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); *out_alert = SSL_AD_DECODE_ERROR; @@ -1990,11 +2034,38 @@ int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl, *out_binders = binders; - /* The PSK identity must have a corresponding binder. */ - CBS binder; - if (!CBS_get_u8_length_prefixed(&binders, &binder)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - *out_alert = SSL_AD_DECODE_ERROR; + /* Check the syntax of the remaining identities, but do not process them. */ + size_t num_identities = 1; + while (CBS_len(&identities) != 0) { + CBS unused_ticket; + uint32_t unused_obfuscated_ticket_age; + if (!CBS_get_u16_length_prefixed(&identities, &unused_ticket) || + !CBS_get_u32(&identities, &unused_obfuscated_ticket_age)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + num_identities++; + } + + /* Check the syntax of the binders. The value will be checked later if + * resuming. */ + size_t num_binders = 0; + while (CBS_len(&binders) != 0) { + CBS binder; + if (!CBS_get_u8_length_prefixed(&binders, &binder)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + num_binders++; + } + + if (num_identities != num_binders) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_BINDER_COUNT_MISMATCH); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } @@ -2013,8 +2084,8 @@ int ssl_ext_pre_shared_key_parse_clienthello(SSL *ssl, return 1; } -int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) { - if (!ssl->s3->session_reused) { +int ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + if (!hs->ssl->s3->session_reused) { return 1; } @@ -2034,7 +2105,10 @@ int ssl_ext_pre_shared_key_add_serverhello(SSL *ssl, CBB *out) { /* Pre-Shared Key Exchange Modes * * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.7 */ -static int ext_psk_key_exchange_modes_add_clienthello(SSL *ssl, CBB *out) { + +static int ext_psk_key_exchange_modes_add_clienthello(SSL_HANDSHAKE *hs, + CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -2055,7 +2129,7 @@ static int ext_psk_key_exchange_modes_add_clienthello(SSL *ssl, CBB *out) { return CBB_flush(out); } -static int ext_psk_key_exchange_modes_parse_clienthello(SSL *ssl, +static int ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, CBS *contents) { if (contents == NULL) { @@ -2071,18 +2145,49 @@ static int ext_psk_key_exchange_modes_parse_clienthello(SSL *ssl, } /* We only support tickets with PSK_DHE_KE. */ - ssl->s3->hs->accept_psk_mode = + hs->accept_psk_mode = memchr(CBS_data(&ke_modes), SSL_PSK_DHE_KE, CBS_len(&ke_modes)) != NULL; return 1; } +/* Early Data Indication + * + * https://tools.ietf.org/html/draft-ietf-tls-tls13-18#section-4.2.8 */ + +static int ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + /* TODO(svaldez): Support 0RTT. */ + return 1; +} + +static int ext_early_data_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; + if (contents == NULL) { + return 1; + } + + if (CBS_len(contents) != 0) { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + /* Since we don't currently accept 0-RTT, we have to skip past any early data + * the client might have sent. */ + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + ssl->s3->skip_early_data = 1; + } + return 1; +} + + /* Key Share * * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.5 */ -static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { +static int ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -2099,18 +2204,18 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { return 0; } - uint16_t group_id = ssl->s3->hs->retry_group; - if (ssl->s3->hs->received_hello_retry_request) { + uint16_t group_id = hs->retry_group; + if (hs->received_hello_retry_request) { /* We received a HelloRetryRequest without a new curve, so there is no new * share to append. Leave |ecdh_ctx| as-is. */ if (group_id == 0 && - !CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes, - ssl->s3->hs->key_share_bytes_len)) { + !CBB_add_bytes(&kse_bytes, hs->key_share_bytes, + hs->key_share_bytes_len)) { return 0; } - OPENSSL_free(ssl->s3->hs->key_share_bytes); - ssl->s3->hs->key_share_bytes = NULL; - ssl->s3->hs->key_share_bytes_len = 0; + OPENSSL_free(hs->key_share_bytes); + hs->key_share_bytes = NULL; + hs->key_share_bytes_len = 0; if (group_id == 0) { return CBB_flush(out); } @@ -2139,19 +2244,18 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { CBB key_exchange; if (!CBB_add_u16(&kse_bytes, group_id) || !CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || - !SSL_ECDH_CTX_init(&ssl->s3->hs->ecdh_ctx, group_id) || - !SSL_ECDH_CTX_offer(&ssl->s3->hs->ecdh_ctx, &key_exchange) || + !SSL_ECDH_CTX_init(&hs->ecdh_ctx, group_id) || + !SSL_ECDH_CTX_offer(&hs->ecdh_ctx, &key_exchange) || !CBB_flush(&kse_bytes)) { return 0; } - if (!ssl->s3->hs->received_hello_retry_request) { + if (!hs->received_hello_retry_request) { /* Save the contents of the extension to repeat it in the second * ClientHello. */ - ssl->s3->hs->key_share_bytes_len = CBB_len(&kse_bytes); - ssl->s3->hs->key_share_bytes = BUF_memdup(CBB_data(&kse_bytes), - CBB_len(&kse_bytes)); - if (ssl->s3->hs->key_share_bytes == NULL) { + hs->key_share_bytes_len = CBB_len(&kse_bytes); + hs->key_share_bytes = BUF_memdup(CBB_data(&kse_bytes), CBB_len(&kse_bytes)); + if (hs->key_share_bytes == NULL) { return 0; } } @@ -2159,9 +2263,10 @@ static int ext_key_share_add_clienthello(SSL *ssl, CBB *out) { return CBB_flush(out); } -int ssl_ext_key_share_parse_serverhello(SSL *ssl, uint8_t **out_secret, +int ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, CBS *contents) { + SSL *const ssl = hs->ssl; CBS peer_key; uint16_t group_id; if (!CBS_get_u16(contents, &group_id) || @@ -2171,31 +2276,30 @@ int ssl_ext_key_share_parse_serverhello(SSL *ssl, uint8_t **out_secret, return 0; } - if (SSL_ECDH_CTX_get_id(&ssl->s3->hs->ecdh_ctx) != group_id) { + if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) != group_id) { *out_alert = SSL_AD_ILLEGAL_PARAMETER; OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); return 0; } - if (!SSL_ECDH_CTX_finish(&ssl->s3->hs->ecdh_ctx, out_secret, out_secret_len, - out_alert, CBS_data(&peer_key), - CBS_len(&peer_key))) { + if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, out_secret, out_secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key))) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } ssl->s3->new_session->key_exchange_info = group_id; - SSL_ECDH_CTX_cleanup(&ssl->s3->hs->ecdh_ctx); + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); return 1; } -int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, +int ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, int *out_found, uint8_t **out_secret, size_t *out_secret_len, uint8_t *out_alert, CBS *contents) { uint16_t group_id; CBS key_shares; - if (!tls1_get_shared_group(ssl, &group_id)) { + if (!tls1_get_shared_group(hs, &group_id)) { OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_GROUP); *out_alert = SSL_AD_HANDSHAKE_FAILURE; return 0; @@ -2247,11 +2351,9 @@ int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, CBB public_key; if (!CBB_init(&public_key, 32) || !SSL_ECDH_CTX_init(&group, group_id) || - !SSL_ECDH_CTX_accept(&group, &public_key, &secret, &secret_len, - out_alert, CBS_data(&peer_key), - CBS_len(&peer_key)) || - !CBB_finish(&public_key, &ssl->s3->hs->public_key, - &ssl->s3->hs->public_key_len)) { + !SSL_ECDH_CTX_accept(&group, &public_key, &secret, &secret_len, out_alert, + CBS_data(&peer_key), CBS_len(&peer_key)) || + !CBB_finish(&public_key, &hs->public_key, &hs->public_key_len)) { OPENSSL_free(secret); SSL_ECDH_CTX_cleanup(&group); CBB_cleanup(&public_key); @@ -2267,23 +2369,23 @@ int ssl_ext_key_share_parse_clienthello(SSL *ssl, int *out_found, return 1; } -int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) { +int ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t group_id; CBB kse_bytes, public_key; - if (!tls1_get_shared_group(ssl, &group_id) || + if (!tls1_get_shared_group(hs, &group_id) || !CBB_add_u16(out, TLSEXT_TYPE_key_share) || !CBB_add_u16_length_prefixed(out, &kse_bytes) || !CBB_add_u16(&kse_bytes, group_id) || !CBB_add_u16_length_prefixed(&kse_bytes, &public_key) || - !CBB_add_bytes(&public_key, ssl->s3->hs->public_key, - ssl->s3->hs->public_key_len) || + !CBB_add_bytes(&public_key, hs->public_key, hs->public_key_len) || !CBB_flush(out)) { return 0; } - OPENSSL_free(ssl->s3->hs->public_key); - ssl->s3->hs->public_key = NULL; - ssl->s3->hs->public_key_len = 0; + OPENSSL_free(hs->public_key); + hs->public_key = NULL; + hs->public_key_len = 0; ssl->s3->new_session->key_exchange_info = group_id; return 1; @@ -2294,7 +2396,8 @@ int ssl_ext_key_share_add_serverhello(SSL *ssl, CBB *out) { * * 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) { +static int ext_supported_versions_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; uint16_t min_version, max_version; if (!ssl_get_version_range(ssl, &min_version, &max_version)) { return 0; @@ -2335,8 +2438,8 @@ static int ext_supported_versions_add_clienthello(SSL *ssl, CBB *out) { * * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.2 */ -static int ext_cookie_add_clienthello(SSL *ssl, CBB *out) { - if (ssl->s3->hs->cookie == NULL) { +static int ext_cookie_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + if (hs->cookie == NULL) { return 1; } @@ -2344,15 +2447,15 @@ static int ext_cookie_add_clienthello(SSL *ssl, CBB *out) { if (!CBB_add_u16(out, TLSEXT_TYPE_cookie) || !CBB_add_u16_length_prefixed(out, &contents) || !CBB_add_u16_length_prefixed(&contents, &cookie) || - !CBB_add_bytes(&cookie, ssl->s3->hs->cookie, ssl->s3->hs->cookie_len) || + !CBB_add_bytes(&cookie, hs->cookie, hs->cookie_len) || !CBB_flush(out)) { return 0; } /* The cookie is no longer needed in memory. */ - OPENSSL_free(ssl->s3->hs->cookie); - ssl->s3->hs->cookie = NULL; - ssl->s3->hs->cookie_len = 0; + OPENSSL_free(hs->cookie); + hs->cookie = NULL; + hs->cookie_len = 0; return 1; } @@ -2362,7 +2465,8 @@ static int ext_cookie_add_clienthello(SSL *ssl, CBB *out) { * https://tools.ietf.org/html/rfc4492#section-5.1.2 * https://tools.ietf.org/html/draft-ietf-tls-tls13-16#section-4.2.4 */ -static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) { +static int ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; CBB contents, groups_bytes; if (!CBB_add_u16(out, TLSEXT_TYPE_supported_groups) || !CBB_add_u16_length_prefixed(out, &contents) || @@ -2390,14 +2494,16 @@ static int ext_supported_groups_add_clienthello(SSL *ssl, CBB *out) { return CBB_flush(out); } -static int ext_supported_groups_parse_serverhello(SSL *ssl, uint8_t *out_alert, +static int ext_supported_groups_parse_serverhello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { /* This extension is not expected to be echoed by servers in TLS 1.2, but some * BigIP servers send it nonetheless, so do not enforce this. */ return 1; } -static int ext_supported_groups_parse_clienthello(SSL *ssl, uint8_t *out_alert, +static int ext_supported_groups_parse_clienthello(SSL_HANDSHAKE *hs, + uint8_t *out_alert, CBS *contents) { if (contents == NULL) { return 1; @@ -2411,9 +2517,9 @@ static int ext_supported_groups_parse_clienthello(SSL *ssl, uint8_t *out_alert, return 0; } - ssl->s3->hs->peer_supported_group_list = OPENSSL_malloc( - CBS_len(&supported_group_list)); - if (ssl->s3->hs->peer_supported_group_list == NULL) { + hs->peer_supported_group_list = + OPENSSL_malloc(CBS_len(&supported_group_list)); + if (hs->peer_supported_group_list == NULL) { *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } @@ -2421,24 +2527,24 @@ static int ext_supported_groups_parse_clienthello(SSL *ssl, uint8_t *out_alert, const size_t num_groups = CBS_len(&supported_group_list) / 2; for (size_t i = 0; i < num_groups; i++) { if (!CBS_get_u16(&supported_group_list, - &ssl->s3->hs->peer_supported_group_list[i])) { + &hs->peer_supported_group_list[i])) { goto err; } } assert(CBS_len(&supported_group_list) == 0); - ssl->s3->hs->peer_supported_group_list_len = num_groups; + hs->peer_supported_group_list_len = num_groups; return 1; err: - OPENSSL_free(ssl->s3->hs->peer_supported_group_list); - ssl->s3->hs->peer_supported_group_list = NULL; + OPENSSL_free(hs->peer_supported_group_list); + hs->peer_supported_group_list = NULL; *out_alert = SSL_AD_INTERNAL_ERROR; return 0; } -static int ext_supported_groups_add_serverhello(SSL *ssl, CBB *out) { +static int ext_supported_groups_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { /* Servers don't echo this extension. */ return 1; } @@ -2561,6 +2667,14 @@ static const struct tls_extension kExtensions[] = { dont_add_serverhello, }, { + TLSEXT_TYPE_early_data, + NULL, + ext_early_data_add_clienthello, + forbid_parse_serverhello, + ext_early_data_parse_clienthello, + dont_add_serverhello, + }, + { TLSEXT_TYPE_supported_versions, NULL, ext_supported_versions_add_clienthello, @@ -2617,9 +2731,10 @@ int SSL_extension_supported(unsigned extension_value) { tls_extension_find(&index, extension_value) != NULL; } -int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { - /* don't add extensions for SSLv3 unless doing secure renegotiation */ - if (ssl->client_version == SSL3_VERSION && +int ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len) { + SSL *const ssl = hs->ssl; + /* Don't add extensions for SSLv3 unless doing secure renegotiation. */ + if (hs->client_version == SSL3_VERSION && !ssl->s3->send_connection_binding) { return 1; } @@ -2629,12 +2744,12 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { goto err; } - ssl->s3->hs->extensions.sent = 0; - ssl->s3->hs->custom_extensions.sent = 0; + hs->extensions.sent = 0; + hs->custom_extensions.sent = 0; for (size_t i = 0; i < kNumExtensions; i++) { if (kExtensions[i].init != NULL) { - kExtensions[i].init(ssl); + kExtensions[i].init(hs); } } @@ -2650,18 +2765,18 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { for (size_t i = 0; i < kNumExtensions; i++) { const size_t len_before = CBB_len(&extensions); - if (!kExtensions[i].add_clienthello(ssl, &extensions)) { + if (!kExtensions[i].add_clienthello(hs, &extensions)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); goto err; } if (CBB_len(&extensions) != len_before) { - ssl->s3->hs->extensions.sent |= (1u << i); + hs->extensions.sent |= (1u << i); } } - if (!custom_ext_add_clienthello(ssl, &extensions)) { + if (!custom_ext_add_clienthello(hs, &extensions)) { goto err; } @@ -2684,7 +2799,7 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { } if (!SSL_is_dtls(ssl)) { - size_t psk_extension_len = ext_pre_shared_key_clienthello_length(ssl); + size_t psk_extension_len = ext_pre_shared_key_clienthello_length(hs); header_len += 2 + CBB_len(&extensions) + psk_extension_len; if (header_len > 0xff && header_len < 0x200) { /* Add padding to workaround bugs in F5 terminators. See RFC 7685. @@ -2714,7 +2829,7 @@ int ssl_add_clienthello_tlsext(SSL *ssl, CBB *out, size_t header_len) { } /* The PSK extension must be last, including after the padding. */ - if (!ext_pre_shared_key_add_clienthello(ssl, &extensions)) { + if (!ext_pre_shared_key_add_clienthello(hs, &extensions)) { goto err; } @@ -2730,27 +2845,27 @@ err: return 0; } -int ssl_add_serverhello_tlsext(SSL *ssl, CBB *out) { +int ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out) { + SSL *const ssl = hs->ssl; CBB extensions; if (!CBB_add_u16_length_prefixed(out, &extensions)) { goto err; } - unsigned i; - for (i = 0; i < kNumExtensions; i++) { - if (!(ssl->s3->hs->extensions.received & (1u << i))) { + for (unsigned i = 0; i < kNumExtensions; i++) { + if (!(hs->extensions.received & (1u << i))) { /* Don't send extensions that were not received. */ continue; } - if (!kExtensions[i].add_serverhello(ssl, &extensions)) { + if (!kExtensions[i].add_serverhello(hs, &extensions)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_ADDING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); goto err; } } - if (!custom_ext_add_serverhello(ssl, &extensions)) { + if (!custom_ext_add_serverhello(hs, &extensions)) { goto err; } @@ -2767,17 +2882,18 @@ err: return 0; } -static int ssl_scan_clienthello_tlsext( - SSL *ssl, const struct ssl_early_callback_ctx *client_hello, - int *out_alert) { +static int ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello, + int *out_alert) { + SSL *const ssl = hs->ssl; for (size_t i = 0; i < kNumExtensions; i++) { if (kExtensions[i].init != NULL) { - kExtensions[i].init(ssl); + kExtensions[i].init(hs); } } - ssl->s3->hs->extensions.received = 0; - ssl->s3->hs->custom_extensions.received = 0; + hs->extensions.received = 0; + hs->custom_extensions.received = 0; CBS extensions; CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len); @@ -2803,16 +2919,16 @@ static int ssl_scan_clienthello_tlsext( tls_extension_find(&ext_index, type); if (ext == NULL) { - if (!custom_ext_parse_clienthello(ssl, out_alert, type, &extension)) { + if (!custom_ext_parse_clienthello(hs, out_alert, type, &extension)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); return 0; } continue; } - ssl->s3->hs->extensions.received |= (1u << ext_index); + hs->extensions.received |= (1u << ext_index); uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_clienthello(ssl, &alert, &extension)) { + if (!ext->parse_clienthello(hs, &alert, &extension)) { *out_alert = alert; OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)type); @@ -2821,7 +2937,7 @@ static int ssl_scan_clienthello_tlsext( } for (size_t i = 0; i < kNumExtensions; i++) { - if (ssl->s3->hs->extensions.received & (1u << i)) { + if (hs->extensions.received & (1u << i)) { continue; } @@ -2835,13 +2951,13 @@ static int ssl_scan_clienthello_tlsext( CBS_init(&fake_contents, kFakeRenegotiateExtension, sizeof(kFakeRenegotiateExtension)); contents = &fake_contents; - ssl->s3->hs->extensions.received |= (1u << i); + hs->extensions.received |= (1u << i); } /* Extension wasn't observed so call the callback with a NULL * parameter. */ uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_clienthello(ssl, &alert, contents)) { + if (!kExtensions[i].parse_clienthello(hs, &alert, contents)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); *out_alert = alert; @@ -2852,15 +2968,16 @@ static int ssl_scan_clienthello_tlsext( return 1; } -int ssl_parse_clienthello_tlsext( - SSL *ssl, const struct ssl_early_callback_ctx *client_hello) { +int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, + const SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; int alert = -1; - if (ssl_scan_clienthello_tlsext(ssl, client_hello, &alert) <= 0) { + if (ssl_scan_clienthello_tlsext(hs, client_hello, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; } - if (ssl_check_clienthello_tlsext(ssl) <= 0) { + if (ssl_check_clienthello_tlsext(hs) <= 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_TLSEXT); return 0; } @@ -2870,7 +2987,9 @@ int ssl_parse_clienthello_tlsext( OPENSSL_COMPILE_ASSERT(kNumExtensions <= sizeof(uint32_t) * 8, too_many_bits); -static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { +static int ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs, + int *out_alert) { + SSL *const ssl = hs->ssl; /* Before TLS 1.3, ServerHello extensions blocks may be omitted if empty. */ if (CBS_len(cbs) == 0 && ssl3_protocol_version(ssl) < TLS1_3_VERSION) { return 1; @@ -2901,13 +3020,13 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { tls_extension_find(&ext_index, type); if (ext == NULL) { - if (!custom_ext_parse_serverhello(ssl, out_alert, type, &extension)) { + if (!custom_ext_parse_serverhello(hs, out_alert, type, &extension)) { return 0; } continue; } - if (!(ssl->s3->hs->extensions.sent & (1u << ext_index)) && + if (!(hs->extensions.sent & (1u << ext_index)) && type != TLSEXT_TYPE_renegotiate) { /* If the extension was never sent then it is illegal, except for the * renegotiation extension which, in SSL 3.0, is signaled via SCSV. */ @@ -2920,7 +3039,7 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { received |= (1u << ext_index); uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ext->parse_serverhello(ssl, &alert, &extension)) { + if (!ext->parse_serverhello(hs, &alert, &extension)) { OPENSSL_PUT_ERROR(SSL, SSL_R_ERROR_PARSING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)type); *out_alert = alert; @@ -2933,7 +3052,7 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { /* Extension wasn't observed so call the callback with a NULL * parameter. */ uint8_t alert = SSL_AD_DECODE_ERROR; - if (!kExtensions[i].parse_serverhello(ssl, &alert, NULL)) { + if (!kExtensions[i].parse_serverhello(hs, &alert, NULL)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION); ERR_add_error_dataf("extension %u", (unsigned)kExtensions[i].value); *out_alert = alert; @@ -2945,7 +3064,8 @@ static int ssl_scan_serverhello_tlsext(SSL *ssl, CBS *cbs, int *out_alert) { return 1; } -static int ssl_check_clienthello_tlsext(SSL *ssl) { +static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = SSL_TLSEXT_ERR_NOACK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -2967,7 +3087,7 @@ static int ssl_check_clienthello_tlsext(SSL *ssl) { return 1; case SSL_TLSEXT_ERR_NOACK: - ssl->s3->hs->should_ack_sni = 0; + hs->should_ack_sni = 0; return 1; default: @@ -2975,7 +3095,8 @@ static int ssl_check_clienthello_tlsext(SSL *ssl) { } } -static int ssl_check_serverhello_tlsext(SSL *ssl) { +static int ssl_check_serverhello_tlsext(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = SSL_TLSEXT_ERR_OK; int al = SSL_AD_UNRECOGNIZED_NAME; @@ -3001,14 +3122,15 @@ static int ssl_check_serverhello_tlsext(SSL *ssl) { } } -int ssl_parse_serverhello_tlsext(SSL *ssl, CBS *cbs) { +int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) { + SSL *const ssl = hs->ssl; int alert = -1; - if (ssl_scan_serverhello_tlsext(ssl, cbs, &alert) <= 0) { + if (ssl_scan_serverhello_tlsext(hs, cbs, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; } - if (ssl_check_serverhello_tlsext(ssl) <= 0) { + if (ssl_check_serverhello_tlsext(hs) <= 0) { OPENSSL_PUT_ERROR(SSL, SSL_R_SERVERHELLO_TLSEXT); return 0; } @@ -3146,13 +3268,12 @@ done: return ret; } -int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { +int tls1_parse_peer_sigalgs(SSL_HANDSHAKE *hs, const CBS *in_sigalgs) { /* Extension ignored for inappropriate versions */ - if (ssl3_protocol_version(ssl) < TLS1_2_VERSION) { + if (ssl3_protocol_version(hs->ssl) < TLS1_2_VERSION) { return 1; } - SSL_HANDSHAKE *hs = ssl->s3->hs; OPENSSL_free(hs->peer_sigalgs); hs->peer_sigalgs = NULL; hs->num_peer_sigalgs = 0; @@ -3188,9 +3309,9 @@ int tls1_parse_peer_sigalgs(SSL *ssl, const CBS *in_sigalgs) { return 1; } -int tls1_choose_signature_algorithm(SSL *ssl, uint16_t *out) { +int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) { + SSL *const ssl = hs->ssl; CERT *cert = ssl->cert; - SSL_HANDSHAKE *hs = ssl->s3->hs; /* Before TLS 1.2, the signature algorithm isn't negotiated as part of the * handshake. It is fixed at MD5-SHA1 for RSA and SHA1 for ECDSA. */ @@ -3448,7 +3569,8 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) { return -1; } - ssl->s3->new_session->original_handshake_hash_len = digest_len; + assert(sizeof(ssl->s3->new_session->original_handshake_hash) < 256); + ssl->s3->new_session->original_handshake_hash_len = (uint8_t)digest_len; return 1; } diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index 97860c41..b7f9c9de 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -65,7 +65,6 @@ OPENSSL_MSVC_PRAGMA(comment(lib, "Ws2_32.lib")) #include "packeted_bio.h" #include "test_config.h" -namespace bssl { #if !defined(OPENSSL_WINDOWS) static int closesocket(int sock) { @@ -246,7 +245,7 @@ static ssl_private_key_result_t AsyncPrivateKeySign( return ssl_private_key_failure; } - ScopedEVP_MD_CTX ctx; + bssl::ScopedEVP_MD_CTX ctx; EVP_PKEY_CTX *pctx; if (!EVP_DigestSignInit(ctx.get(), &pctx, md, nullptr, test_state->private_key.get())) { @@ -438,9 +437,9 @@ static bool InstallCertificate(SSL *ssl) { return true; } -static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) { - const TestConfig *config = GetTestConfig(ctx->ssl); - GetTestState(ctx->ssl)->early_callback_called = true; +static int SelectCertificateCallback(const SSL_CLIENT_HELLO *client_hello) { + const TestConfig *config = GetTestConfig(client_hello->ssl); + GetTestState(client_hello->ssl)->early_callback_called = true; if (!config->expected_server_name.empty()) { const uint8_t *extension_data; @@ -448,9 +447,9 @@ static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) { CBS extension, server_name_list, host_name; uint8_t name_type; - if (!SSL_early_callback_ctx_extension_get(ctx, TLSEXT_TYPE_server_name, - &extension_data, - &extension_len)) { + if (!SSL_early_callback_ctx_extension_get( + client_hello, TLSEXT_TYPE_server_name, &extension_data, + &extension_len)) { fprintf(stderr, "Could not find server_name extension.\n"); return -1; } @@ -483,7 +482,7 @@ static int SelectCertificateCallback(const struct ssl_early_callback_ctx *ctx) { // Install the certificate asynchronously. return 0; } - if (!InstallCertificate(ctx->ssl)) { + if (!InstallCertificate(client_hello->ssl)) { return -1; } } @@ -697,8 +696,8 @@ static SSL_SESSION *GetSessionCallback(SSL *ssl, uint8_t *data, int len, } } -static int DDoSCallback(const struct ssl_early_callback_ctx *early_context) { - const TestConfig *config = GetTestConfig(early_context->ssl); +static int DDoSCallback(const SSL_CLIENT_HELLO *client_hello) { + const TestConfig *config = GetTestConfig(client_hello->ssl); static int callback_num = 0; callback_num++; @@ -981,7 +980,7 @@ static bssl::UniquePtr<SSL_CTX> SetupCtx(const TestConfig *config) { SSL_CTX_set_alpn_select_cb(ssl_ctx.get(), AlpnSelectCallback, NULL); } - SSL_CTX_enable_tls_channel_id(ssl_ctx.get()); + SSL_CTX_set_tls_channel_id_enabled(ssl_ctx.get(), 1); SSL_CTX_set_channel_id_cb(ssl_ctx.get(), ChannelIdCallback); SSL_CTX_set_current_time_cb(ssl_ctx.get(), CurrentTimeCallback); @@ -1520,10 +1519,10 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, } if (!config->expected_channel_id.empty() || config->enable_channel_id) { - SSL_enable_tls_channel_id(ssl.get()); + SSL_set_tls_channel_id_enabled(ssl.get(), 1); } if (!config->send_channel_id.empty()) { - SSL_enable_tls_channel_id(ssl.get()); + SSL_set_tls_channel_id_enabled(ssl.get(), 1); if (!config->async) { // The async case will be supplied by |ChannelIdCallback|. bssl::UniquePtr<EVP_PKEY> pkey = LoadPrivateKey(config->send_channel_id); @@ -1589,9 +1588,6 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, if (!config->check_close_notify) { SSL_set_quiet_shutdown(ssl.get(), 1); } - if (config->disable_npn) { - SSL_set_options(ssl.get(), SSL_OP_DISABLE_NPN); - } if (config->p384_only) { int nid = NID_secp384r1; if (!SSL_set1_curves(ssl.get(), &nid, 1)) { @@ -1873,7 +1869,7 @@ class StderrDelimiter { ~StderrDelimiter() { fprintf(stderr, "--- DONE ---\n"); } }; -static int Main(int argc, char **argv) { +int main(int argc, char **argv) { // To distinguish ASan's output from ours, add a trailing message to stderr. // Anything following this line will be considered an error. StderrDelimiter delimiter; @@ -1941,9 +1937,3 @@ static int Main(int argc, char **argv) { return 0; } - -} // namespace bssl - -int main(int argc, char **argv) { - return bssl::Main(argc, argv); -} diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index a6496fdd..9fbf5dc9 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -1109,6 +1109,25 @@ type ProtocolBugs struct { // copies of each KeyShareEntry. DuplicateKeyShares bool + // SendEarlyAlert, if true, sends a fatal alert after the ClientHello. + SendEarlyAlert bool + + // SendEarlyDataLength, if non-zero, is the amount of early data to send after + // the ClientHello. + SendEarlyDataLength int + + // OmitEarlyDataExtension, if true, causes the early data extension to + // be omitted in the ClientHello. + OmitEarlyDataExtension bool + + // SendEarlyDataOnSecondClientHello, if true, causes the TLS 1.3 client to + // send early data after the second ClientHello. + SendEarlyDataOnSecondClientHello bool + + // InterleaveEarlyData, if true, causes the TLS 1.3 client to send early + // data interleaved with the second ClientHello and the client Finished. + InterleaveEarlyData bool + // EmptyEncryptedExtensions, if true, causes the TLS 1.3 server to // emit an empty EncryptedExtensions block. EmptyEncryptedExtensions bool @@ -1198,6 +1217,10 @@ type ProtocolBugs struct { // SendNoPSKBinder, if true, causes the client to send no PSK binders. SendNoPSKBinder bool + // SendExtraPSKBinder, if true, causes the client to send an extra PSK + // binder. + SendExtraPSKBinder bool + // PSKBinderFirst, if true, causes the client to send the PSK Binder // extension as the first extension instead of the last extension. PSKBinderFirst bool diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index 39c27850..80a5b06d 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -1768,3 +1768,16 @@ func (c *Conn) sendKeyUpdateLocked(keyUpdateRequest byte) error { c.out.doKeyUpdate(c, true) return nil } + +func (c *Conn) sendFakeEarlyData(len int) error { + // Assemble a fake early data record. This does not use writeRecord + // because the record layer may be using different keys at this point. + payload := make([]byte, 5+len) + payload[0] = byte(recordTypeApplicationData) + payload[1] = 3 + payload[2] = 1 + payload[3] = byte(len >> 8) + payload[4] = byte(len) + _, err := c.conn.Write(payload) + return err +} diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index d074778c..7fa7ea21 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -319,6 +319,10 @@ NextCipherSuite: hello.cipherSuites = c.config.Bugs.SendCipherSuites } + if c.config.Bugs.SendEarlyDataLength > 0 && !c.config.Bugs.OmitEarlyDataExtension { + hello.hasEarlyData = true + } + var helloBytes []byte if c.config.Bugs.SendV2ClientHello { // Test that the peer left-pads random. @@ -356,6 +360,12 @@ NextCipherSuite: if err := c.simulatePacketLoss(nil); err != nil { return err } + if c.config.Bugs.SendEarlyAlert { + c.sendAlert(alertHandshakeFailure) + } + if c.config.Bugs.SendEarlyDataLength > 0 { + c.sendFakeEarlyData(c.config.Bugs.SendEarlyDataLength) + } msg, err := c.readHandshake() if err != nil { return err @@ -452,16 +462,28 @@ NextCipherSuite: hello.hasKeyShares = false } - hello.hasEarlyData = false + hello.hasEarlyData = c.config.Bugs.SendEarlyDataOnSecondClientHello hello.raw = nil if len(hello.pskIdentities) > 0 { generatePSKBinders(hello, pskCipherSuite, session.masterSecret, append(helloBytes, helloRetryRequest.marshal()...), c.config) } secondHelloBytes = hello.marshal() - c.writeRecord(recordTypeHandshake, secondHelloBytes) + + if c.config.Bugs.InterleaveEarlyData { + c.sendFakeEarlyData(4) + c.writeRecord(recordTypeHandshake, secondHelloBytes[:16]) + c.sendFakeEarlyData(4) + c.writeRecord(recordTypeHandshake, secondHelloBytes[16:]) + } else { + c.writeRecord(recordTypeHandshake, secondHelloBytes) + } c.flushHandshake() + if c.config.Bugs.SendEarlyDataOnSecondClientHello { + c.sendFakeEarlyData(4) + } + msg, err = c.readHandshake() if err != nil { return err @@ -622,7 +644,6 @@ 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.serverHello.hasPSKIdentity { // We send at most one PSK identity. if hs.session == nil || hs.serverHello.pskIdentity != 0 { @@ -634,21 +655,18 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.sendAlert(alertHandshakeFailure) return errors.New("tls: server resumed an invalid session for the cipher suite") } - psk = hs.session.masterSecret + hs.finishedHash.addEntropy(hs.session.masterSecret) c.didResume = true } else { - psk = zeroSecret + hs.finishedHash.addEntropy(zeroSecret) } - earlySecret := hs.finishedHash.extractKey(zeroSecret, psk) - if !hs.serverHello.hasKeyShare { c.sendAlert(alertUnsupportedExtension) return errors.New("tls: server omitted KeyShare on resumption.") } // Resolve ECDHE and compute the handshake secret. - var ecdheSecret []byte if !c.config.Bugs.MissingKeyShare && !c.config.Bugs.SecondClientHelloMissingKeyShare { curve, ok := hs.keyShares[hs.serverHello.keyShare.group] if !ok { @@ -657,22 +675,19 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { } c.curveID = hs.serverHello.keyShare.group - var err error - ecdheSecret, err = curve.finish(hs.serverHello.keyShare.keyExchange) + ecdheSecret, err := curve.finish(hs.serverHello.keyShare.keyExchange) if err != nil { return err } + hs.finishedHash.addEntropy(ecdheSecret) } else { - ecdheSecret = zeroSecret + hs.finishedHash.addEntropy(zeroSecret) } - // Compute the handshake secret. - handshakeSecret := hs.finishedHash.extractKey(earlySecret, ecdheSecret) - // Switch to handshake traffic keys. - clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel) + clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) c.out.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) - serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel) + serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) c.in.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) msg, err := c.readHandshake() @@ -800,9 +815,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // The various secrets do not incorporate the client's final leg, so // derive them now before updating the handshake context. - masterSecret := hs.finishedHash.extractKey(handshakeSecret, zeroSecret) - clientTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, clientApplicationTrafficLabel) - serverTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, serverApplicationTrafficLabel) + hs.finishedHash.addEntropy(zeroSecret) + clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel) + serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel) if certReq != nil && !c.config.Bugs.SkipClientCertificate { certMsg := &certificateMsg{ @@ -871,6 +886,12 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { if c.config.Bugs.PartialClientFinishedWithClientHello { // The first byte has already been sent. c.writeRecord(recordTypeHandshake, finished.marshal()[1:]) + } else if c.config.Bugs.InterleaveEarlyData { + finishedBytes := finished.marshal() + c.sendFakeEarlyData(4) + c.writeRecord(recordTypeHandshake, finishedBytes[:1]) + c.sendFakeEarlyData(4) + c.writeRecord(recordTypeHandshake, finishedBytes[1:]) } else { c.writeRecord(recordTypeHandshake, finished.marshal()) } @@ -883,8 +904,8 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) - c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel) - c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel) + c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) + c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) return nil } @@ -1648,11 +1669,16 @@ func generatePSKBinders(hello *clientHelloMsg, pskCipherSuite *cipherSuite, psk, binderLen-- } + numBinders := 1 + if config.Bugs.SendExtraPSKBinder { + numBinders++ + } + // Fill hello.pskBinders with appropriate length arrays of zeros so the // length prefixes are correct when computing the binder over the truncated // ClientHello message. - hello.pskBinders = make([][]byte, len(hello.pskIdentities)) - for i := range hello.pskIdentities { + hello.pskBinders = make([][]byte, numBinders) + for i := range hello.pskBinders { hello.pskBinders[i] = make([]byte, binderLen) } diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 67950baa..57566c57 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -501,15 +501,12 @@ Curves: } // Resolve PSK and compute the early secret. - var psk []byte if hs.sessionState != nil { - psk = hs.sessionState.masterSecret + hs.finishedHash.addEntropy(hs.sessionState.masterSecret) } else { - psk = hs.finishedHash.zeroSecret() + hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret()) } - earlySecret := hs.finishedHash.extractKey(hs.finishedHash.zeroSecret(), psk) - hs.hello.hasKeyShare = true if hs.sessionState != nil && config.Bugs.NegotiatePSKResumption { hs.hello.hasKeyShare = false @@ -647,7 +644,6 @@ ResendHelloRetryRequest: } // Resolve ECDHE and compute the handshake secret. - var ecdheSecret []byte if hs.hello.hasKeyShare { // Once a curve has been selected and a key share identified, // the server needs to generate a public value and send it in @@ -672,13 +668,12 @@ ResendHelloRetryRequest: peerKey = selectedKeyShare.keyExchange } - var publicKey []byte - var err error - publicKey, ecdheSecret, err = curve.accept(config.rand(), peerKey) + publicKey, ecdheSecret, err := curve.accept(config.rand(), peerKey) if err != nil { c.sendAlert(alertHandshakeFailure) return err } + hs.finishedHash.addEntropy(ecdheSecret) hs.hello.hasKeyShare = true curveID := selectedCurve @@ -702,7 +697,7 @@ ResendHelloRetryRequest: } } } else { - ecdheSecret = hs.finishedHash.zeroSecret() + hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret()) } // Send unencrypted ServerHello. @@ -718,13 +713,10 @@ ResendHelloRetryRequest: } c.flushHandshake() - // Compute the handshake secret. - handshakeSecret := hs.finishedHash.extractKey(earlySecret, ecdheSecret) - // Switch to handshake traffic keys. - serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, serverHandshakeTrafficLabel) + serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) c.out.useTrafficSecret(c.vers, hs.suite, serverHandshakeTrafficSecret, serverWrite) - clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(handshakeSecret, clientHandshakeTrafficLabel) + clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) c.in.useTrafficSecret(c.vers, hs.suite, clientHandshakeTrafficSecret, clientWrite) // Send EncryptedExtensions. @@ -842,10 +834,10 @@ ResendHelloRetryRequest: // The various secrets do not incorporate the client's final leg, so // derive them now before updating the handshake context. - masterSecret := hs.finishedHash.extractKey(handshakeSecret, hs.finishedHash.zeroSecret()) - clientTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, clientApplicationTrafficLabel) - serverTrafficSecret := hs.finishedHash.deriveSecret(masterSecret, serverApplicationTrafficLabel) - c.exporterSecret = hs.finishedHash.deriveSecret(masterSecret, exporterLabel) + hs.finishedHash.addEntropy(hs.finishedHash.zeroSecret()) + clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel) + serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel) + c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) // Switch to application data keys on write. In particular, any alerts // from the client certificate are sent over these keys. @@ -956,7 +948,7 @@ ResendHelloRetryRequest: c.in.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) c.cipherSuite = hs.suite - c.resumptionSecret = hs.finishedHash.deriveSecret(masterSecret, resumptionLabel) + c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) // TODO(davidben): Allow configuring the number of tickets sent for // testing. diff --git a/src/ssl/test/runner/prf.go b/src/ssl/test/runner/prf.go index c311e995..cfc383dc 100644 --- a/src/ssl/test/runner/prf.go +++ b/src/ssl/test/runner/prf.go @@ -129,14 +129,8 @@ func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, labe return prf30 case VersionTLS10, VersionTLS11: return prf10 - // TODO(nharper): VersionTLS13 is in the case statement below only to - // support Fake TLS 1.3. Real TLS 1.3 should never call this function. - // Once we no longer support Fake TLS 1.3, the VersionTLS13 should be - // removed from this case statement. - case VersionTLS12, VersionTLS13: - if version == VersionTLS12 { - return prf12(suite.hash().New) - } + case VersionTLS12: + return prf12(suite.hash().New) } panic("unknown version") } @@ -197,6 +191,8 @@ func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { if version == VersionTLS12 { ret.prf = prf12(ret.hash.New) + } else { + ret.secret = make([]byte, ret.hash.Size()) } } else { ret.hash = crypto.MD5SHA1 @@ -232,6 +228,9 @@ type finishedHash struct { version uint16 prf func(result, secret, label, seed []byte) + + // secret, in TLS 1.3, is the running input secret. + secret []byte } func (h *finishedHash) Write(msg []byte) (n int, err error) { @@ -370,10 +369,9 @@ func (h *finishedHash) zeroSecret() []byte { return make([]byte, h.hash.Size()) } -// extractKey combines two secrets together with HKDF-Expand in the TLS 1.3 key -// derivation schedule. -func (h *finishedHash) extractKey(salt, ikm []byte) []byte { - return hkdfExtract(h.hash.New, salt, ikm) +// addEntropy incorporates ikm into the running TLS 1.3 secret with HKDF-Expand. +func (h *finishedHash) addEntropy(ikm []byte) { + h.secret = hkdfExtract(h.hash.New, h.secret, ikm) } // hkdfExpandLabel implements TLS 1.3's HKDF-Expand-Label function, as defined @@ -420,8 +418,8 @@ var ( // deriveSecret implements TLS 1.3's Derive-Secret function, as defined in // section 7.1 of draft ietf-tls-tls13-16. -func (h *finishedHash) deriveSecret(secret, label []byte) []byte { - return hkdfExpandLabel(h.hash, secret, label, h.appendContextHashes(nil), h.hash.Size()) +func (h *finishedHash) deriveSecret(label []byte) []byte { + return hkdfExpandLabel(h.hash, h.secret, label, h.appendContextHashes(nil), h.hash.Size()) } // The following are context strings for CertificateVerify in TLS 1.3. @@ -472,8 +470,8 @@ func updateTrafficSecret(hash crypto.Hash, secret []byte) []byte { func computePSKBinder(psk, label []byte, cipherSuite *cipherSuite, transcript, truncatedHello []byte) []byte { finishedHash := newFinishedHash(VersionTLS13, cipherSuite) - earlySecret := finishedHash.extractKey(finishedHash.zeroSecret(), psk) - binderKey := finishedHash.deriveSecret(earlySecret, label) + finishedHash.addEntropy(psk) + binderKey := finishedHash.deriveSecret(label) finishedHash.Write(transcript) finishedHash.Write(truncatedHello) return finishedHash.clientSum(binderKey) diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 683f07cb..15895d62 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -835,6 +835,18 @@ func runTest(test *testCase, shimPath string, mallocNumToFail int64) error { panic("expectResumeRejected without resumeSession in " + test.name) } + for _, ver := range tlsVersions { + if !strings.Contains("-"+test.name+"-", "-"+ver.name+"-") { + continue + } + + if test.config.MaxVersion != 0 || test.config.MinVersion != 0 || test.expectedVersion != 0 { + continue + } + + panic(fmt.Sprintf("The name of test %q suggests that it's version specific, but min/max version in the Config is %x/%x. One of them should probably be %x", test.name, test.config.MinVersion, test.config.MaxVersion, ver.version)) + } + listener, err := net.ListenTCP("tcp4", &net.TCPAddr{IP: net.IP{127, 0, 0, 1}}) if err != nil { panic(err) @@ -4973,20 +4985,6 @@ func addExtensionTests() { shouldFail: true, expectedError: ":NEGOTIATED_BOTH_NPN_AND_ALPN:", }) - - // Test that NPN can be disabled with SSL_OP_DISABLE_NPN. - testCases = append(testCases, testCase{ - name: "DisableNPN-" + ver.name, - config: Config{ - MaxVersion: ver.version, - NextProtos: []string{"foo"}, - }, - flags: []string{ - "-select-next-proto", "foo", - "-disable-npn", - }, - expectNoNextProto: true, - }) } // Test ticket behavior. @@ -5568,7 +5566,7 @@ func addExtensionTests() { "-signed-cert-timestamps", base64.StdEncoding.EncodeToString([]byte{0, 0}), }, - shouldFail: true, + shouldFail: true, expectedError: ":INVALID_SCT_LIST:", }) } @@ -5979,6 +5977,36 @@ func addResumptionVersionTests() { testCases = append(testCases, testCase{ testType: serverTest, + name: "Resume-Server-ExtraPSKBinder", + resumeSession: true, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendExtraPSKBinder: true, + }, + }, + shouldFail: true, + expectedLocalError: "remote error: illegal parameter", + expectedError: ":PSK_IDENTITY_BINDER_COUNT_MISMATCH:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Resume-Server-ExtraIdentityNoBinder", + resumeSession: true, + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + ExtraPSKIdentity: true, + }, + }, + shouldFail: true, + expectedLocalError: "remote error: illegal parameter", + expectedError: ":PSK_IDENTITY_BINDER_COUNT_MISMATCH:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, name: "Resume-Server-InvalidPSKBinder", resumeSession: true, config: Config{ @@ -9033,6 +9061,144 @@ func addTLS13HandshakeTests() { }) testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + }, + }, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-OmitEarlyDataExtension", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + OmitEarlyDataExtension: true, + }, + }, + shouldFail: true, + expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-TooMuchData", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 16384 + 1, + }, + }, + shouldFail: true, + expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-Interleaved", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + InterleaveEarlyData: true, + }, + }, + shouldFail: true, + expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-EarlyDataInTLS12", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + flags: []string{"-max-version", strconv.Itoa(VersionTLS12)}, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-HRR", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + }, + DefaultCurves: []CurveID{}, + }, + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-HRR-Interleaved", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 4, + InterleaveEarlyData: true, + }, + DefaultCurves: []CurveID{}, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_RECORD:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-HRR-TooMuchData", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataLength: 16384 + 1, + }, + DefaultCurves: []CurveID{}, + }, + shouldFail: true, + expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:", + }) + + // Test that skipping early data looking for cleartext correctly + // processes an alert record. + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-HRR-FatalAlert", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyAlert: true, + SendEarlyDataLength: 4, + }, + DefaultCurves: []CurveID{}, + }, + shouldFail: true, + expectedError: ":SSLV3_ALERT_HANDSHAKE_FAILURE:", + }) + + testCases = append(testCases, testCase{ + testType: serverTest, + name: "SkipEarlyData-SecondClientHelloEarlyData", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + SendEarlyDataOnSecondClientHello: true, + }, + DefaultCurves: []CurveID{}, + }, + shouldFail: true, + expectedLocalError: "remote error: bad record MAC", + }) + + testCases = append(testCases, testCase{ testType: clientTest, name: "EmptyEncryptedExtensions", config: Config{ @@ -9364,7 +9530,8 @@ func addTLS13HandshakeTests() { config: Config{ MaxVersion: VersionTLS13, Bugs: ProtocolBugs{ - ExtraPSKIdentity: true, + ExtraPSKIdentity: true, + SendExtraPSKBinder: true, }, }, resumeSession: true, @@ -9559,6 +9726,8 @@ func addCertificateTests() { testType: clientTest, name: "SendReceiveIntermediate-Client-" + ver.name, config: Config{ + MinVersion: ver.version, + MaxVersion: ver.version, Certificates: []Certificate{rsaChainCertificate}, ClientAuth: RequireAnyClientCert, }, @@ -9574,6 +9743,8 @@ func addCertificateTests() { testType: serverTest, name: "SendReceiveIntermediate-Server-" + ver.name, config: Config{ + MinVersion: ver.version, + MaxVersion: ver.version, Certificates: []Certificate{rsaChainCertificate}, }, expectPeerCertificate: &rsaChainCertificate, diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index 940e676e..9b9e20c6 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -97,7 +97,6 @@ const Flag<bool> kBoolFlags[] = { { "-renegotiate-once", &TestConfig::renegotiate_once }, { "-renegotiate-freely", &TestConfig::renegotiate_freely }, { "-renegotiate-ignore", &TestConfig::renegotiate_ignore }, - { "-disable-npn", &TestConfig::disable_npn }, { "-p384-only", &TestConfig::p384_only }, { "-enable-all-curves", &TestConfig::enable_all_curves }, { "-use-sparse-dh-prime", &TestConfig::use_sparse_dh_prime }, diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index ed1a47bd..76cd5fbd 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -102,7 +102,6 @@ struct TestConfig { bool renegotiate_once = false; bool renegotiate_freely = false; bool renegotiate_ignore = false; - bool disable_npn = false; int expect_peer_signature_algorithm = 0; bool p384_only = false; bool enable_all_curves = false; diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c index 17f7161e..ea3eb77d 100644 --- a/src/ssl/tls13_both.c +++ b/src/ssl/tls13_both.c @@ -34,9 +34,8 @@ * without being able to return application data. */ static const uint8_t kMaxKeyUpdates = 32; -int tls13_handshake(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - +int tls13_handshake(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; for (;;) { /* Resolve the operation the handshake was waiting on. */ switch (hs->wait) { @@ -95,7 +94,7 @@ int tls13_handshake(SSL *ssl) { } /* Run the state machine again. */ - hs->wait = hs->do_handshake(ssl); + hs->wait = hs->do_tls13_handshake(hs); if (hs->wait == ssl_hs_error) { /* Don't loop around to avoid a stray |SSL_R_SSL_HANDSHAKE_FAILURE| the * first time around. */ @@ -402,10 +401,11 @@ int tls13_check_message_type(SSL *ssl, int type) { return 1; } -int tls13_process_finished(SSL *ssl) { +int tls13_process_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint8_t verify_data[EVP_MAX_MD_SIZE]; size_t verify_data_len; - if (!tls13_finished_mac(ssl, verify_data, &verify_data_len, !ssl->server)) { + if (!tls13_finished_mac(hs, verify_data, &verify_data_len, !ssl->server)) { return 0; } @@ -424,7 +424,8 @@ int tls13_process_finished(SSL *ssl) { return 1; } -int tls13_prepare_certificate(SSL *ssl) { +int tls13_prepare_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; CBB cbb, body, certificate_list; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CERTIFICATE) || /* The request context is always empty in the handshake. */ @@ -451,7 +452,7 @@ int tls13_prepare_certificate(SSL *ssl) { goto err; } - if (ssl->s3->hs->scts_requested && + if (hs->scts_requested && ssl->ctx->signed_cert_timestamp_list_length != 0) { CBB contents; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) || @@ -464,7 +465,7 @@ int tls13_prepare_certificate(SSL *ssl) { } } - if (ssl->s3->hs->ocsp_stapling_requested && + if (hs->ocsp_stapling_requested && ssl->ctx->ocsp_response_length != 0) { CBB contents, ocsp_response; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) || @@ -501,7 +502,8 @@ err: } enum ssl_private_key_result_t tls13_prepare_certificate_verify( - SSL *ssl, int is_first_run) { + SSL_HANDSHAKE *hs, int is_first_run) { + SSL *const ssl = hs->ssl; enum ssl_private_key_result_t ret = ssl_private_key_failure; uint8_t *msg = NULL; size_t msg_len; @@ -509,7 +511,7 @@ enum ssl_private_key_result_t tls13_prepare_certificate_verify( CBB_zero(&cbb); uint16_t signature_algorithm; - if (!tls1_choose_signature_algorithm(ssl, &signature_algorithm)) { + if (!tls1_choose_signature_algorithm(hs, &signature_algorithm)) { goto err; } if (!ssl->method->init_message(ssl, &cbb, &body, @@ -562,11 +564,12 @@ err: return ret; } -int tls13_prepare_finished(SSL *ssl) { +int tls13_prepare_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; size_t verify_data_len; uint8_t verify_data[EVP_MAX_MD_SIZE]; - if (!tls13_finished_mac(ssl, verify_data, &verify_data_len, ssl->server)) { + if (!tls13_finished_mac(hs, verify_data, &verify_data_len, ssl->server)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DIGEST_CHECK_FAILED); return 0; diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c index 4a30ce3d..7a09fb12 100644 --- a/src/ssl/tls13_client.c +++ b/src/ssl/tls13_client.c @@ -48,8 +48,10 @@ enum client_hs_state_t { state_done, }; -static enum ssl_hs_wait_t do_process_hello_retry_request(SSL *ssl, - SSL_HANDSHAKE *hs) { +static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; + +static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST) { hs->state = state_process_server_hello; return ssl_hs_ok; @@ -140,9 +142,8 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL *ssl, return ssl_hs_ok; } -static enum ssl_hs_wait_t do_send_second_client_hello(SSL *ssl, - SSL_HANDSHAKE *hs) { - if (!ssl_write_client_hello(ssl)) { +static enum ssl_hs_wait_t do_send_second_client_hello(SSL_HANDSHAKE *hs) { + if (!ssl_write_client_hello(hs)) { return ssl_hs_error; } @@ -150,13 +151,13 @@ static enum ssl_hs_wait_t do_send_second_client_hello(SSL *ssl, return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_flush_second_client_hello(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_flush_second_client_hello(SSL_HANDSHAKE *hs) { hs->state = state_process_server_hello; return ssl_hs_flush_and_read_message; } -static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_SERVER_HELLO)) { return ssl_hs_error; } @@ -229,7 +230,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!ssl_ext_pre_shared_key_parse_serverhello(ssl, &alert, + if (!ssl_ext_pre_shared_key_parse_serverhello(hs, &alert, &pre_shared_key)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; @@ -264,7 +265,7 @@ 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)) { + } else if (!ssl_get_new_session(hs, 0)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } @@ -275,33 +276,30 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { /* The PRF hash is now known. Set up the key schedule. */ size_t hash_len = EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl))); + if (!tls13_init_key_schedule(hs)) { + return ssl_hs_error; + } - /* Derive resumption material. */ - uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0}; + /* Incorporate the PSK into the running secret. */ if (ssl->s3->session_reused) { - if (hash_len != (size_t) ssl->s3->new_session->master_key_length) { + if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key, + ssl->s3->new_session->master_key_length)) { return ssl_hs_error; } - memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len); - } - - /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK - * into the running secret. */ - if (!tls13_init_key_schedule(ssl) || - !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) { + } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) { return ssl_hs_error; } /* Resolve ECDHE and incorporate it into the secret. */ uint8_t *dhe_secret; size_t dhe_secret_len; - if (!ssl_ext_key_share_parse_serverhello(ssl, &dhe_secret, &dhe_secret_len, + if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &dhe_secret_len, &alert, &key_share)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; } - if (!tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len)) { + if (!tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len)) { OPENSSL_free(dhe_secret); return ssl_hs_error; } @@ -314,7 +312,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!tls13_set_handshake_traffic(ssl)) { + if (!tls13_set_handshake_traffic(hs)) { return ssl_hs_error; } @@ -322,15 +320,15 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_read_message; } -static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_ENCRYPTED_EXTENSIONS)) { return ssl_hs_error; } CBS cbs; CBS_init(&cbs, ssl->init_msg, ssl->init_num); - if (!ssl_parse_serverhello_tlsext(ssl, &cbs)) { + if (!ssl_parse_serverhello_tlsext(hs, &cbs)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); return ssl_hs_error; } @@ -348,8 +346,8 @@ static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL *ssl, return ssl_hs_read_message; } -static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* CertificateRequest may only be sent in non-resumption handshakes. */ if (ssl->s3->session_reused) { hs->state = state_process_server_finished; @@ -369,7 +367,7 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, CBS_len(&context) != 0 || !CBS_get_u16_length_prefixed(&cbs, &supported_signature_algorithms) || CBS_len(&supported_signature_algorithms) == 0 || - !tls1_parse_peer_sigalgs(ssl, &supported_signature_algorithms)) { + !tls1_parse_peer_sigalgs(hs, &supported_signature_algorithms)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return ssl_hs_error; @@ -392,9 +390,9 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, return ssl_hs_error; } - ssl->s3->hs->cert_request = 1; - sk_X509_NAME_pop_free(ssl->s3->hs->ca_names, X509_NAME_free); - ssl->s3->hs->ca_names = ca_sk; + hs->cert_request = 1; + sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + hs->ca_names = ca_sk; if (!ssl_hash_current_message(ssl)) { return ssl_hs_error; @@ -404,8 +402,8 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL *ssl, return ssl_hs_read_message; } -static enum ssl_hs_wait_t do_process_server_certificate(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE) || !tls13_process_certificate(ssl, 0 /* certificate required */) || !ssl_hash_current_message(ssl)) { @@ -417,7 +415,8 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL *ssl, } static enum ssl_hs_wait_t do_process_server_certificate_verify( - SSL *ssl, SSL_HANDSHAKE *hs) { + SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(ssl) || !ssl_hash_current_message(ssl)) { @@ -428,15 +427,14 @@ static enum ssl_hs_wait_t do_process_server_certificate_verify( return ssl_hs_read_message; } -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}; +static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) || - !tls13_process_finished(ssl) || + !tls13_process_finished(hs) || !ssl_hash_current_message(ssl) || /* Update the secret to the master secret and derive traffic keys. */ - !tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) || - !tls13_derive_application_secrets(ssl)) { + !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || + !tls13_derive_application_secrets(hs)) { return ssl_hs_error; } @@ -445,9 +443,10 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL *ssl, return ssl_hs_ok; } -static enum ssl_hs_wait_t do_certificate_callback(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_certificate_callback(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* The peer didn't request a certificate. */ - if (!ssl->s3->hs->cert_request) { + if (!hs->cert_request) { hs->state = state_send_channel_id; return ssl_hs_ok; } @@ -470,8 +469,8 @@ static enum ssl_hs_wait_t do_certificate_callback(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_ok; } -static enum ssl_hs_wait_t do_send_client_certificate(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* Call client_cert_cb to update the certificate. */ int should_retry; if (!ssl_do_client_cert_cb(ssl, &should_retry)) { @@ -482,7 +481,7 @@ static enum ssl_hs_wait_t do_send_client_certificate(SSL *ssl, return ssl_hs_error; } - if (!tls13_prepare_certificate(ssl)) { + if (!tls13_prepare_certificate(hs)) { return ssl_hs_error; } @@ -490,16 +489,16 @@ static enum ssl_hs_wait_t do_send_client_certificate(SSL *ssl, return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL *ssl, - SSL_HANDSHAKE *hs, +static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs, int is_first_run) { + SSL *const ssl = hs->ssl; /* Don't send CertificateVerify if there is no certificate. */ if (!ssl_has_certificate(ssl)) { hs->state = state_send_channel_id; return ssl_hs_ok; } - switch (tls13_prepare_certificate_verify(ssl, is_first_run)) { + switch (tls13_prepare_certificate_verify(hs, is_first_run)) { case ssl_private_key_success: hs->state = state_send_channel_id; return ssl_hs_write_message; @@ -516,7 +515,8 @@ static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL *ssl, return ssl_hs_error; } -static enum ssl_hs_wait_t do_send_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!ssl->s3->tlsext_channel_id_valid) { hs->state = state_send_client_finished; return ssl_hs_ok; @@ -542,8 +542,8 @@ static enum ssl_hs_wait_t do_send_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) { - if (!tls13_prepare_finished(ssl)) { +static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) { + if (!tls13_prepare_finished(hs)) { return ssl_hs_error; } @@ -551,12 +551,13 @@ static enum ssl_hs_wait_t do_send_client_finished(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_flush(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_traffic_secret_0, hs->hash_len) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->client_traffic_secret_0, hs->hash_len) || - !tls13_derive_resumption_secret(ssl)) { + !tls13_derive_resumption_secret(hs)) { return ssl_hs_error; } @@ -564,60 +565,58 @@ static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_flush; } -enum ssl_hs_wait_t tls13_client_handshake(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - +enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { while (hs->state != state_done) { enum ssl_hs_wait_t ret = ssl_hs_error; enum client_hs_state_t state = hs->state; switch (state) { case state_process_hello_retry_request: - ret = do_process_hello_retry_request(ssl, hs); + ret = do_process_hello_retry_request(hs); break; case state_send_second_client_hello: - ret = do_send_second_client_hello(ssl, hs); + ret = do_send_second_client_hello(hs); break; case state_flush_second_client_hello: - ret = do_flush_second_client_hello(ssl, hs); + ret = do_flush_second_client_hello(hs); break; case state_process_server_hello: - ret = do_process_server_hello(ssl, hs); + ret = do_process_server_hello(hs); break; case state_process_encrypted_extensions: - ret = do_process_encrypted_extensions(ssl, hs); + ret = do_process_encrypted_extensions(hs); break; case state_process_certificate_request: - ret = do_process_certificate_request(ssl, hs); + ret = do_process_certificate_request(hs); break; case state_process_server_certificate: - ret = do_process_server_certificate(ssl, hs); + ret = do_process_server_certificate(hs); break; case state_process_server_certificate_verify: - ret = do_process_server_certificate_verify(ssl, hs); + ret = do_process_server_certificate_verify(hs); break; case state_process_server_finished: - ret = do_process_server_finished(ssl, hs); + ret = do_process_server_finished(hs); break; case state_certificate_callback: - ret = do_certificate_callback(ssl, hs); + ret = do_certificate_callback(hs); break; case state_send_client_certificate: - ret = do_send_client_certificate(ssl, hs); + ret = do_send_client_certificate(hs); break; case state_send_client_certificate_verify: - ret = do_send_client_certificate_verify(ssl, hs, 1 /* first run */); + ret = do_send_client_certificate_verify(hs, 1 /* first run */); break; case state_complete_client_certificate_verify: - ret = do_send_client_certificate_verify(ssl, hs, 0 /* complete */); + ret = do_send_client_certificate_verify(hs, 0 /* complete */); break; case state_send_channel_id: - ret = do_send_channel_id(ssl, hs); + ret = do_send_channel_id(hs); break; case state_send_client_finished: - ret = do_send_client_finished(ssl, hs); + ret = do_send_client_finished(hs); break; case state_flush: - ret = do_flush(ssl, hs); + ret = do_flush(hs); break; case state_done: ret = ssl_hs_ok; @@ -669,10 +668,10 @@ int tls13_process_new_session_ticket(SSL *ssl) { return 1; } -void ssl_clear_tls13_state(SSL *ssl) { - SSL_ECDH_CTX_cleanup(&ssl->s3->hs->ecdh_ctx); +void ssl_clear_tls13_state(SSL_HANDSHAKE *hs) { + SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); - OPENSSL_free(ssl->s3->hs->key_share_bytes); - ssl->s3->hs->key_share_bytes = NULL; - ssl->s3->hs->key_share_bytes_len = 0; + OPENSSL_free(hs->key_share_bytes); + hs->key_share_bytes = NULL; + hs->key_share_bytes_len = 0; } diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c index d87d8a6f..4fca65bb 100644 --- a/src/ssl/tls13_enc.c +++ b/src/ssl/tls13_enc.c @@ -27,8 +27,8 @@ #include "internal.h" -int tls13_init_key_schedule(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; +int tls13_init_key_schedule(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); hs->hash_len = EVP_MD_size(digest); @@ -44,9 +44,10 @@ int tls13_init_key_schedule(SSL *ssl) { return 1; } -int tls13_advance_key_schedule(SSL *ssl, const uint8_t *in, size_t len) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); +int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in, + size_t len) { + const EVP_MD *digest = + ssl_get_handshake_digest(ssl_get_algorithm_prf(hs->ssl)); return HKDF_extract(hs->secret, &hs->hash_len, digest, in, len, hs->secret, hs->hash_len); @@ -97,9 +98,9 @@ int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) { /* derive_secret derives a secret of length |len| and writes the result in |out| * with the given label and the current base secret and most recently-saved * handshake context. It returns one on success and zero on error. */ -static int derive_secret(SSL *ssl, uint8_t *out, size_t len, +static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len, const uint8_t *label, size_t label_len) { - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL *const ssl = hs->ssl; const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); uint8_t context_hash[EVP_MAX_MD_SIZE]; @@ -184,17 +185,16 @@ static const char kTLS13LabelClientApplicationTraffic[] = static const char kTLS13LabelServerApplicationTraffic[] = "server application traffic secret"; -int tls13_set_handshake_traffic(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - +int tls13_set_handshake_traffic(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; uint8_t client_traffic_secret[EVP_MAX_MD_SIZE]; uint8_t server_traffic_secret[EVP_MAX_MD_SIZE]; - if (!derive_secret(ssl, client_traffic_secret, hs->hash_len, + if (!derive_secret(hs, client_traffic_secret, hs->hash_len, (const uint8_t *)kTLS13LabelClientHandshakeTraffic, strlen(kTLS13LabelClientHandshakeTraffic)) || !ssl_log_secret(ssl, "CLIENT_HANDSHAKE_TRAFFIC_SECRET", client_traffic_secret, hs->hash_len) || - !derive_secret(ssl, server_traffic_secret, hs->hash_len, + !derive_secret(hs, server_traffic_secret, hs->hash_len, (const uint8_t *)kTLS13LabelServerHandshakeTraffic, strlen(kTLS13LabelServerHandshakeTraffic)) || !ssl_log_secret(ssl, "SERVER_HANDSHAKE_TRAFFIC_SECRET", @@ -222,21 +222,20 @@ int tls13_set_handshake_traffic(SSL *ssl) { static const char kTLS13LabelExporter[] = "exporter master secret"; -int tls13_derive_application_secrets(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - +int tls13_derive_application_secrets(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; ssl->s3->exporter_secret_len = hs->hash_len; - return derive_secret(ssl, hs->client_traffic_secret_0, hs->hash_len, + return derive_secret(hs, hs->client_traffic_secret_0, hs->hash_len, (const uint8_t *)kTLS13LabelClientApplicationTraffic, strlen(kTLS13LabelClientApplicationTraffic)) && ssl_log_secret(ssl, "CLIENT_TRAFFIC_SECRET_0", hs->client_traffic_secret_0, hs->hash_len) && - derive_secret(ssl, hs->server_traffic_secret_0, hs->hash_len, + derive_secret(hs, hs->server_traffic_secret_0, hs->hash_len, (const uint8_t *)kTLS13LabelServerApplicationTraffic, strlen(kTLS13LabelServerApplicationTraffic)) && ssl_log_secret(ssl, "SERVER_TRAFFIC_SECRET_0", hs->server_traffic_secret_0, hs->hash_len) && - derive_secret(ssl, ssl->s3->exporter_secret, hs->hash_len, + derive_secret(hs, ssl->s3->exporter_secret, hs->hash_len, (const uint8_t *)kTLS13LabelExporter, strlen(kTLS13LabelExporter)); } @@ -269,9 +268,15 @@ int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) { static const char kTLS13LabelResumption[] = "resumption master secret"; -int tls13_derive_resumption_secret(SSL *ssl) { - ssl->s3->new_session->master_key_length = ssl->s3->hs->hash_len; - return derive_secret(ssl, ssl->s3->new_session->master_key, +int tls13_derive_resumption_secret(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (ssl->s3->hs->hash_len > SSL_MAX_MASTER_KEY_LENGTH) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + ssl->s3->new_session->master_key_length = hs->hash_len; + return derive_secret(hs, ssl->s3->new_session->master_key, ssl->s3->new_session->master_key_length, (const uint8_t *)kTLS13LabelResumption, strlen(kTLS13LabelResumption)); @@ -297,8 +302,9 @@ static int tls13_verify_data(const EVP_MD *digest, uint8_t *out, return 1; } -int tls13_finished_mac(SSL *ssl, uint8_t *out, size_t *out_len, int is_server) { - SSL_HANDSHAKE *hs = ssl->s3->hs; +int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, + int is_server) { + SSL *const ssl = hs->ssl; const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); const uint8_t *traffic_secret; diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c index 83ef6795..626d2ee8 100644 --- a/src/ssl/tls13_server.c +++ b/src/ssl/tls13_server.c @@ -53,14 +53,15 @@ enum server_hs_state_t { static const uint8_t kZeroes[EVP_MAX_MD_SIZE] = {0}; -static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry, - struct ssl_early_callback_ctx *early_ctx) { +static int resolve_ecdhe_secret(SSL_HANDSHAKE *hs, int *out_need_retry, + SSL_CLIENT_HELLO *client_hello) { + SSL *const ssl = hs->ssl; *out_need_retry = 0; /* 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)) { + if (!ssl_client_hello_get_extension(client_hello, &key_share, + TLSEXT_TYPE_key_share)) { OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_KEY_SHARE); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_MISSING_EXTENSION); return 0; @@ -70,7 +71,7 @@ static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry, uint8_t *dhe_secret; size_t dhe_secret_len; uint8_t alert = SSL_AD_DECODE_ERROR; - if (!ssl_ext_key_share_parse_clienthello(ssl, &found_key_share, &dhe_secret, + if (!ssl_ext_key_share_parse_clienthello(hs, &found_key_share, &dhe_secret, &dhe_secret_len, &alert, &key_share)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); @@ -82,19 +83,20 @@ static int resolve_ecdhe_secret(SSL *ssl, int *out_need_retry, return 0; } - int ok = tls13_advance_key_schedule(ssl, dhe_secret, dhe_secret_len); + int ok = tls13_advance_key_schedule(hs, dhe_secret, dhe_secret_len); OPENSSL_free(dhe_secret); return ok; } -static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { return ssl_hs_error; } - struct ssl_early_callback_ctx client_hello; - if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg, - ssl->init_num)) { + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; @@ -118,7 +120,7 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { } /* TLS extensions. */ - if (!ssl_parse_clienthello_tlsext(ssl, &client_hello)) { + if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) { OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); return ssl_hs_error; } @@ -128,7 +130,7 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { } static const SSL_CIPHER *choose_tls13_cipher( - const SSL *ssl, const struct ssl_early_callback_ctx *client_hello) { + const SSL *ssl, const SSL_CLIENT_HELLO *client_hello) { if (client_hello->cipher_suites_len % 2 != 0) { return NULL; } @@ -173,7 +175,8 @@ static const SSL_CIPHER *choose_tls13_cipher( return best; } -static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* Call |cert_cb| to update server certificates if required. */ if (ssl->cert->cert_cb != NULL) { int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); @@ -188,9 +191,9 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { } } - struct ssl_early_callback_ctx client_hello; - if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg, - ssl->init_num)) { + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; @@ -209,8 +212,8 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { SSL_SESSION *session = NULL; CBS pre_shared_key, binders; if (hs->accept_psk_mode && - ssl_early_callback_get_extension(&client_hello, &pre_shared_key, - TLSEXT_TYPE_pre_shared_key)) { + ssl_client_hello_get_extension(&client_hello, &pre_shared_key, + TLSEXT_TYPE_pre_shared_key)) { /* Verify that the pre_shared_key extension is the last extension in * ClientHello. */ if (CBS_data(&pre_shared_key) + CBS_len(&pre_shared_key) != @@ -220,7 +223,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!ssl_ext_pre_shared_key_parse_clienthello(ssl, &session, &binders, + if (!ssl_ext_pre_shared_key_parse_clienthello(hs, &session, &binders, &alert, &pre_shared_key)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; @@ -236,7 +239,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { /* Set up the new session, either using the original one as a template or * creating a fresh one. */ if (session == NULL) { - if (!ssl_get_new_session(ssl, 1 /* server */)) { + if (!ssl_get_new_session(hs, 1 /* server */)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } @@ -244,8 +247,8 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { ssl->s3->new_session->cipher = ssl->s3->tmp.new_cipher; /* On new sessions, stash the SNI value in the session. */ - if (ssl->s3->hs->hostname != NULL) { - ssl->s3->new_session->tlsext_hostname = BUF_strdup(ssl->s3->hs->hostname); + if (hs->hostname != NULL) { + ssl->s3->new_session->tlsext_hostname = BUF_strdup(hs->hostname); if (ssl->s3->new_session->tlsext_hostname == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; @@ -279,28 +282,25 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was * deferred. Complete it now. */ - if (!ssl_negotiate_alpn(ssl, &alert, &client_hello)) { + if (!ssl_negotiate_alpn(hs, &alert, &client_hello)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; } - /* The PRF hash is now known. */ + /* The PRF hash is now known. Set up the key schedule. */ size_t hash_len = EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl))); + if (!tls13_init_key_schedule(hs)) { + return ssl_hs_error; + } - /* Derive resumption material. */ - uint8_t psk_secret[EVP_MAX_MD_SIZE] = {0}; + /* Incorporate the PSK into the running secret. */ if (ssl->s3->session_reused) { - if (hash_len != (size_t) ssl->s3->new_session->master_key_length) { + if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key, + ssl->s3->new_session->master_key_length)) { return ssl_hs_error; } - memcpy(psk_secret, ssl->s3->new_session->master_key, hash_len); - } - - /* Set up the key schedule, hash in the ClientHello, and incorporate the PSK - * into the running secret. */ - if (!tls13_init_key_schedule(ssl) || - !tls13_advance_key_schedule(ssl, psk_secret, hash_len)) { + } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) { return ssl_hs_error; } @@ -308,7 +308,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { /* Resolve ECDHE and incorporate it into the secret. */ int need_retry; - if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) { + if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) { if (need_retry) { hs->state = state_send_hello_retry_request; return ssl_hs_ok; @@ -320,14 +320,14 @@ static enum ssl_hs_wait_t do_select_parameters(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_ok; } -static enum ssl_hs_wait_t do_send_hello_retry_request(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_hello_retry_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; CBB cbb, body, extensions; uint16_t group_id; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_HELLO_RETRY_REQUEST) || !CBB_add_u16(&body, ssl->version) || - !tls1_get_shared_group(ssl, &group_id) || + !tls1_get_shared_group(hs, &group_id) || !CBB_add_u16_length_prefixed(&body, &extensions) || !CBB_add_u16(&extensions, TLSEXT_TYPE_key_share) || !CBB_add_u16(&extensions, 2 /* length */) || @@ -341,28 +341,27 @@ static enum ssl_hs_wait_t do_send_hello_retry_request(SSL *ssl, return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_flush_hello_retry_request(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_flush_hello_retry_request(SSL_HANDSHAKE *hs) { hs->state = state_process_second_client_hello; return ssl_hs_flush_and_read_message; } -static enum ssl_hs_wait_t do_process_second_client_hello(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { return ssl_hs_error; } - struct ssl_early_callback_ctx client_hello; - if (!ssl_early_callback_init(ssl, &client_hello, ssl->init_msg, - ssl->init_num)) { + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { OPENSSL_PUT_ERROR(SSL, SSL_R_CLIENTHELLO_PARSE_FAILED); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return ssl_hs_error; } int need_retry; - if (!resolve_ecdhe_secret(ssl, &need_retry, &client_hello)) { + if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) { if (need_retry) { /* Only send one HelloRetryRequest. */ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); @@ -380,7 +379,8 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL *ssl, return ssl_hs_ok; } -static enum ssl_hs_wait_t do_send_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; CBB cbb, body, extensions; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) || !CBB_add_u16(&body, ssl->version) || @@ -388,8 +388,8 @@ static enum ssl_hs_wait_t do_send_server_hello(SSL *ssl, SSL_HANDSHAKE *hs) { !CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) || !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_ext_pre_shared_key_add_serverhello(hs, &extensions) || + !ssl_ext_key_share_add_serverhello(hs, &extensions) || !ssl_complete_message(ssl, &cbb)) { goto err; } @@ -402,16 +402,16 @@ err: return ssl_hs_error; } -static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl, - SSL_HANDSHAKE *hs) { - if (!tls13_set_handshake_traffic(ssl)) { +static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!tls13_set_handshake_traffic(hs)) { return ssl_hs_error; } CBB cbb, body; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_ENCRYPTED_EXTENSIONS) || - !ssl_add_serverhello_tlsext(ssl, &body) || + !ssl_add_serverhello_tlsext(hs, &body) || !ssl_complete_message(ssl, &cbb)) { CBB_cleanup(&cbb); return ssl_hs_error; @@ -421,16 +421,16 @@ static enum ssl_hs_wait_t do_send_encrypted_extensions(SSL *ssl, return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_send_certificate_request(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_certificate_request(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* Determine whether to request a client certificate. */ - ssl->s3->hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); + hs->cert_request = !!(ssl->verify_mode & SSL_VERIFY_PEER); /* CertificateRequest may only be sent in non-resumption handshakes. */ if (ssl->s3->session_reused) { - ssl->s3->hs->cert_request = 0; + hs->cert_request = 0; } - if (!ssl->s3->hs->cert_request) { + if (!hs->cert_request) { /* Skip this state. */ hs->state = state_send_server_certificate; return ssl_hs_ok; @@ -469,8 +469,8 @@ err: return ssl_hs_error; } -static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->s3->session_reused) { hs->state = state_send_server_finished; return ssl_hs_ok; @@ -481,7 +481,7 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl, return ssl_hs_error; } - if (!tls13_prepare_certificate(ssl)) { + if (!tls13_prepare_certificate(hs)) { return ssl_hs_error; } @@ -489,10 +489,9 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL *ssl, return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL *ssl, - SSL_HANDSHAKE *hs, +static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL_HANDSHAKE *hs, int is_first_run) { - switch (tls13_prepare_certificate_verify(ssl, is_first_run)) { + switch (tls13_prepare_certificate_verify(hs, is_first_run)) { case ssl_private_key_success: hs->state = state_send_server_finished; return ssl_hs_write_message; @@ -509,8 +508,8 @@ static enum ssl_hs_wait_t do_send_server_certificate_verify(SSL *ssl, return ssl_hs_error; } -static enum ssl_hs_wait_t do_send_server_finished(SSL *ssl, SSL_HANDSHAKE *hs) { - if (!tls13_prepare_finished(ssl)) { +static enum ssl_hs_wait_t do_send_server_finished(SSL_HANDSHAKE *hs) { + if (!tls13_prepare_finished(hs)) { return ssl_hs_error; } @@ -518,10 +517,11 @@ static enum ssl_hs_wait_t do_send_server_finished(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_write_message; } -static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_flush(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* Update the secret to the master secret and derive traffic keys. */ - if (!tls13_advance_key_schedule(ssl, kZeroes, hs->hash_len) || - !tls13_derive_application_secrets(ssl) || + if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || + !tls13_derive_application_secrets(hs) || !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_traffic_secret_0, hs->hash_len)) { return ssl_hs_error; @@ -531,9 +531,9 @@ static enum ssl_hs_wait_t do_flush(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_flush_and_read_message; } -static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl, - SSL_HANDSHAKE *hs) { - if (!ssl->s3->hs->cert_request) { +static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!hs->cert_request) { /* OpenSSL returns X509_V_OK when no certificates are requested. This is * classed by them as a bug, but it's assumed by at least NGINX. */ ssl->s3->new_session->verify_result = X509_V_OK; @@ -563,7 +563,8 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL *ssl, } static enum ssl_hs_wait_t do_process_client_certificate_verify( - SSL *ssl, SSL_HANDSHAKE *hs) { + SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (ssl->s3->new_session->x509_peer == NULL) { /* Skip this state. */ hs->state = state_process_channel_id; @@ -580,7 +581,8 @@ static enum ssl_hs_wait_t do_process_client_certificate_verify( return ssl_hs_read_message; } -static enum ssl_hs_wait_t do_process_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!ssl->s3->tlsext_channel_id_valid) { hs->state = state_process_client_finished; return ssl_hs_ok; @@ -596,15 +598,15 @@ static enum ssl_hs_wait_t do_process_channel_id(SSL *ssl, SSL_HANDSHAKE *hs) { return ssl_hs_read_message; } -static enum ssl_hs_wait_t do_process_client_finished(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; if (!tls13_check_message_type(ssl, SSL3_MT_FINISHED) || - !tls13_process_finished(ssl) || + !tls13_process_finished(hs) || !ssl_hash_current_message(ssl) || /* evp_aead_seal keys have already been switched. */ !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0, hs->hash_len) || - !tls13_derive_resumption_secret(ssl)) { + !tls13_derive_resumption_secret(hs)) { return ssl_hs_error; } @@ -621,8 +623,8 @@ static enum ssl_hs_wait_t do_process_client_finished(SSL *ssl, * client makes several connections before getting a renewal. */ static const int kNumTickets = 2; -static enum ssl_hs_wait_t do_send_new_session_ticket(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_send_new_session_ticket(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* If the client doesn't accept resumption with PSK_DHE_KE, don't send a * session ticket. */ if (!hs->accept_psk_mode) { @@ -674,75 +676,72 @@ err: return ssl_hs_error; } -static enum ssl_hs_wait_t do_flush_new_session_tickets(SSL *ssl, - SSL_HANDSHAKE *hs) { +static enum ssl_hs_wait_t do_flush_new_session_tickets(SSL_HANDSHAKE *hs) { hs->state = state_done; return ssl_hs_flush; } -enum ssl_hs_wait_t tls13_server_handshake(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; - +enum ssl_hs_wait_t tls13_server_handshake(SSL_HANDSHAKE *hs) { while (hs->state != state_done) { enum ssl_hs_wait_t ret = ssl_hs_error; enum server_hs_state_t state = hs->state; switch (state) { case state_process_client_hello: - ret = do_process_client_hello(ssl, hs); + ret = do_process_client_hello(hs); break; case state_select_parameters: - ret = do_select_parameters(ssl, hs); + ret = do_select_parameters(hs); break; case state_send_hello_retry_request: - ret = do_send_hello_retry_request(ssl, hs); + ret = do_send_hello_retry_request(hs); break; case state_flush_hello_retry_request: - ret = do_flush_hello_retry_request(ssl, hs); + ret = do_flush_hello_retry_request(hs); break; case state_process_second_client_hello: - ret = do_process_second_client_hello(ssl, hs); + ret = do_process_second_client_hello(hs); break; case state_send_server_hello: - ret = do_send_server_hello(ssl, hs); + ret = do_send_server_hello(hs); break; case state_send_encrypted_extensions: - ret = do_send_encrypted_extensions(ssl, hs); + ret = do_send_encrypted_extensions(hs); break; case state_send_certificate_request: - ret = do_send_certificate_request(ssl, hs); + ret = do_send_certificate_request(hs); break; case state_send_server_certificate: - ret = do_send_server_certificate(ssl, hs); + ret = do_send_server_certificate(hs); break; case state_send_server_certificate_verify: - ret = do_send_server_certificate_verify(ssl, hs, 1 /* first run */); + ret = do_send_server_certificate_verify(hs, 1 /* first run */); break; case state_complete_server_certificate_verify: - ret = do_send_server_certificate_verify(ssl, hs, 0 /* complete */); + ret = do_send_server_certificate_verify(hs, 0 /* complete */); break; case state_send_server_finished: - ret = do_send_server_finished(ssl, hs); + ret = do_send_server_finished(hs); break; case state_flush: - ret = do_flush(ssl, hs); + ret = do_flush(hs); break; case state_process_client_certificate: - ret = do_process_client_certificate(ssl, hs); + ret = do_process_client_certificate(hs); break; case state_process_client_certificate_verify: - ret = do_process_client_certificate_verify(ssl, hs); + ret = do_process_client_certificate_verify(hs); break; case state_process_channel_id: - ret = do_process_channel_id(ssl, hs); + ret = do_process_channel_id(hs); break; case state_process_client_finished: - ret = do_process_client_finished(ssl, hs); + ret = do_process_client_finished(hs); break; case state_send_new_session_ticket: - ret = do_send_new_session_ticket(ssl, hs); + ret = do_send_new_session_ticket(hs); break; case state_flush_new_session_tickets: - ret = do_flush_new_session_tickets(ssl, hs); + ret = do_flush_new_session_tickets(hs); break; case state_done: ret = ssl_hs_ok; diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c index ce42904b..9effb363 100644 --- a/src/ssl/tls_method.c +++ b/src/ssl/tls_method.c @@ -97,6 +97,12 @@ static uint16_t ssl3_version_to_wire(uint16_t version) { return 0; } +static int ssl3_supports_cipher(const SSL_CIPHER *cipher) { return 1; } + +static void ssl3_expect_flight(SSL *ssl) {} + +static void ssl3_received_flight(SSL *ssl) {} + static int ssl3_set_read_state(SSL *ssl, SSL_AEAD_CTX *aead_ctx) { if (ssl->s3->rrec.length != 0) { /* There may not be unprocessed record data at a cipher change. */ diff --git a/src/ssl/tls_record.c b/src/ssl/tls_record.c index 59319225..c52909ce 100644 --- a/src/ssl/tls_record.c +++ b/src/ssl/tls_record.c @@ -125,6 +125,12 @@ * forever. */ static const uint8_t kMaxEmptyRecords = 32; +/* kMaxEarlyDataSkipped is the maximum amount of data processed when skipping + * over early data. Without this limit an attacker could send records at a + * faster rate than we can process and cause trial decryption to loop + * forever. */ +static const size_t kMaxEarlyDataSkipped = 16384; + /* kMaxWarningAlerts is the number of consecutive warning alerts that will be * processed. */ static const uint8_t kMaxWarningAlerts = 4; @@ -246,15 +252,32 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, in, SSL3_RT_HEADER_LENGTH); + *out_consumed = in_len - CBS_len(&cbs); + + /* Skip early data received when expecting a second ClientHello if we rejected + * 0RTT. */ + if (ssl->s3->skip_early_data && + ssl->s3->aead_read_ctx == NULL && + type == SSL3_RT_APPLICATION_DATA) { + goto skipped_data; + } + /* Decrypt the body in-place. */ if (!SSL_AEAD_CTX_open(ssl->s3->aead_read_ctx, out, type, version, ssl->s3->read_sequence, (uint8_t *)CBS_data(&body), CBS_len(&body))) { + if (ssl->s3->skip_early_data && + ssl->s3->aead_read_ctx != NULL) { + ERR_clear_error(); + goto skipped_data; + } + OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC); *out_alert = SSL_AD_BAD_RECORD_MAC; return ssl_open_record_error; } - *out_consumed = in_len - CBS_len(&cbs); + + ssl->s3->skip_early_data = 0; if (!ssl_record_sequence_update(ssl->s3->read_sequence, 8)) { *out_alert = SSL_AD_INTERNAL_ERROR; @@ -310,6 +333,20 @@ enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type, CBS *out, *out_type = type; return ssl_open_record_success; + +skipped_data: + ssl->s3->early_data_skipped += *out_consumed; + if (ssl->s3->early_data_skipped < *out_consumed) { + ssl->s3->early_data_skipped = kMaxEarlyDataSkipped + 1; + } + + if (ssl->s3->early_data_skipped > kMaxEarlyDataSkipped) { + OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA); + *out_alert = SSL_AD_UNEXPECTED_MESSAGE; + return ssl_open_record_error; + } + + return ssl_open_record_discard; } static int do_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, diff --git a/src/tool/server.cc b/src/tool/server.cc index d0213e9e..a049422e 100644 --- a/src/tool/server.cc +++ b/src/tool/server.cc @@ -15,6 +15,7 @@ #include <openssl/base.h> #include <openssl/err.h> +#include <openssl/rand.h> #include <openssl/ssl.h> #include "internal.h" @@ -40,7 +41,9 @@ static const struct argument kArguments[] = { }, { "-key", kOptionalArgument, - "Private-key file to use (default is server.pem)", + "PEM-encoded file containing the private key, leaf certificate and " + "optional certificate chain. A self-signed certificate is generated " + "at runtime if this argument is not provided.", }, { "-ocsp-response", kOptionalArgument, @@ -91,6 +94,49 @@ out: return ret; } +static bssl::UniquePtr<EVP_PKEY> MakeKeyPairForSelfSignedCert() { + bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); + if (!ec_key || !EC_KEY_generate_key(ec_key.get())) { + fprintf(stderr, "Failed to generate key pair.\n"); + return nullptr; + } + bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new()); + if (!evp_pkey || !EVP_PKEY_assign_EC_KEY(evp_pkey.get(), ec_key.release())) { + fprintf(stderr, "Failed to assign key pair.\n"); + return nullptr; + } + return evp_pkey; +} + +static bssl::UniquePtr<X509> MakeSelfSignedCert(EVP_PKEY *evp_pkey, + const int valid_days) { + bssl::UniquePtr<X509> x509(X509_new()); + uint32_t serial; + RAND_bytes(reinterpret_cast<uint8_t*>(&serial), sizeof(serial)); + ASN1_INTEGER_set(X509_get_serialNumber(x509.get()), serial >> 1); + X509_gmtime_adj(X509_get_notBefore(x509.get()), 0); + X509_gmtime_adj(X509_get_notAfter(x509.get()), 60 * 60 * 24 * valid_days); + + X509_NAME* subject = X509_get_subject_name(x509.get()); + X509_NAME_add_entry_by_txt(subject, "C", MBSTRING_ASC, + reinterpret_cast<const uint8_t *>("US"), -1, -1, + 0); + X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC, + reinterpret_cast<const uint8_t *>("BoringSSL"), -1, + -1, 0); + X509_set_issuer_name(x509.get(), subject); + + if (!X509_set_pubkey(x509.get(), evp_pkey)) { + fprintf(stderr, "Failed to set public key.\n"); + return nullptr; + } + if (!X509_sign(x509.get(), evp_pkey, EVP_sha256())) { + fprintf(stderr, "Failed to sign certificate.\n"); + return nullptr; + } + return x509; +} + bool Server(const std::vector<std::string> &args) { if (!InitSocketLibrary()) { return false; @@ -107,17 +153,34 @@ bool Server(const std::vector<std::string> &args) { SSL_CTX_set_options(ctx.get(), SSL_OP_NO_SSLv3); // Server authentication is required. - std::string key_file = "server.pem"; if (args_map.count("-key") != 0) { - key_file = args_map["-key"]; - } - if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key_file.c_str(), SSL_FILETYPE_PEM)) { - fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str()); - return false; - } - if (!SSL_CTX_use_certificate_chain_file(ctx.get(), key_file.c_str())) { - fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str()); - return false; + std::string key_file = args_map["-key"]; + if (!SSL_CTX_use_PrivateKey_file(ctx.get(), key_file.c_str(), SSL_FILETYPE_PEM)) { + fprintf(stderr, "Failed to load private key: %s\n", key_file.c_str()); + return false; + } + if (!SSL_CTX_use_certificate_chain_file(ctx.get(), key_file.c_str())) { + fprintf(stderr, "Failed to load cert chain: %s\n", key_file.c_str()); + return false; + } + } else { + bssl::UniquePtr<EVP_PKEY> evp_pkey = MakeKeyPairForSelfSignedCert(); + if (!evp_pkey) { + return false; + } + bssl::UniquePtr<X509> cert = + MakeSelfSignedCert(evp_pkey.get(), 365 /* valid_days */); + if (!cert) { + return false; + } + if (!SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get())) { + fprintf(stderr, "Failed to set private key.\n"); + return false; + } + if (!SSL_CTX_use_certificate(ctx.get(), cert.get())) { + fprintf(stderr, "Failed to set certificate.\n"); + return false; + } } if (args_map.count("-cipher") != 0 && diff --git a/src/tool/speed.cc b/src/tool/speed.cc index f16a9ebc..5fd1058e 100644 --- a/src/tool/speed.cc +++ b/src/tool/speed.cc @@ -654,6 +654,12 @@ bool Speed(const std::vector<std::string> &args) { kLegacyADLen, selected) || !SpeedAEAD(EVP_aead_aes_256_cbc_sha1_tls(), "AES-256-CBC-SHA1", kLegacyADLen, selected) || +#if !defined(OPENSSL_SMALL) + !SpeedAEAD(EVP_aead_aes_128_gcm_siv(), "AES-128-GCM-SIV", kTLSADLen, + selected) || + !SpeedAEAD(EVP_aead_aes_256_gcm_siv(), "AES-256-GCM-SIV", kTLSADLen, + selected) || +#endif !SpeedHash(EVP_sha1(), "SHA-1", selected) || !SpeedHash(EVP_sha256(), "SHA-256", selected) || !SpeedHash(EVP_sha512(), "SHA-512", selected) || diff --git a/src/util/all_tests.json b/src/util/all_tests.json index d2e39ce1..5ffa5e81 100644 --- a/src/util/all_tests.json +++ b/src/util/all_tests.json @@ -8,6 +8,8 @@ ["crypto/chacha/chacha_test"], ["crypto/cipher/aead_test", "aes-128-gcm", "crypto/cipher/test/aes_128_gcm_tests.txt"], ["crypto/cipher/aead_test", "aes-256-gcm", "crypto/cipher/test/aes_256_gcm_tests.txt"], + ["crypto/cipher/aead_test", "aes-128-gcm-siv", "crypto/cipher/test/aes_128_gcm_siv_tests.txt"], + ["crypto/cipher/aead_test", "aes-256-gcm-siv", "crypto/cipher/test/aes_256_gcm_siv_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/bot/DEPS b/src/util/bot/DEPS index 0452d552..5036c0c1 100644 --- a/src/util/bot/DEPS +++ b/src/util/bot/DEPS @@ -104,8 +104,6 @@ hooks = [ 'boringssl/util/bot/update_clang.py', ], }, - # TODO(davidben): Only extract archives when they've changed. Extracting perl - # on Windows is a significant part of the cycle time. { 'name': 'cmake_linux64_extract', 'pattern': '.', diff --git a/src/util/bot/extract.py b/src/util/bot/extract.py index 77603c0e..e36ce99b 100644 --- a/src/util/bot/extract.py +++ b/src/util/bot/extract.py @@ -15,6 +15,7 @@ """Extracts archives.""" +import hashlib import optparse import os import os.path @@ -78,6 +79,22 @@ def main(args): # Skip archives that weren't downloaded. return 0 + with open(archive) as f: + sha256 = hashlib.sha256() + while True: + chunk = f.read(1024 * 1024) + if not chunk: + break + sha256.update(chunk) + digest = sha256.hexdigest() + + stamp_path = os.path.join(output, ".boringssl_archive_digest") + if os.path.exists(stamp_path): + with open(stamp_path) as f: + if f.read().strip() == digest: + print "Already up-to-date." + return 0 + if archive.endswith('.zip'): entries = IterateZip(archive) elif archive.endswith('.tar.gz'): @@ -129,9 +146,10 @@ def main(args): finally: entries.close() - if num_extracted % 100 == 0: - print "Done. Extracted %d files." % (num_extracted,) + with open(stamp_path, 'w') as f: + f.write(digest) + print "Done. Extracted %d files." % (num_extracted,) return 0 |