diff options
62 files changed, 2196 insertions, 1952 deletions
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION index 14bbebce..f26983b6 100644 --- a/BORINGSSL_REVISION +++ b/BORINGSSL_REVISION @@ -1 +1 @@ -ab20cec1c1de815de8da6cc74c2503460efd6e1c +040bc4944be97f5d4b44da176f6e801fc804a176 diff --git a/linux-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S b/linux-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S index 241d7d02..c7e673fc 100644 --- a/linux-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S +++ b/linux-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S @@ -2,6 +2,9 @@ .text .extern OPENSSL_ia32cap_P .hidden OPENSSL_ia32cap_P + +chacha20_poly1305_constants: + .align 64 .chacha20_consts: .byte 'e','x','p','a','n','d',' ','3','2','-','b','y','t','e',' ','k' diff --git a/mac-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S b/mac-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S index 4e5c0f35..03cd8725 100644 --- a/mac-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S +++ b/mac-x86_64/crypto/cipher/chacha20_poly1305_x86_64.S @@ -1,6 +1,9 @@ #if defined(__x86_64__) .text + +chacha20_poly1305_constants: + .p2align 6 .chacha20_consts: .byte 'e','x','p','a','n','d',' ','3','2','-','b','y','t','e',' ','k' @@ -408,7 +408,6 @@ cc_defaults { "src/ssl/handshake_client.c", "src/ssl/handshake_server.c", "src/ssl/s3_both.c", - "src/ssl/s3_enc.c", "src/ssl/s3_lib.c", "src/ssl/s3_pkt.c", "src/ssl/ssl_aead_ctx.c", @@ -419,10 +418,11 @@ cc_defaults { "src/ssl/ssl_ecdh.c", "src/ssl/ssl_file.c", "src/ssl/ssl_lib.c", - "src/ssl/ssl_rsa.c", - "src/ssl/ssl_rsa_cc.cc", + "src/ssl/ssl_privkey.c", + "src/ssl/ssl_privkey_cc.cc", "src/ssl/ssl_session.c", "src/ssl/ssl_stat.c", + "src/ssl/ssl_transcript.c", "src/ssl/ssl_x509.c", "src/ssl/t1_enc.c", "src/ssl/t1_lib.c", diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 36224fc1..bbc68d00 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -214,6 +214,7 @@ add_executable( dh/dh_test.cc dsa/dsa_test.cc + err/err_test.cc $<TARGET_OBJECTS:gtest_main> $<TARGET_OBJECTS:test_support> diff --git a/src/crypto/bn/asm/rsaz-avx2.pl b/src/crypto/bn/asm/rsaz-avx2.pl index 73db3c2b..b8e830e2 100755 --- a/src/crypto/bn/asm/rsaz-avx2.pl +++ b/src/crypto/bn/asm/rsaz-avx2.pl @@ -804,6 +804,7 @@ $code.=<<___; mov %rbp, %rax ___ $code.=<<___ if ($win64); +.Lsqr_1024_in_tail: movaps -0xd8(%rax),%xmm6 movaps -0xc8(%rax),%xmm7 movaps -0xb8(%rax),%xmm8 @@ -1437,6 +1438,7 @@ $code.=<<___; mov %rbp, %rax ___ $code.=<<___ if ($win64); +.Lmul_1024_in_tail: movaps -0xd8(%rax),%xmm6 movaps -0xc8(%rax),%xmm7 movaps -0xb8(%rax),%xmm8 @@ -1792,14 +1794,17 @@ rsaz_se_handler: cmp %r10,%rbx # context->Rip<prologue label jb .Lcommon_seh_tail - mov 152($context),%rax # pull context->Rsp - mov 4(%r11),%r10d # HandlerData[1] lea (%rsi,%r10),%r10 # epilogue label cmp %r10,%rbx # context->Rip>=epilogue label jae .Lcommon_seh_tail - mov 160($context),%rax # pull context->Rbp + mov 160($context),%rbp # pull context->Rbp + + mov 8(%r11),%r10d # HandlerData[2] + lea (%rsi,%r10),%r10 # "in tail" label + cmp %r10,%rbx # context->Rip>="in tail" label + cmovc %rbp,%rax mov -48(%rax),%r15 mov -40(%rax),%r14 @@ -1877,11 +1882,13 @@ rsaz_se_handler: .LSEH_info_rsaz_1024_sqr_avx2: .byte 9,0,0,0 .rva rsaz_se_handler - .rva .Lsqr_1024_body,.Lsqr_1024_epilogue + .rva .Lsqr_1024_body,.Lsqr_1024_epilogue,.Lsqr_1024_in_tail + .long 0 .LSEH_info_rsaz_1024_mul_avx2: .byte 9,0,0,0 .rva rsaz_se_handler - .rva .Lmul_1024_body,.Lmul_1024_epilogue + .rva .Lmul_1024_body,.Lmul_1024_epilogue,.Lmul_1024_in_tail + .long 0 .LSEH_info_rsaz_1024_gather5: .byte 0x01,0x36,0x17,0x0b .byte 0x36,0xf8,0x09,0x00 # vmovaps 0x90(rsp),xmm15 diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc index a152cdf7..c0af58d9 100644 --- a/src/crypto/bn/bn_test.cc +++ b/src/crypto/bn/bn_test.cc @@ -1668,6 +1668,93 @@ static bool TestBNSetGetU64() { return true; } +static bool TestBNPow2(BN_CTX *ctx) { + bssl::UniquePtr<BIGNUM> + power_of_two(BN_new()), + random(BN_new()), + expected(BN_new()), + actual(BN_new()); + + if (!power_of_two.get() || + !random.get() || + !expected.get() || + !actual.get()) { + return false; + } + + // Choose an exponent. + for (size_t e = 3; e < 512; e += 11) { + // Choose a bit length for our randoms. + for (int len = 3; len < 512; len += 23) { + // Set power_of_two = 2^e. + if (!BN_lshift(power_of_two.get(), BN_value_one(), (int) e)) { + fprintf(stderr, "Failed to shiftl.\n"); + return false; + } + + // Test BN_is_pow2 on power_of_two. + if (!BN_is_pow2(power_of_two.get())) { + fprintf(stderr, "BN_is_pow2 returned false for a power of two.\n"); + hexdump(stderr, "Arg: ", power_of_two->d, + power_of_two->top * sizeof(BN_ULONG)); + return false; + } + + // Pick a large random value, ensuring it isn't a power of two. + if (!BN_rand(random.get(), len, BN_RAND_TOP_TWO, BN_RAND_BOTTOM_ANY)) { + fprintf(stderr, "Failed to generate random in TestBNPow2.\n"); + return false; + } + + // Test BN_is_pow2 on |r|. + if (BN_is_pow2(random.get())) { + fprintf(stderr, "BN_is_pow2 returned true for a non-power of two.\n"); + hexdump(stderr, "Arg: ", random->d, random->top * sizeof(BN_ULONG)); + return false; + } + + // Test BN_mod_pow2 on |r|. + if (!BN_mod(expected.get(), random.get(), power_of_two.get(), ctx) || + !BN_mod_pow2(actual.get(), random.get(), e) || + BN_cmp(actual.get(), expected.get())) { + fprintf(stderr, "BN_mod_pow2 returned the wrong value:\n"); + hexdump(stderr, "Expected: ", expected->d, + expected->top * sizeof(BN_ULONG)); + hexdump(stderr, "Got: ", actual->d, + actual->top * sizeof(BN_ULONG)); + return false; + } + + // Test BN_nnmod_pow2 on |r|. + if (!BN_nnmod(expected.get(), random.get(), power_of_two.get(), ctx) || + !BN_nnmod_pow2(actual.get(), random.get(), e) || + BN_cmp(actual.get(), expected.get())) { + fprintf(stderr, "BN_nnmod_pow2 failed on positive input:\n"); + hexdump(stderr, "Expected: ", expected->d, + expected->top * sizeof(BN_ULONG)); + hexdump(stderr, "Got: ", actual->d, + actual->top * sizeof(BN_ULONG)); + return false; + } + + // Test BN_nnmod_pow2 on -|r|. + BN_set_negative(random.get(), 1); + if (!BN_nnmod(expected.get(), random.get(), power_of_two.get(), ctx) || + !BN_nnmod_pow2(actual.get(), random.get(), e) || + BN_cmp(actual.get(), expected.get())) { + fprintf(stderr, "BN_nnmod_pow2 failed on negative input:\n"); + hexdump(stderr, "Expected: ", expected->d, + expected->top * sizeof(BN_ULONG)); + hexdump(stderr, "Got: ", actual->d, + actual->top * sizeof(BN_ULONG)); + return false; + } + } + } + + return true; +} + int main(int argc, char *argv[]) { CRYPTO_library_init(); @@ -1695,7 +1782,8 @@ int main(int argc, char *argv[]) { !TestSmallPrime(ctx.get()) || !TestCmpWord() || !TestBN2Dec() || - !TestBNSetGetU64()) { + !TestBNSetGetU64() || + !TestBNPow2(ctx.get())) { return 1; } diff --git a/src/crypto/bn/cmp.c b/src/crypto/bn/cmp.c index 9cf33b48..71c04658 100644 --- a/src/crypto/bn/cmp.c +++ b/src/crypto/bn/cmp.c @@ -212,6 +212,20 @@ int BN_is_odd(const BIGNUM *bn) { return bn->top > 0 && (bn->d[0] & 1) == 1; } +int BN_is_pow2(const BIGNUM *bn) { + if (bn->top == 0 || bn->neg) { + return 0; + } + + for (int i = 0; i < bn->top - 1; i++) { + if (bn->d[i] != 0) { + return 0; + } + } + + return 0 == (bn->d[bn->top-1] & (bn->d[bn->top-1] - 1)); +} + int BN_equal_consttime(const BIGNUM *a, const BIGNUM *b) { if (a->top != b->top) { return 0; diff --git a/src/crypto/bn/div.c b/src/crypto/bn/div.c index 6e3df7d3..de3fa1f1 100644 --- a/src/crypto/bn/div.c +++ b/src/crypto/bn/div.c @@ -58,6 +58,7 @@ #include <assert.h> #include <limits.h> + #include <openssl/err.h> #include "internal.h" @@ -646,3 +647,82 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { } return (BN_ULONG)ret; } + +int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) { + if (e == 0 || a->top == 0) { + BN_zero(r); + return 1; + } + + size_t num_words = 1 + ((e - 1) / BN_BITS2); + + /* If |a| definitely has less than |e| bits, just BN_copy. */ + if ((size_t) a->top < num_words) { + return BN_copy(r, a) != NULL; + } + + /* Otherwise, first make sure we have enough space in |r|. + * Note that this will fail if num_words > INT_MAX. */ + if (bn_wexpand(r, num_words) == NULL) { + return 0; + } + + /* Copy the content of |a| into |r|. */ + OPENSSL_memcpy(r->d, a->d, num_words * sizeof(BN_ULONG)); + + /* If |e| isn't word-aligned, we have to mask off some of our bits. */ + size_t top_word_exponent = e % (sizeof(BN_ULONG) * 8); + if (top_word_exponent != 0) { + r->d[num_words - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1; + } + + /* Fill in the remaining fields of |r|. */ + r->neg = a->neg; + r->top = (int) num_words; + bn_correct_top(r); + return 1; +} + +int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) { + if (!BN_mod_pow2(r, a, e)) { + return 0; + } + + /* If the returned value was non-negative, we're done. */ + if (BN_is_zero(r) || !r->neg) { + return 1; + } + + size_t num_words = 1 + (e - 1) / BN_BITS2; + + /* Expand |r| to the size of our modulus. */ + if (bn_wexpand(r, num_words) == NULL) { + return 0; + } + + /* Clear the upper words of |r|. */ + OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES); + + /* Set parameters of |r|. */ + r->neg = 0; + r->top = (int) num_words; + + /* Now, invert every word. The idea here is that we want to compute 2^e-|x|, + * which is actually equivalent to the twos-complement representation of |x| + * in |e| bits, which is -x = ~x + 1. */ + for (int i = 0; i < r->top; i++) { + r->d[i] = ~r->d[i]; + } + + /* If our exponent doesn't span the top word, we have to mask the rest. */ + size_t top_word_exponent = e % BN_BITS2; + if (top_word_exponent != 0) { + r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1; + } + + /* Keep the correct_top invariant for BN_add. */ + bn_correct_top(r); + + /* Finally, add one, for the reason described above. */ + return BN_add(r, r, BN_value_one()); +} diff --git a/src/crypto/cipher/asm/chacha20_poly1305_x86_64.pl b/src/crypto/cipher/asm/chacha20_poly1305_x86_64.pl index 44590c2f..857f1d5d 100644 --- a/src/crypto/cipher/asm/chacha20_poly1305_x86_64.pl +++ b/src/crypto/cipher/asm/chacha20_poly1305_x86_64.pl @@ -39,6 +39,9 @@ $avx = 2; $code.=<<___; .text .extern OPENSSL_ia32cap_P + +chacha20_poly1305_constants: + .align 64 .chacha20_consts: .byte 'e','x','p','a','n','d',' ','3','2','-','b','y','t','e',' ','k' diff --git a/src/crypto/dh/dh_test.cc b/src/crypto/dh/dh_test.cc index 9cde6796..e08664fa 100644 --- a/src/crypto/dh/dh_test.cc +++ b/src/crypto/dh/dh_test.cc @@ -86,7 +86,6 @@ TEST(DHTest, AllTests) { !TestBadY() || !TestASN1() || !TestRFC3526()) { - ERR_print_errors_fp(stderr); ADD_FAILURE() << "Tests failed."; } } diff --git a/src/crypto/dsa/dsa_test.cc b/src/crypto/dsa/dsa_test.cc index d2cd33e3..63b78036 100644 --- a/src/crypto/dsa/dsa_test.cc +++ b/src/crypto/dsa/dsa_test.cc @@ -312,7 +312,6 @@ TEST(DSATest, AllTests) { !TestVerify(fips_sig_extra, sizeof(fips_sig_extra), -1) || !TestVerify(fips_sig_bad_length, sizeof(fips_sig_bad_length), -1) || !TestVerify(fips_sig_bad_r, sizeof(fips_sig_bad_r), 0)) { - ERR_print_errors_fp(stderr); ADD_FAILURE() << "Tests failed"; } } diff --git a/src/crypto/err/CMakeLists.txt b/src/crypto/err/CMakeLists.txt index a095b542..579a35be 100644 --- a/src/crypto/err/CMakeLists.txt +++ b/src/crypto/err/CMakeLists.txt @@ -37,14 +37,3 @@ add_library( err.c err_data.c ) - -add_executable( - err_test - - err_test.cc - - $<TARGET_OBJECTS:test_support> -) - -target_link_libraries(err_test crypto) -add_dependencies(all_tests err_test) diff --git a/src/crypto/err/err_test.cc b/src/crypto/err/err_test.cc index d6913558..8e820b85 100644 --- a/src/crypto/err/err_test.cc +++ b/src/crypto/err/err_test.cc @@ -15,40 +15,34 @@ #include <stdio.h> #include <string.h> +#include <gtest/gtest.h> + #include <openssl/crypto.h> #include <openssl/err.h> #include <openssl/mem.h> -static bool TestOverflow() { +TEST(ErrTest, Overflow) { for (unsigned i = 0; i < ERR_NUM_ERRORS*2; i++) { ERR_put_error(1, 0 /* unused */, i+1, "test", 1); } for (unsigned i = 0; i < ERR_NUM_ERRORS - 1; i++) { + SCOPED_TRACE(i); uint32_t err = ERR_get_error(); /* Errors are returned in order they were pushed, with the least recent ones * removed, up to |ERR_NUM_ERRORS - 1| errors. So the errors returned are * |ERR_NUM_ERRORS + 2| through |ERR_NUM_ERRORS * 2|, inclusive. */ - if (err == 0 || ((unsigned)ERR_GET_REASON(err)) != i + ERR_NUM_ERRORS + 2) { - fprintf(stderr, "ERR_get_error failed at %u\n", i); - return false; - } - } - - if (ERR_get_error() != 0) { - fprintf(stderr, "ERR_get_error more than the expected number of values.\n"); - return false; + EXPECT_NE(0u, err); + EXPECT_EQ(static_cast<int>(i + ERR_NUM_ERRORS + 2), ERR_GET_REASON(err)); } - return true; + EXPECT_EQ(0u, ERR_get_error()); } -static bool TestPutError() { - if (ERR_get_error() != 0) { - fprintf(stderr, "ERR_get_error returned value before an error was added.\n"); - return false; - } +TEST(ErrTest, PutError) { + ASSERT_EQ(0u, ERR_get_error()) + << "ERR_get_error returned value before an error was added."; ERR_put_error(1, 0 /* unused */, 2, "test", 4); ERR_add_error_data(1, "testing"); @@ -60,45 +54,31 @@ static bool TestPutError() { &peeked_flags); uint32_t packed_error = ERR_get_error_line_data(&file, &line, &data, &flags); - if (peeked_packed_error != packed_error || - peeked_file != file || - peeked_data != data || - peeked_flags != flags) { - fprintf(stderr, "Bad peeked error data returned.\n"); - return false; - } - - if (strcmp(file, "test") != 0 || - line != 4 || - (flags & ERR_FLAG_STRING) == 0 || - ERR_GET_LIB(packed_error) != 1 || - ERR_GET_REASON(packed_error) != 2 || - strcmp(data, "testing") != 0) { - fprintf(stderr, "Bad error data returned.\n"); - return false; - } - - return true; + EXPECT_EQ(peeked_packed_error, packed_error); + EXPECT_EQ(peeked_file, file); + EXPECT_EQ(peeked_data, data); + EXPECT_EQ(peeked_flags, flags); + + EXPECT_STREQ("test", file); + EXPECT_EQ(4, line); + EXPECT_TRUE(flags & ERR_FLAG_STRING); + EXPECT_EQ(1, ERR_GET_LIB(packed_error)); + EXPECT_EQ(2, ERR_GET_REASON(packed_error)); + EXPECT_STREQ("testing", data); } -static bool TestClearError() { - if (ERR_get_error() != 0) { - fprintf(stderr, "ERR_get_error returned value before an error was added.\n"); - return false; - } +TEST(ErrTest, ClearError) { + ASSERT_EQ(0u, ERR_get_error()) + << "ERR_get_error returned value before an error was added."; ERR_put_error(1, 0 /* unused */, 2, "test", 4); ERR_clear_error(); - if (ERR_get_error() != 0) { - fprintf(stderr, "Error remained after clearing.\n"); - return false; - } - - return true; + // The error queue should be cleared. + EXPECT_EQ(0u, ERR_get_error()); } -static bool TestPrint() { +TEST(ErrTest, Print) { ERR_put_error(1, 0 /* unused */, 2, "test", 4); ERR_add_error_data(1, "testing"); uint32_t packed_error = ERR_get_error(); @@ -107,14 +87,14 @@ static bool TestPrint() { for (size_t i = 0; i <= sizeof(buf); i++) { ERR_error_string_n(packed_error, buf, i); } - - return true; } -static bool TestRelease() { +TEST(ErrTest, Release) { ERR_put_error(1, 0 /* unused */, 2, "test", 4); ERR_remove_thread_state(NULL); - return true; + + // The error queue should be cleared. + EXPECT_EQ(0u, ERR_get_error()); } static bool HasSuffix(const char *str, const char *suffix) { @@ -126,7 +106,7 @@ static bool HasSuffix(const char *str, const char *suffix) { return strcmp(str + str_len - suffix_len, suffix) == 0; } -static bool TestPutMacro() { +TEST(ErrTest, PutMacro) { int expected_line = __LINE__ + 1; OPENSSL_PUT_ERROR(USER, ERR_R_INTERNAL_ERROR); @@ -134,29 +114,8 @@ static bool TestPutMacro() { const char *file; uint32_t error = ERR_get_error_line(&file, &line); - if (!HasSuffix(file, "err_test.cc") || - line != expected_line || - ERR_GET_LIB(error) != ERR_LIB_USER || - ERR_GET_REASON(error) != ERR_R_INTERNAL_ERROR) { - fprintf(stderr, "Bad error data returned.\n"); - return false; - } - - return true; -} - -int main() { - CRYPTO_library_init(); - - if (!TestOverflow() || - !TestPutError() || - !TestClearError() || - !TestPrint() || - !TestRelease() || - !TestPutMacro()) { - return 1; - } - - printf("PASS\n"); - return 0; + EXPECT_PRED2(HasSuffix, file, "err_test.cc"); + EXPECT_EQ(expected_line, line); + EXPECT_EQ(ERR_LIB_USER, ERR_GET_LIB(error)); + EXPECT_EQ(ERR_R_INTERNAL_ERROR, ERR_GET_REASON(error)); } diff --git a/src/crypto/perlasm/x86_64-xlate.pl b/src/crypto/perlasm/x86_64-xlate.pl index 074f185e..16553f2a 100755 --- a/src/crypto/perlasm/x86_64-xlate.pl +++ b/src/crypto/perlasm/x86_64-xlate.pl @@ -51,12 +51,7 @@ # 7. Stick to explicit ip-relative addressing. If you have to use # GOTPCREL addressing, stick to mov symbol@GOTPCREL(%rip),%r??. # Both are recognized and translated to proper Win64 addressing -# modes. To support legacy code a synthetic directive, .picmeup, -# is implemented. It puts address of the *next* instruction into -# target register, e.g.: -# -# .picmeup %rax -# lea .Label-.(%rax),%rax +# modes. # # 8. In order to provide for structured exception handling unified # Win64 prologue copies %rsp value to %rax. For further details @@ -125,7 +120,7 @@ my %globals; $self->{sz} = ""; } elsif ($self->{op} =~ /^p/ && $' !~ /^(ush|op|insrw)/) { # SSEn $self->{sz} = ""; - } elsif ($self->{op} =~ /^v/) { # VEX + } elsif ($self->{op} =~ /^[vk]/) { # VEX or k* such as kmov $self->{sz} = ""; } elsif ($self->{op} =~ /mov[dq]/ && $$line =~ /%xmm/) { $self->{sz} = ""; @@ -218,18 +213,26 @@ my %globals; } } { package ea; # pick up effective addresses: expr(%reg,%reg,scale) + + my %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", + l=>"DWORD$PTR", d=>"DWORD$PTR", + q=>"QWORD$PTR", o=>"OWORD$PTR", + x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", + z=>"ZMMWORD$PTR" ) if (!$gas); + sub re { my ($class, $line, $opcode) = @_; my $self = {}; my $ret; # optional * ----vvv--- appears in indirect jmp/call - if ($$line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)/) { + if ($$line =~ /^(\*?)([^\(,]*)\(([%\w,]+)\)((?:{[^}]+})*)/) { bless $self, $class; $self->{asterisk} = $1; $self->{label} = $2; ($self->{base},$self->{index},$self->{scale})=split(/,/,$3); $self->{scale} = 1 if (!defined($self->{scale})); + $self->{opmask} = $4; $ret = $self; $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; @@ -270,6 +273,8 @@ my %globals; $self->{label} =~ s/\b([0-9]+)\b/$1>>0/eg; } + # if base register is %rbp or %r13, see if it's possible to + # flip base and ingex registers [for better performance] if (!$self->{label} && $self->{index} && $self->{scale}==1 && $self->{base} =~ /(rbp|r13)/) { $self->{base} = $self->{index}; $self->{index} = $1; @@ -279,19 +284,16 @@ my %globals; $self->{label} =~ s/^___imp_/__imp__/ if ($flavour eq "mingw64"); if (defined($self->{index})) { - sprintf "%s%s(%s,%%%s,%d)",$self->{asterisk}, - $self->{label}, + sprintf "%s%s(%s,%%%s,%d)%s", + $self->{asterisk},$self->{label}, $self->{base}?"%$self->{base}":"", - $self->{index},$self->{scale}; + $self->{index},$self->{scale}, + $self->{opmask}; } else { - sprintf "%s%s(%%%s)", $self->{asterisk},$self->{label},$self->{base}; + sprintf "%s%s(%%%s)%s", $self->{asterisk},$self->{label}, + $self->{base},$self->{opmask}; } } else { - my %szmap = ( b=>"BYTE$PTR", w=>"WORD$PTR", - l=>"DWORD$PTR", d=>"DWORD$PTR", - q=>"QWORD$PTR", o=>"OWORD$PTR", - x=>"XMMWORD$PTR", y=>"YMMWORD$PTR", z=>"ZMMWORD$PTR" ); - $self->{label} =~ s/\./\$/g; $self->{label} =~ s/(?<![\w\$\.])0x([0-9a-f]+)/0$1h/ig; $self->{label} = "($self->{label})" if ($self->{label} =~ /[\*\+\-\/]/); @@ -303,17 +305,20 @@ my %globals; ($mnemonic =~ /^vpbroadcast([qdwb])$/) && ($sz=$1) || ($mnemonic =~ /^v(?!perm)[a-z]+[fi]128$/) && ($sz="x"); + $self->{opmask} =~ s/%(k[0-7])/$1/; + if (defined($self->{index})) { - sprintf "%s[%s%s*%d%s]",$szmap{$sz}, + sprintf "%s[%s%s*%d%s]%s",$szmap{$sz}, $self->{label}?"$self->{label}+":"", $self->{index},$self->{scale}, - $self->{base}?"+$self->{base}":""; + $self->{base}?"+$self->{base}":"", + $self->{opmask}; } elsif ($self->{base} eq "rip") { sprintf "%s[%s]",$szmap{$sz},$self->{label}; } else { - sprintf "%s[%s%s]",$szmap{$sz}, + sprintf "%s[%s%s]%s", $szmap{$sz}, $self->{label}?"$self->{label}+":"", - $self->{base}; + $self->{base},$self->{opmask}; } } } @@ -325,10 +330,11 @@ my %globals; my $ret; # optional * ----vvv--- appears in indirect jmp/call - if ($$line =~ /^(\*?)%(\w+)/) { + if ($$line =~ /^(\*?)%(\w+)((?:{[^}]+})*)/) { bless $self,$class; $self->{asterisk} = $1; $self->{value} = $2; + $self->{opmask} = $3; $opcode->size($self->size()); $ret = $self; $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; @@ -352,8 +358,11 @@ my %globals; } sub out { my $self = shift; - if ($gas) { sprintf "%s%%%s",$self->{asterisk},$self->{value}; } - else { $self->{value}; } + if ($gas) { sprintf "%s%%%s%s", $self->{asterisk}, + $self->{value}, + $self->{opmask}; } + else { $self->{opmask} =~ s/%(k[0-7])/$1/; + $self->{value}.$self->{opmask}; } } } { package label; # pick up labels, which end with : @@ -377,9 +386,8 @@ my %globals; if ($gas) { my $func = ($globals{$self->{value}} or $self->{value}) . ":"; - if ($win64 && - $current_function->{name} eq $self->{value} && - $current_function->{abi} eq "svr4") { + if ($win64 && $current_function->{name} eq $self->{value} + && $current_function->{abi} eq "svr4") { $func .= "\n"; $func .= " movq %rdi,8(%rsp)\n"; $func .= " movq %rsi,16(%rsp)\n"; @@ -458,15 +466,6 @@ my %globals; my $self = {}; my $ret; my $dir; - my %opcode = # lea 2f-1f(%rip),%dst; 1: nop; 2: - ( "%rax"=>0x01058d48, "%rcx"=>0x010d8d48, - "%rdx"=>0x01158d48, "%rbx"=>0x011d8d48, - "%rsp"=>0x01258d48, "%rbp"=>0x012d8d48, - "%rsi"=>0x01358d48, "%rdi"=>0x013d8d48, - "%r8" =>0x01058d4c, "%r9" =>0x010d8d4c, - "%r10"=>0x01158d4c, "%r11"=>0x011d8d4c, - "%r12"=>0x01258d4c, "%r13"=>0x012d8d4c, - "%r14"=>0x01358d4c, "%r15"=>0x013d8d4c ); if ($$line =~ /^\s*(\.\w+)/) { bless $self,$class; @@ -476,12 +475,6 @@ my %globals; $$line = substr($$line,@+[0]); $$line =~ s/^\s+//; SWITCH: for ($dir) { - /\.picmeup/ && do { if ($$line =~ /(%r[\w]+)/i) { - $dir="\t.long"; - $$line=sprintf "0x%x,0x90000000",$opcode{$1}; - } - last; - }; /\.global|\.globl|\.extern/ && do { $globals{$$line} = $prefix . $$line; $$line = $globals{$$line} if ($prefix); @@ -696,15 +689,6 @@ my %globals; } } -sub rex { - my $opcode=shift; - my ($dst,$src,$rex)=@_; - - $rex|=0x04 if($dst>=8); - $rex|=0x01 if($src>=8); - push @$opcode,($rex|0x40) if ($rex); -} - # Upon initial x86_64 introduction SSE>2 extensions were not introduced # yet. In order not to be bothered by tracing exact assembler versions, # but at the same time to provide a bare security minimum of AES-NI, we @@ -715,6 +699,15 @@ sub rex { my %regrm = ( "%eax"=>0, "%ecx"=>1, "%edx"=>2, "%ebx"=>3, "%esp"=>4, "%ebp"=>5, "%esi"=>6, "%edi"=>7 ); +sub rex { + my $opcode=shift; + my ($dst,$src,$rex)=@_; + + $rex|=0x04 if($dst>=8); + $rex|=0x01 if($src>=8); + push @$opcode,($rex|0x40) if ($rex); +} + my $movq = sub { # elderly gas can't handle inter-register movq my $arg = shift; my @opcode=(0x66); @@ -838,6 +831,10 @@ my $rdseed = sub { } }; +# Not all AVX-capable assemblers recognize AMD XOP extension. Since we +# are using only two instructions hand-code them in order to be excused +# from chasing assembler versions... + sub rxb { my $opcode=shift; my ($dst,$src1,$src2,$rxb)=@_; @@ -877,10 +874,15 @@ my $vprotq = sub { } }; +# Intel Control-flow Enforcement Technology extension. All functions and +# indirect branch targets will have to start with this instruction... + my $endbranch = sub { (0xf3,0x0f,0x1e,0xfa); }; +######################################################################## + if ($nasm) { print <<___; default rel @@ -1077,6 +1079,7 @@ close STDOUT; # movq -16(%rcx),%rbx # movq -8(%rcx),%r15 # movq %rcx,%rsp # restore original rsp +# magic_epilogue: # ret # .size function,.-function # @@ -1089,11 +1092,16 @@ close STDOUT; # EXCEPTION_DISPOSITION handler (EXCEPTION_RECORD *rec,ULONG64 frame, # CONTEXT *context,DISPATCHER_CONTEXT *disp) # { ULONG64 *rsp = (ULONG64 *)context->Rax; -# if (context->Rip >= magic_point) -# { rsp = ((ULONG64 **)context->Rsp)[0]; -# context->Rbp = rsp[-3]; -# context->Rbx = rsp[-2]; -# context->R15 = rsp[-1]; +# ULONG64 rip = context->Rip; +# +# if (rip >= magic_point) +# { rsp = (ULONG64 *)context->Rsp; +# if (rip < magic_epilogue) +# { rsp = (ULONG64 *)rsp[0]; +# context->Rbp = rsp[-3]; +# context->Rbx = rsp[-2]; +# context->R15 = rsp[-1]; +# } # } # context->Rsp = (ULONG64)rsp; # context->Rdi = rsp[1]; @@ -1185,13 +1193,12 @@ close STDOUT; # instruction and reflecting it in finer grade unwind logic in handler. # After all, isn't it why it's called *language-specific* handler... # -# Attentive reader can notice that exceptions would be mishandled in -# auto-generated "gear" epilogue. Well, exception effectively can't -# occur there, because if memory area used by it was subject to -# segmentation violation, then it would be raised upon call to the -# function (and as already mentioned be accounted to caller, which is -# not a problem). If you're still not comfortable, then define tail -# "magic point" just prior ret instruction and have handler treat it... +# SE handlers are also involved in unwinding stack when executable is +# profiled or debugged. Profiling implies additional limitations that +# are too subtle to discuss here. For now it's sufficient to say that +# in order to simplify handlers one should either a) offload original +# %rsp to stack (like discussed above); or b) if you have a register to +# spare for frame pointer, choose volatile one. # # (*) Note that we're talking about run-time, not debug-time. Lack of # unwind information makes debugging hard on both Windows and diff --git a/src/crypto/test/gtest_main.cc b/src/crypto/test/gtest_main.cc index 50147bc8..50970af3 100644 --- a/src/crypto/test/gtest_main.cc +++ b/src/crypto/test/gtest_main.cc @@ -14,10 +14,35 @@ #include <gtest/gtest.h> +#include <stdio.h> + +#include <openssl/err.h> #include <openssl/crypto.h> +namespace { + +class ErrorTestEventListener : public testing::EmptyTestEventListener { + public: + ErrorTestEventListener() {} + ~ErrorTestEventListener() override {} + + void OnTestEnd(const testing::TestInfo &test_info) override { + // If the test failed, print any errors left in the error queue. + if (test_info.result()->Failed()) { + ERR_print_errors_fp(stdout); + } + + // Clean up the error queue for the next run. + ERR_clear_error(); + } +}; + +} // namespace + int main(int argc, char **argv) { CRYPTO_library_init(); testing::InitGoogleTest(&argc, argv); + testing::UnitTest::GetInstance()->listeners().Append( + new ErrorTestEventListener); return RUN_ALL_TESTS(); } diff --git a/src/crypto/test/test_util.cc b/src/crypto/test/test_util.cc index 928972a3..493b1247 100644 --- a/src/crypto/test/test_util.cc +++ b/src/crypto/test/test_util.cc @@ -12,11 +12,12 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <stdint.h> -#include <stdio.h> - #include "test_util.h" +#include <ostream> + +#include "../internal.h" + void hexdump(FILE *fp, const char *msg, const void *in, size_t len) { const uint8_t *data = reinterpret_cast<const uint8_t*>(in); @@ -27,3 +28,13 @@ void hexdump(FILE *fp, const char *msg, const void *in, size_t len) { } fputs("\n", fp); } + +std::ostream &operator<<(std::ostream &os, const Bytes &in) { + // Print a byte slice as hex. + static const char hex[] = "0123456789abcdef"; + for (size_t i = 0; i < in.len; i++) { + os << hex[in.data[i] >> 4]; + os << hex[in.data[i] & 0xf]; + } + return os; +} diff --git a/src/crypto/test/test_util.h b/src/crypto/test/test_util.h index 972e2065..d834973e 100644 --- a/src/crypto/test/test_util.h +++ b/src/crypto/test/test_util.h @@ -16,20 +16,38 @@ #define OPENSSL_HEADER_CRYPTO_TEST_TEST_UTIL_H #include <stddef.h> +#include <stdint.h> #include <stdio.h> -#if defined(__cplusplus) -extern "C" { -#endif +#include <iosfwd> +#include "../internal.h" -/* hexdump writes |msg| to |fp| followed by the hex encoding of |len| bytes - * from |in|. */ + +// hexdump writes |msg| to |fp| followed by the hex encoding of |len| bytes +// from |in|. void hexdump(FILE *fp, const char *msg, const void *in, size_t len); +// Bytes is a wrapper over a byte slice which may be compared for equality. This +// allows it to be used in EXPECT_EQ macros. +struct Bytes { + Bytes(const uint8_t *data_arg, size_t len_arg) + : data(data_arg), len(len_arg) {} + + template <size_t N> + Bytes(const uint8_t (&array)[N]) : data(array), len(N) {} + + const uint8_t *data; + size_t len; +}; -#if defined(__cplusplus) +inline bool operator==(const Bytes &a, const Bytes &b) { + return a.len == b.len && OPENSSL_memcmp(a.data, b.data, a.len) == 0; } -#endif + +inline bool operator!=(const Bytes &a, const Bytes &b) { return !(a == b); } + +std::ostream &operator<<(std::ostream &os, const Bytes &in); + #endif /* OPENSSL_HEADER_CRYPTO_TEST_TEST_UTIL_H */ diff --git a/src/crypto/x509/pkcs7_test.c b/src/crypto/x509/pkcs7_test.c index 7bf4b81d..f620b9bc 100644 --- a/src/crypto/x509/pkcs7_test.c +++ b/src/crypto/x509/pkcs7_test.c @@ -23,7 +23,6 @@ #include <openssl/x509.h> #include "../internal.h" -#include "../test/test_util.h" /* kPKCS7NSS contains the certificate chain of mail.google.com, as saved by NSS diff --git a/src/crypto/x509v3/v3_cpols.c b/src/crypto/x509v3/v3_cpols.c index d67dcb08..7de54962 100644 --- a/src/crypto/x509v3/v3_cpols.c +++ b/src/crypto/x509v3/v3_cpols.c @@ -400,10 +400,10 @@ static int nref_nos(STACK_OF(ASN1_INTEGER) *nnums, STACK_OF(CONF_VALUE) *nos) return 1; merr: + ASN1_INTEGER_free(aint); OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); err: - sk_ASN1_INTEGER_pop_free(nnums, ASN1_STRING_free); return 0; } diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h index 77f61963..a57c23a9 100644 --- a/src/include/openssl/bn.h +++ b/src/include/openssl/bn.h @@ -476,6 +476,8 @@ OPENSSL_EXPORT int BN_is_word(const BIGNUM *bn, BN_ULONG w); /* BN_is_odd returns one if |bn| is odd and zero otherwise. */ OPENSSL_EXPORT int BN_is_odd(const BIGNUM *bn); +/* BN_is_pow2 returns 1 if |a| is a power of two, and 0 otherwise. */ +OPENSSL_EXPORT int BN_is_pow2(const BIGNUM *a); /* Bitwise operations. */ @@ -519,6 +521,14 @@ OPENSSL_EXPORT int BN_mask_bits(BIGNUM *a, int n); /* BN_mod_word returns |a| mod |w| or (BN_ULONG)-1 on error. */ OPENSSL_EXPORT BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w); +/* BN_mod_pow2 sets |r| = |a| mod 2^|e|. It returns 1 on success and + * 0 on error. */ +OPENSSL_EXPORT int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e); + +/* BN_nnmod_pow2 sets |r| = |a| mod 2^|e| where |r| is always positive. + * It returns 1 on success and 0 on error. */ +OPENSSL_EXPORT int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e); + /* BN_mod is a helper macro that calls |BN_div| and discards the quotient. */ #define BN_mod(rem, numerator, divisor, ctx) \ BN_div(NULL, (rem), (numerator), (divisor), (ctx)) diff --git a/src/include/openssl/digest.h b/src/include/openssl/digest.h index caf58610..87de3dfe 100644 --- a/src/include/openssl/digest.h +++ b/src/include/openssl/digest.h @@ -102,7 +102,8 @@ OPENSSL_EXPORT const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj); * An EVP_MD_CTX represents the state of a specific digest operation in * progress. */ -/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. */ +/* EVP_MD_CTX_init initialises an, already allocated, |EVP_MD_CTX|. This is the + * same as setting the structure to zero. */ OPENSSL_EXPORT void EVP_MD_CTX_init(EVP_MD_CTX *ctx); /* EVP_MD_CTX_create allocates and initialises a fresh |EVP_MD_CTX| and returns diff --git a/src/include/openssl/ssl.h b/src/include/openssl/ssl.h index 263b2728..497093db 100644 --- a/src/include/openssl/ssl.h +++ b/src/include/openssl/ssl.h @@ -904,6 +904,14 @@ OPENSSL_EXPORT int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, size_t list_len); +/* SSL_set_signed_cert_timestamp_list sets the list of signed certificate + * timestamps that is sent to clients that request is. The same format as the + * one used for |SSL_CTX_set_signed_cert_timestamp_list| applies. The caller + * retains ownership of |list|. */ +OPENSSL_EXPORT int SSL_set_signed_cert_timestamp_list(SSL *ctx, + const uint8_t *list, + size_t list_len); + /* SSL_CTX_set_ocsp_response sets the OCSP response that is sent to clients * which request it. It returns one on success and zero on error. The caller * retains ownership of |response|. */ @@ -1562,9 +1570,9 @@ DECLARE_LHASH_OF(SSL_SESSION) DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) /* SSL_SESSION_new returns a newly-allocated blank |SSL_SESSION| or NULL on - * error. This may be useful in writing tests but otherwise should not be - * used outside the library. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(void); + * error. This may be useful when writing tests but should otherwise not be + * used. */ +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx); /* SSL_SESSION_up_ref increments the reference count of |session| and returns * one. */ @@ -1589,8 +1597,8 @@ OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(const SSL_SESSION *in, /* SSL_SESSION_from_bytes parses |in_len| bytes from |in| as an SSL_SESSION. It * returns a newly-allocated |SSL_SESSION| on success or NULL on error. */ -OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, - size_t in_len); +OPENSSL_EXPORT SSL_SESSION *SSL_SESSION_from_bytes( + const uint8_t *in, size_t in_len, const SSL_CTX *ctx); /* SSL_SESSION_get_version returns a string describing the TLS version |session| * was established at. For example, "TLSv1.2" or "SSLv3". */ @@ -1753,20 +1761,6 @@ OPENSSL_EXPORT void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, * sessions created in |ctx|. */ OPENSSL_EXPORT long SSL_CTX_get_timeout(const SSL_CTX *ctx); -/* SSL_set_session_timeout sets the default lifetime, in seconds, of a TLS 1.2 - * (or earlier) 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_set_session_psk_dhe_timeout sets the lifetime, in seconds, of TLS 1.3 - * sessions created in |ssl| to |timeout|. */ -OPENSSL_EXPORT void SSL_set_session_psk_dhe_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 @@ -3688,6 +3682,7 @@ OPENSSL_EXPORT long BIO_set_ssl(BIO *bio, SSL *ssl, int take_owership); * deprecated. */ typedef struct ssl_protocol_method_st SSL_PROTOCOL_METHOD; +typedef struct ssl_x509_method_st SSL_X509_METHOD; struct ssl_cipher_st { /* name is the OpenSSL name for the cipher. */ @@ -3739,6 +3734,8 @@ struct ssl_session_st { * certificate. */ STACK_OF(CRYPTO_BUFFER) *certs; + const SSL_X509_METHOD *x509_method; + /* x509_peer is the peer's certificate. */ X509 *x509_peer; @@ -3866,6 +3863,7 @@ struct ssl_cipher_preference_list_st { * connections. */ struct ssl_ctx_st { const SSL_PROTOCOL_METHOD *method; + const SSL_X509_METHOD *x509_method; /* lock is used to protect various operations on this object. */ CRYPTO_MUTEX lock; @@ -4064,8 +4062,7 @@ struct ssl_ctx_st { EVP_PKEY *tlsext_channel_id_private; /* Signed certificate timestamp list to be sent to the client, if requested */ - uint8_t *signed_cert_timestamp_list; - size_t signed_cert_timestamp_list_length; + CRYPTO_BUFFER *signed_cert_timestamp_list; /* OCSP response to be sent to the client, if requested. */ CRYPTO_BUFFER *ocsp_response; diff --git a/src/include/openssl/ssl3.h b/src/include/openssl/ssl3.h index 84051ff2..6a03d1be 100644 --- a/src/include/openssl/ssl3.h +++ b/src/include/openssl/ssl3.h @@ -345,9 +345,6 @@ OPENSSL_COMPILE_ASSERT( #define SSL3_ST_SR_CLNT_HELLO_C (0x112 | SSL_ST_ACCEPT) #define SSL3_ST_SR_CLNT_HELLO_D (0x113 | SSL_ST_ACCEPT) /* write to client */ -#define SSL3_ST_SW_HELLO_REQ_A (0x120 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_HELLO_REQ_B (0x121 | SSL_ST_ACCEPT) -#define SSL3_ST_SW_HELLO_REQ_C (0x122 | SSL_ST_ACCEPT) #define SSL3_ST_SW_SRVR_HELLO_A (0x130 | SSL_ST_ACCEPT) #define SSL3_ST_SW_CERT_A (0x140 | SSL_ST_ACCEPT) #define SSL3_ST_SW_KEY_EXCH_A (0x150 | SSL_ST_ACCEPT) diff --git a/src/ssl/CMakeLists.txt b/src/ssl/CMakeLists.txt index afc3a398..5b5ea976 100644 --- a/src/ssl/CMakeLists.txt +++ b/src/ssl/CMakeLists.txt @@ -5,16 +5,15 @@ add_library( bio_ssl.c custom_extensions.c - handshake_server.c - handshake_client.c d1_both.c d1_lib.c d1_pkt.c d1_srtp.c dtls_method.c dtls_record.c + handshake_client.c + handshake_server.c s3_both.c - s3_enc.c s3_lib.c s3_pkt.c ssl_aead_ctx.c @@ -25,10 +24,11 @@ add_library( ssl_ecdh.c ssl_file.c ssl_lib.c - ssl_rsa.c - ssl_rsa_cc.cc + ssl_privkey.c + ssl_privkey_cc.cc ssl_session.c ssl_stat.c + ssl_transcript.c ssl_x509.c t1_enc.c t1_lib.c diff --git a/src/ssl/d1_both.c b/src/ssl/d1_both.c index 48a5c542..b864e426 100644 --- a/src/ssl/d1_both.c +++ b/src/ssl/d1_both.c @@ -549,7 +549,14 @@ static int add_outgoing(SSL *ssl, int is_ccs, uint8_t *data, size_t len) { } if (!is_ccs) { - ssl3_update_handshake_hash(ssl, data, len); + /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT + * on hs. */ + if (ssl->s3->hs != NULL && + !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + OPENSSL_free(data); + return 0; + } ssl->d1->handshake_write_seq++; } diff --git a/src/ssl/dtls_method.c b/src/ssl/dtls_method.c index 7a35b398..60847895 100644 --- a/src/ssl/dtls_method.c +++ b/src/ssl/dtls_method.c @@ -165,6 +165,7 @@ const SSL_METHOD *DTLS_method(void) { static const SSL_METHOD kMethod = { 0, &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -175,6 +176,7 @@ const SSL_METHOD *DTLSv1_2_method(void) { static const SSL_METHOD kMethod = { DTLS1_2_VERSION, &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -183,6 +185,7 @@ const SSL_METHOD *DTLSv1_method(void) { static const SSL_METHOD kMethod = { DTLS1_VERSION, &kDTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } diff --git a/src/ssl/handshake_client.c b/src/ssl/handshake_client.c index 23a4cffc..427213c2 100644 --- a/src/ssl/handshake_client.c +++ b/src/ssl/handshake_client.c @@ -399,7 +399,7 @@ int ssl3_connect(SSL_HANDSHAKE *hs) { * record the handshake hashes at this point in the session so that * any resumption of this session with ChannelID can sign those * hashes. */ - ret = tls1_record_handshake_hashes_for_channel_id(ssl); + ret = tls1_record_handshake_hashes_for_channel_id(hs); if (ret <= 0) { goto end; } @@ -732,7 +732,7 @@ int ssl_write_client_hello(SSL_HANDSHAKE *hs) { /* Now that the length prefixes have been computed, fill in the placeholder * PSK binder. */ if (hs->needs_psk_binder && - !tls13_write_psk_binder(ssl, msg, len)) { + !tls13_write_psk_binder(hs, msg, len)) { OPENSSL_free(msg); goto err; } @@ -748,7 +748,7 @@ static int ssl3_send_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; /* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we * may send multiple ClientHellos if we receive HelloVerifyRequest. */ - if (!ssl3_init_handshake_buffer(ssl)) { + if (!SSL_TRANSCRIPT_init(&hs->transcript)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } @@ -819,9 +819,6 @@ static int dtls1_get_hello_verify(SSL_HANDSHAKE *hs) { return 1; } - /* The handshake transcript is reset on HelloVerifyRequst, so do not bother - * hashing it. */ - CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num); if (!CBS_get_u16(&hello_verify_request, &server_version) || !CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) || @@ -897,8 +894,6 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete); if (!ssl->s3->have_version) { ssl->version = server_wire_version; - ssl->s3->enc_method = ssl3_get_enc_method(server_version); - assert(ssl->s3->enc_method != NULL); /* At this point, the connection's version is known and ssl->version is * fixed. Begin enforcing the record-layer version. */ ssl->s3->have_version = 1; @@ -999,8 +994,9 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { /* Now that the cipher is known, initialize the handshake hash and hash the * ServerHello. */ - if (!ssl3_init_handshake_hash(ssl) || - !ssl_hash_current_message(ssl)) { + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), + c->algorithm_prf) || + !ssl_hash_current_message(hs)) { goto f_err; } @@ -1009,7 +1005,7 @@ static int ssl3_get_server_hello(SSL_HANDSHAKE *hs) { * buffer may be released. */ if (ssl->session != NULL || !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); } /* Only the NULL compression algorithm is supported. */ @@ -1061,14 +1057,14 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } CBS cbs; CBS_init(&cbs, ssl->init_msg, ssl->init_num); - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free); EVP_PKEY_free(hs->peer_pubkey); hs->peer_pubkey = NULL; @@ -1081,7 +1077,7 @@ static int ssl3_get_server_certificate(SSL_HANDSHAKE *hs) { if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0 || CBS_len(&cbs) != 0 || - !ssl_session_x509_cache_objects(ssl->s3->new_session)) { + !ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return -1; @@ -1115,7 +1111,7 @@ static int ssl3_get_cert_status(SSL_HANDSHAKE *hs) { return 1; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return -1; } @@ -1177,7 +1173,7 @@ static int ssl3_get_server_key_exchange(SSL_HANDSHAKE *hs) { return 1; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return -1; } @@ -1403,12 +1399,12 @@ static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { ssl->s3->tmp.reuse_message = 1; /* If we get here we don't need the handshake buffer as we won't be doing * client auth. */ - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); return 1; } if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } @@ -1439,7 +1435,7 @@ static int ssl3_get_certificate_request(SSL_HANDSHAKE *hs) { } } - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); if (ca_sk == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); @@ -1467,7 +1463,7 @@ static int ssl3_get_server_hello_done(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } @@ -1499,7 +1495,7 @@ static int ssl3_send_client_certificate(SSL_HANDSHAKE *hs) { if (!ssl_has_certificate(ssl)) { /* Without a client certificate, the handshake buffer may be released. */ - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); /* In SSL 3.0, the Certificate message is replaced with a warning alert. */ if (ssl->version == SSL3_VERSION) { @@ -1619,7 +1615,7 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { } /* Compute the premaster. */ - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; 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); @@ -1680,9 +1676,8 @@ static int ssl3_send_client_key_exchange(SSL_HANDSHAKE *hs) { goto err; } - ssl->s3->new_session->master_key_length = - tls1_generate_master_secret(ssl, ssl->s3->new_session->master_key, pms, - pms_len); + ssl->s3->new_session->master_key_length = tls1_generate_master_secret( + hs, ssl->s3->new_session->master_key, pms, pms_len); if (ssl->s3->new_session->master_key_length == 0) { goto err; } @@ -1743,11 +1738,11 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { goto err; } - const EVP_MD *md; uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len, - signature_algorithm)) { + if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash( + &hs->transcript, digest, &digest_len, ssl->s3->new_session, + signature_algorithm)) { goto err; } @@ -1756,7 +1751,6 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL); if (pctx == NULL || !EVP_PKEY_sign_init(pctx) || - !EVP_PKEY_CTX_set_signature_md(pctx, md) || !EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) { EVP_PKEY_CTX_free(pctx); sign_result = ssl_private_key_failure; @@ -1766,12 +1760,12 @@ static int ssl3_send_cert_verify(SSL_HANDSHAKE *hs) { } else { sign_result = ssl_private_key_sign( ssl, ptr, &sig_len, max_sig_len, signature_algorithm, - (const uint8_t *)ssl->s3->handshake_buffer->data, - ssl->s3->handshake_buffer->length); + (const uint8_t *)hs->transcript.buffer->data, + hs->transcript.buffer->length); } /* The handshake buffer is no longer necessary. */ - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); } else { assert(hs->state == SSL3_ST_CW_CERT_VRFY_B); sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len); @@ -1834,7 +1828,7 @@ static int ssl3_send_channel_id(SSL_HANDSHAKE *hs) { CBB cbb, body; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || - !tls1_write_channel_id(ssl, &body) || + !tls1_write_channel_id(hs, &body) || !ssl_add_message_cbb(ssl, &cbb)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); CBB_cleanup(&cbb); @@ -1852,7 +1846,7 @@ static int ssl3_get_new_session_ticket(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } diff --git a/src/ssl/handshake_server.c b/src/ssl/handshake_server.c index 00f451e4..c352dd95 100644 --- a/src/ssl/handshake_server.c +++ b/src/ssl/handshake_server.c @@ -171,7 +171,9 @@ #include "../crypto/internal.h" -static int ssl3_get_client_hello(SSL_HANDSHAKE *hs); +static int ssl3_process_client_hello(SSL_HANDSHAKE *hs); +static int ssl3_select_certificate(SSL_HANDSHAKE *hs); +static int ssl3_select_parameters(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); @@ -216,24 +218,37 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { case SSL_ST_ACCEPT: ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1); + hs->state = SSL3_ST_SR_CLNT_HELLO_A; + break; - if (!ssl3_init_handshake_buffer(ssl)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - ret = -1; + case SSL3_ST_SR_CLNT_HELLO_A: + ret = ssl->method->ssl_get_message(ssl); + if (ret <= 0) { goto end; } - - hs->state = SSL3_ST_SR_CLNT_HELLO_A; + hs->state = SSL3_ST_SR_CLNT_HELLO_B; break; - case SSL3_ST_SR_CLNT_HELLO_A: case SSL3_ST_SR_CLNT_HELLO_B: + ret = ssl3_process_client_hello(hs); + if (ret <= 0) { + goto end; + } + hs->state = SSL3_ST_SR_CLNT_HELLO_C; + break; + case SSL3_ST_SR_CLNT_HELLO_C: - case SSL3_ST_SR_CLNT_HELLO_D: - ret = ssl3_get_client_hello(hs); - if (hs->state == SSL_ST_TLS13) { - break; + ret = ssl3_select_certificate(hs); + if (ret <= 0) { + goto end; + } + if (hs->state != SSL_ST_TLS13) { + hs->state = SSL3_ST_SR_CLNT_HELLO_D; } + break; + + case SSL3_ST_SR_CLNT_HELLO_D: + ret = ssl3_select_parameters(hs); if (ret <= 0) { goto end; } @@ -399,7 +414,7 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { * hashes in |ssl->s3->new_session| in case we need them to verify a * ChannelID signature on a resumption of this session in the future. */ if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) { - ret = tls1_record_handshake_hashes_for_channel_id(ssl); + ret = tls1_record_handshake_hashes_for_channel_id(hs); if (ret <= 0) { goto end; } @@ -468,10 +483,10 @@ int ssl3_accept(SSL_HANDSHAKE *hs) { * now. */ if (ssl->s3->new_session != NULL && ssl->retain_only_sha256_of_client_certs) { - X509_free(ssl->s3->new_session->x509_peer); - ssl->s3->new_session->x509_peer = NULL; - sk_X509_pop_free(ssl->s3->new_session->x509_chain, X509_free); - ssl->s3->new_session->x509_chain = NULL; + sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, + CRYPTO_BUFFER_free); + ssl->s3->new_session->certs = NULL; + ssl->ctx->x509_method->session_clear(ssl->s3->new_session); } SSL_SESSION_free(ssl->s3->established_session); @@ -632,8 +647,6 @@ static int negotiate_version(SSL_HANDSHAKE *hs, uint8_t *out_alert, 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); /* At this point, the connection's version is known and |ssl->version| is * fixed. Begin enforcing the record-layer version. */ @@ -807,126 +820,130 @@ static const SSL_CIPHER *ssl3_choose_cipher( return ret; } -static int ssl3_get_client_hello(SSL_HANDSHAKE *hs) { +static int ssl3_process_client_hello(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - uint8_t al = SSL_AD_INTERNAL_ERROR; - int ret = -1; - SSL_SESSION *session = NULL; - - if (hs->state == SSL3_ST_SR_CLNT_HELLO_A) { - /* The first time around, read the ClientHello. */ - int msg_ret = ssl->method->ssl_get_message(ssl); - if (msg_ret <= 0) { - return msg_ret; - } - - if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { - return -1; - } - - hs->state = SSL3_ST_SR_CLNT_HELLO_B; + if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_HELLO)) { + return -1; } 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; + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); + return -1; } - if (hs->state == SSL3_ST_SR_CLNT_HELLO_B) { - /* Run the early callback. */ - if (ssl->ctx->select_certificate_cb != NULL) { - switch (ssl->ctx->select_certificate_cb(&client_hello)) { - case 0: - ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; - goto err; + /* Run the early callback. */ + if (ssl->ctx->select_certificate_cb != NULL) { + switch (ssl->ctx->select_certificate_cb(&client_hello)) { + case 0: + ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; + return -1; - case -1: - /* Connection rejected. */ - al = SSL_AD_HANDSHAKE_FAILURE; - OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); - goto f_err; + case -1: + /* Connection rejected. */ + OPENSSL_PUT_ERROR(SSL, SSL_R_CONNECTION_REJECTED); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; - default: - /* fallthrough */; - } + default: + /* fallthrough */; } + } - if (!negotiate_version(hs, &al, &client_hello)) { - goto f_err; - } + uint8_t alert = SSL_AD_DECODE_ERROR; + if (!negotiate_version(hs, &alert, &client_hello)) { + ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); + return -1; + } - /* Load the client random. */ - if (client_hello.random_len != SSL3_RANDOM_SIZE) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + /* Load the client random. */ + if (client_hello.random_len != SSL3_RANDOM_SIZE) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return -1; + } + OPENSSL_memcpy(ssl->s3->client_random, client_hello.random, + client_hello.random_len); + + /* Only null compression is supported. TLS 1.3 further requires the peer + * advertise no other compression. */ + if (OPENSSL_memchr(client_hello.compression_methods, 0, + client_hello.compression_methods_len) == NULL || + (ssl3_protocol_version(ssl) >= TLS1_3_VERSION && + client_hello.compression_methods_len != 1)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); + return -1; + } + + /* TLS extensions. */ + if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); + return -1; + } + + return 1; +} + +static int ssl3_select_certificate(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); + if (rv == 0) { + OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return -1; } - OPENSSL_memcpy(ssl->s3->client_random, client_hello.random, - client_hello.random_len); - - /* Only null compression is supported. TLS 1.3 further requires the peer - * advertise no other compression. */ - if (OPENSSL_memchr(client_hello.compression_methods, 0, - client_hello.compression_methods_len) == NULL || - (ssl3_protocol_version(ssl) >= TLS1_3_VERSION && - client_hello.compression_methods_len != 1)) { - al = SSL_AD_ILLEGAL_PARAMETER; - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_COMPRESSION_LIST); - goto f_err; + if (rv < 0) { + ssl->rwstate = SSL_X509_LOOKUP; + return -1; } + } - /* TLS extensions. */ - if (!ssl_parse_clienthello_tlsext(hs, &client_hello)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT); - goto err; - } + if (!ssl_auto_chain_if_needed(ssl)) { + return -1; + } - hs->state = SSL3_ST_SR_CLNT_HELLO_C; + if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { + /* Jump to the TLS 1.3 state machine. */ + hs->state = SSL_ST_TLS13; + hs->do_tls13_handshake = tls13_server_handshake; + return 1; } - if (hs->state == SSL3_ST_SR_CLNT_HELLO_C) { - /* Call |cert_cb| to update server certificates if required. */ - if (ssl->cert->cert_cb != NULL) { - int rv = ssl->cert->cert_cb(ssl, ssl->cert->cert_cb_arg); - if (rv == 0) { - al = SSL_AD_INTERNAL_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_CERT_CB_ERROR); - goto f_err; - } - if (rv < 0) { - ssl->rwstate = SSL_X509_LOOKUP; - goto err; - } - } + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + return -1; + } - if (!ssl_auto_chain_if_needed(ssl)) { - goto err; - } + /* Negotiate the cipher suite. This must be done after |cert_cb| so the + * certificate is finalized. */ + ssl->s3->tmp.new_cipher = + ssl3_choose_cipher(hs, &client_hello, ssl_get_cipher_preferences(ssl)); + if (ssl->s3->tmp.new_cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_SHARED_CIPHER); + ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + return -1; + } - if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { - /* Jump to the TLS 1.3 state machine. */ - hs->state = SSL_ST_TLS13; - hs->do_tls13_handshake = tls13_server_handshake; - return 1; - } + return 1; +} - /* Negotiate the cipher suite. This must be done after |cert_cb| so the - * certificate is finalized. */ - ssl->s3->tmp.new_cipher = - 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); - goto f_err; - } +static int ssl3_select_parameters(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + uint8_t al = SSL_AD_INTERNAL_ERROR; + int ret = -1; + SSL_SESSION *session = NULL; - hs->state = SSL3_ST_SR_CLNT_HELLO_D; + SSL_CLIENT_HELLO client_hello; + if (!ssl_client_hello_init(ssl, &client_hello, ssl->init_msg, + ssl->init_num)) { + return -1; } - assert(hs->state == SSL3_ST_SR_CLNT_HELLO_D); - /* Determine whether we are doing session resumption. */ int tickets_supported = 0, renew_ticket = 0; switch (ssl_get_prev_session(ssl, &session, &tickets_supported, &renew_ticket, @@ -1027,14 +1044,15 @@ static int ssl3_get_client_hello(SSL_HANDSHAKE *hs) { /* Now that all parameters are known, initialize the handshake hash and hash * the ClientHello. */ - if (!ssl3_init_handshake_hash(ssl) || - !ssl_hash_current_message(ssl)) { + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl), + ssl->s3->tmp.new_cipher->algorithm_prf) || + !ssl_hash_current_message(hs)) { goto f_err; } /* Release the handshake buffer if client authentication isn't required. */ if (!hs->cert_request) { - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); } ret = 1; @@ -1431,7 +1449,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { return -1; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return -1; } @@ -1441,7 +1459,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { sk_CRYPTO_BUFFER_pop_free(ssl->s3->new_session->certs, CRYPTO_BUFFER_free); EVP_PKEY_free(hs->peer_pubkey); hs->peer_pubkey = NULL; - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; ssl->s3->new_session->certs = ssl_parse_cert_chain(&alert, &hs->peer_pubkey, ssl->retain_only_sha256_of_client_certs @@ -1454,7 +1472,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { } if (CBS_len(&certificate_msg) != 0 || - !ssl_session_x509_cache_objects(ssl->s3->new_session)) { + !ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); return -1; @@ -1462,7 +1480,7 @@ static int ssl3_get_client_certificate(SSL_HANDSHAKE *hs) { if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) { /* No client certificate so the handshake buffer may be discarded. */ - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); /* In SSL 3.0, sending no certificate is signaled by omitting the * Certificate message. */ @@ -1517,7 +1535,7 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } } @@ -1693,7 +1711,7 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { } /* Compute the premaster. */ - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; if (!SSL_ECDH_CTX_finish(&hs->ecdh_ctx, &premaster_secret, &premaster_secret_len, &alert, CBS_data(&peer_key), CBS_len(&peer_key))) { @@ -1745,9 +1763,9 @@ static int ssl3_get_client_key_exchange(SSL_HANDSHAKE *hs) { } /* Compute the master secret */ - ssl->s3->new_session->master_key_length = tls1_generate_master_secret( - ssl, ssl->s3->new_session->master_key, premaster_secret, - premaster_secret_len); + ssl->s3->new_session->master_key_length = + tls1_generate_master_secret(hs, ssl->s3->new_session->master_key, + premaster_secret, premaster_secret_len); if (ssl->s3->new_session->master_key_length == 0) { goto err; } @@ -1779,7 +1797,7 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { * CertificateVerify is required if and only if there's a client certificate. * */ if (hs->peer_pubkey == NULL) { - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); return 1; } @@ -1828,26 +1846,25 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { /* The SSL3 construction for CertificateVerify does not decompose into a * single final digest and signature, and must be special-cased. */ if (ssl3_protocol_version(ssl) == SSL3_VERSION) { - const EVP_MD *md; uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len, - signature_algorithm)) { + if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest, + &digest_len, ssl->s3->new_session, + signature_algorithm)) { goto err; } EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL); sig_ok = pctx != NULL && EVP_PKEY_verify_init(pctx) && - EVP_PKEY_CTX_set_signature_md(pctx, md) && EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature), digest, digest_len); EVP_PKEY_CTX_free(pctx); } else { sig_ok = ssl_public_key_verify( ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm, - hs->peer_pubkey, (const uint8_t *)ssl->s3->handshake_buffer->data, - ssl->s3->handshake_buffer->length); + hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data, + hs->transcript.buffer->length); } #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) @@ -1862,8 +1879,8 @@ static int ssl3_get_cert_verify(SSL_HANDSHAKE *hs) { /* The handshake buffer is no longer necessary, and we may hash the current * message.*/ - ssl3_free_handshake_buffer(ssl); - if (!ssl_hash_current_message(ssl)) { + SSL_TRANSCRIPT_free_buffer(&hs->transcript); + if (!ssl_hash_current_message(hs)) { goto err; } @@ -1885,7 +1902,7 @@ static int ssl3_get_next_proto(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return -1; } @@ -1916,8 +1933,8 @@ static int ssl3_get_channel_id(SSL_HANDSHAKE *hs) { } if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) || - !tls1_verify_channel_id(ssl) || - !ssl_hash_current_message(ssl)) { + !tls1_verify_channel_id(hs) || + !ssl_hash_current_message(hs)) { return -1; } return 1; diff --git a/src/ssl/internal.h b/src/ssl/internal.h index a90294e2..5b93f475 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -220,10 +220,9 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, const SSL_CIPHER *cipher, uint16_t version); /* ssl_get_handshake_digest returns the |EVP_MD| corresponding to - * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is - * responsible for maintaining the additional MD5 digest and switching to - * SHA-256 in TLS 1.2. */ -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf); + * |algorithm_prf| and the |version|. */ +const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf, + uint16_t version); /* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in * |ssl_method|. It sets |*out_cipher_list| to a newly-allocated @@ -260,6 +259,87 @@ int ssl_cipher_requires_server_key_exchange(const SSL_CIPHER *cipher); size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher); +/* Transcript layer. */ + +/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a + * buffer and running hash. */ +typedef struct ssl_transcript_st { + /* buffer, if non-NULL, contains the handshake transcript. */ + BUF_MEM *buffer; + /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For + * TLS 1.1 and below, it is the SHA-1 half. */ + EVP_MD_CTX hash; + /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the + * handshake hash for TLS 1.1 and below. */ + EVP_MD_CTX md5; +} SSL_TRANSCRIPT; + +/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an + * existing transcript, it resets the transcript and hash. It returns one on + * success and zero on failure. */ +int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and + * contents of the handshake transcript. Subsequent calls to + * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on + * success and zero on failure. It is an error to call this function after the + * handshake buffer is released. */ +int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, + int algorithm_prf); + +/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */ +void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to + * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */ +void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */ +size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is + * |EVP_md5_sha1|. */ +const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript); + +/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash, + * whichever is enabled. It returns one on success and zero on failure. */ +int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, + size_t in_len); + +/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have + * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns + * one and sets |*out_len| to the number of bytes written. Otherwise, it returns + * zero. */ +int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len); + +/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify + * hash into the bytes pointed to by |out| and writes the number of bytes to + * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one + * on success and zero on failure. */ +int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, + uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + int signature_algorithm); + +/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the + * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out| + * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and + * zero on failure. */ +int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len, const SSL_SESSION *session, + int from_server, uint16_t version); + +/* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to + * |out|, using |secret| as the secret and |label| as the label. |seed1| and + * |seed2| are concatenated to form the seed parameter. It returns one on + * success and zero on failure. */ +int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len); + + /* Encryption layer. */ /* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt @@ -525,35 +605,6 @@ int custom_ext_parse_clienthello(SSL_HANDSHAKE *hs, int *out_alert, int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions); -/* Handshake hash. - * - * The TLS handshake maintains a transcript of all handshake messages. At - * various points in the protocol, this is either a handshake buffer, a rolling - * hash (selected by cipher suite) or both. */ - -/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the - * handshake hash. It returns one success and zero on failure. */ -int ssl3_init_handshake_buffer(SSL *ssl); - -/* ssl3_init_handshake_hash initializes the handshake hash based on the pending - * cipher and the contents of the handshake buffer. Subsequent calls to - * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on - * success and zero on failure. It is an error to call this function after the - * handshake buffer is released. */ -int ssl3_init_handshake_hash(SSL *ssl); - -/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls - * to |ssl3_update_handshake_hash| will not update the handshake buffer. */ -void ssl3_free_handshake_buffer(SSL *ssl); - -/* ssl3_free_handshake_hash releases the handshake hash. */ -void ssl3_free_handshake_hash(SSL *ssl); - -/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake - * hash, whichever is enabled. It returns one on success and zero on failure. */ -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len); - - /* ECDH groups. */ typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX; @@ -753,12 +804,6 @@ void ssl_write_buffer_clear(SSL *ssl); * configured and zero otherwise. */ int ssl_has_certificate(const SSL *ssl); -/* ssl_session_x509_cache_objects fills out |sess->x509_peer| and - * |sess->x509_chain| from |sess->certs| and erases - * |sess->x509_chain_without_leaf|. It returns one on success or zero on - * error. */ -int ssl_session_x509_cache_objects(SSL_SESSION *sess); - /* ssl_parse_cert_chain parses a certificate list from |cbs| in the format used * by a TLS Certificate message. On success, it returns a newly-allocated * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets @@ -827,12 +872,6 @@ int tls13_init_key_schedule(SSL_HANDSHAKE *hs); 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 - * and sets |*out_len| to the number of bytes written. Otherwise, it returns - * zero. */ -int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len); - /* 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, @@ -872,12 +911,13 @@ int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, /* tls13_write_psk_binder calculates the PSK binder value and replaces the last * bytes of |msg| with the resulting value. It returns 1 on success, and 0 on * failure. */ -int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len); +int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len); /* tls13_verify_psk_binder verifies that the handshake transcript, truncated * up to the binders has a valid signature using the value of |session|'s * resumption secret. It returns 1 on success, and 0 on failure. */ -int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, CBS *binders); +int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, + CBS *binders); /* Handshake functions. */ @@ -951,6 +991,9 @@ struct ssl_handshake_st { /* ecdh_ctx is the current ECDH instance. */ SSL_ECDH_CTX ecdh_ctx; + /* transcript is the current handshake transcript. */ + SSL_TRANSCRIPT transcript; + /* cookie is the value of the cookie received from the server, if any. */ uint8_t *cookie; size_t cookie_len; @@ -1132,7 +1175,7 @@ enum ssl_cert_verify_context_t { * containing the result. The caller must free it with |OPENSSL_free| to release * it. This function returns one on success and zero on failure. */ int tls13_get_cert_verify_signature_input( - SSL *ssl, uint8_t **out, size_t *out_len, + SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, enum ssl_cert_verify_context_t cert_verify_context); /* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns @@ -1256,6 +1299,10 @@ typedef struct cert_st { * operations. */ const SSL_PRIVATE_KEY_METHOD *key_method; + /* x509_method contains pointers to functions that might deal with |X509| + * compatibility, or might be a no-op, depending on the application. */ + const SSL_X509_METHOD *x509_method; + DH *dh_tmp; DH *(*dh_tmp_cb)(SSL *ssl, int is_export, int keysize); @@ -1287,6 +1334,9 @@ struct ssl_method_st { /* method is the underlying SSL_PROTOCOL_METHOD that initializes the * SSL_CTX. */ const SSL_PROTOCOL_METHOD *method; + /* x509_method contains pointers to functions that might deal with |X509| + * compatibility, or might be a no-op, depending on the application. */ + const SSL_X509_METHOD *x509_method; }; /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */ @@ -1368,19 +1418,34 @@ struct ssl_protocol_method_st { int (*set_write_state)(SSL *ssl, SSL_AEAD_CTX *aead_ctx); }; -/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff It is a bit - * of a mess of functions, but hell, think of it as an opaque structure. */ -typedef struct ssl3_enc_method { - /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to - * |out|, using |secret| as the secret and |label| as the label. |seed1| and - * |seed2| are concatenated to form the seed parameter. It returns one on - * success and zero on failure. */ - int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len); - int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out); -} SSL3_ENC_METHOD; +struct ssl_x509_method_st { + /* cert_clear frees and NULLs all X509-related state. */ + void (*cert_clear)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based certificate chain + * from |cert|. */ + void (*cert_flush_cached_chain)(CERT *cert); + /* cert_flush_cached_chain drops any cached |X509|-based leaf certificate + * from |cert|. */ + void (*cert_flush_cached_leaf)(CERT *cert); + + /* session_cache_objects fills out |sess->x509_peer| and |sess->x509_chain| + * from |sess->certs| and erases |sess->x509_chain_without_leaf|. It returns + * one on success or zero on error. */ + int (*session_cache_objects)(SSL_SESSION *session); + /* session_dup duplicates any needed fields from |session| to |new_session|. + * It returns one on success or zero on error. */ + int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); + /* session_clear frees any X509-related state from |session|. */ + void (*session_clear)(SSL_SESSION *session); +}; + +/* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by + * doing nothing. */ +extern const struct ssl_x509_method_st ssl_noop_x509_method; + +/* ssl_crypto_x509_method provides the |ssl_x509_method_st| functions using + * crypto/x509. */ +extern const struct ssl_x509_method_st ssl_crypto_x509_method; typedef struct ssl3_record_st { /* type is the record type. */ @@ -1431,15 +1496,6 @@ typedef struct ssl3_state_st { int wpend_ret; /* number of bytes submitted */ const uint8_t *wpend_buf; - /* handshake_buffer, if non-NULL, contains the handshake transcript. */ - BUF_MEM *handshake_buffer; - /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake - * hash. For TLS 1.1 and below, it is the SHA-1 half. */ - EVP_MD_CTX handshake_hash; - /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of - * the handshake hash for TLS 1.1 and below. */ - EVP_MD_CTX handshake_md5; - /* recv_shutdown is the shutdown state for the receive half of the * connection. */ enum ssl_shutdown_t recv_shutdown; @@ -1516,10 +1572,6 @@ typedef struct ssl3_state_st { /* aead_write_ctx is the current write cipher state. */ SSL_AEAD_CTX *aead_write_ctx; - /* enc_method is the method table corresponding to the current protocol - * version. */ - const SSL3_ENC_METHOD *enc_method; - /* hs is the handshake state for the current handshake or NULL if there isn't * one. */ SSL_HANDSHAKE *hs; @@ -1836,21 +1888,13 @@ struct ssl_st { * session space. Only effective on the server side. */ unsigned retain_only_sha256_of_client_certs:1; - /* session_timeout is the default lifetime in seconds of the session - * created in this connection at TLS 1.2 and earlier. */ - long session_timeout; - - /* session_psk_dhe_timeout is the default lifetime in seconds of sessions - * created in this connection at TLS 1.3. */ - long session_psk_dhe_timeout; + /* Signed certificate timestamp list to be sent to the client, if requested */ + CRYPTO_BUFFER *signed_cert_timestamp_list; /* OCSP response to be sent to the client, if requested. */ CRYPTO_BUFFER *ocsp_response; }; -extern const SSL3_ENC_METHOD TLSv1_enc_data; -extern const SSL3_ENC_METHOD SSLv3_enc_data; - /* From draft-ietf-tls-tls13-18, used in determining PSK modes. */ #define SSL_PSK_KE 0x0 #define SSL_PSK_DHE_KE 0x1 @@ -1860,13 +1904,12 @@ extern const SSL3_ENC_METHOD SSLv3_enc_data; #define SSL_KEY_UPDATE_NOT_REQUESTED 0 #define SSL_KEY_UPDATE_REQUESTED 1 -CERT *ssl_cert_new(void); +CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method); CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); -CRYPTO_BUFFER *x509_to_buffer(X509 *x509); -void ssl_cert_flush_cached_x509_leaf(CERT *cert); -int ssl_cert_cache_leaf_cert(CERT *cert); +int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer); +int ssl_is_key_type_supported(int key_type); /* ssl_compare_public_and_private_key returns one if |pubkey| is the public * counterpart to |privkey|. Otherwise it returns zero and pushes a helpful * message on the error queue. */ @@ -1876,6 +1919,15 @@ int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); 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_new returns a newly-allocated blank |SSL_SESSION| or NULL on + * error. */ +SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method); + +/* SSL_SESSION_parse parses an |SSL_SESSION| from |cbs| and advances |cbs| over + * the parsed data. */ +SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool); + /* ssl_session_is_context_valid returns one if |session|'s session ID context * matches the one set on |ssl| and zero otherwise. */ int ssl_session_is_context_valid(const SSL *ssl, const SSL_SESSION *session); @@ -1888,6 +1940,11 @@ int ssl_session_is_time_valid(const SSL *ssl, const SSL_SESSION *session); * zero otherwise. */ int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session); +/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is + * invalid, it returns NULL. */ +const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session, + const SSL *ssl); + void ssl_set_session(SSL *ssl, SSL_SESSION *session); enum ssl_session_result_t { @@ -1936,7 +1993,7 @@ const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( const SSL *ssl); int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result, - STACK_OF(X509) * cert_chain); + STACK_OF(X509) *cert_chain); void ssl_update_cache(SSL_HANDSHAKE *hs, int mode); int ssl_verify_alarm_type(long type); @@ -1947,13 +2004,6 @@ int ssl3_get_message(SSL *ssl); void ssl3_get_current_message(const SSL *ssl, CBS *out); void ssl3_release_current_message(SSL *ssl, int free_buffer); -/* ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify hash into the - * bytes pointed to by |out| and writes the number of bytes to |*out_len|. |out| - * must have room for |EVP_MAX_MD_SIZE| bytes. It sets |*out_md| to the hash - * function used. It returns one on success and zero on failure. */ -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_HANDSHAKE *hs); int ssl3_dispatch_alert(SSL *ssl); int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len, @@ -1990,7 +2040,7 @@ int ssl_add_message_cbb(SSL *ssl, CBB *cbb); /* ssl_hash_current_message incorporates the current handshake message into the * handshake hash. It returns one on success and zero on allocation failure. */ -int ssl_hash_current_message(SSL *ssl); +int ssl_hash_current_message(SSL_HANDSHAKE *hs); /* dtls1_get_record reads a new input record. On success, it places it in * |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if @@ -2034,9 +2084,8 @@ void dtls1_release_current_message(SSL *ssl, int free_buffer); int dtls1_dispatch_alert(SSL *ssl); 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); +int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, + const uint8_t *premaster, size_t premaster_len); /* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the * locally-configured group preference list. */ @@ -2092,19 +2141,19 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, /* tls1_verify_channel_id processes the current message as a Channel ID message, * and verifies the signature. If the key is valid, it saves the Channel ID and * returns one. Otherwise, it returns zero. */ -int tls1_verify_channel_id(SSL *ssl); +int tls1_verify_channel_id(SSL_HANDSHAKE *hs); /* tls1_write_channel_id generates a Channel ID message and puts the output in * |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling. * This function returns one on success and zero on error. */ -int tls1_write_channel_id(SSL *ssl, CBB *cbb); +int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb); /* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes * it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns * one on success and zero on failure. */ -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len); +int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len); -int tls1_record_handshake_hashes_for_channel_id(SSL *ssl); +int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs); /* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if * necessary. It returns one on success and zero on fatal error. Note that, on @@ -2116,10 +2165,6 @@ int ssl_do_channel_id_callback(SSL *ssl); * otherwise. */ int ssl3_can_false_start(const SSL *ssl); -/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to - * |version|. */ -const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version); - /* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the * minimum and maximum enabled protocol versions, respectively. */ int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version, @@ -2129,8 +2174,6 @@ int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version, * call this function before the version is determined. */ uint16_t ssl3_protocol_version(const SSL *ssl); -uint32_t ssl_get_algorithm_prf(const SSL *ssl); - void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock); /* ssl_reset_error_state resets state for |SSL_get_error|. */ diff --git a/src/ssl/s3_both.c b/src/ssl/s3_both.c index 8d2657fa..d3f9421b 100644 --- a/src/ssl/s3_both.c +++ b/src/ssl/s3_both.c @@ -141,6 +141,10 @@ SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { hs->ssl = ssl; hs->wait = ssl_hs_ok; hs->state = SSL_ST_INIT; + if (!SSL_TRANSCRIPT_init(&hs->transcript)) { + ssl_handshake_free(hs); + return NULL; + } return hs; } @@ -159,6 +163,7 @@ void ssl_handshake_free(SSL_HANDSHAKE *hs) { OPENSSL_cleanse(hs->server_traffic_secret_0, sizeof(hs->server_traffic_secret_0)); SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx); + SSL_TRANSCRIPT_cleanup(&hs->transcript); OPENSSL_free(hs->cookie); OPENSSL_free(hs->key_share_bytes); OPENSSL_free(hs->public_key); @@ -264,7 +269,12 @@ int ssl3_add_message(SSL *ssl, uint8_t *msg, size_t len) { } while (added < len); ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len); - ssl3_update_handshake_hash(ssl, msg, len); + /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT + * on hs. */ + if (ssl->s3->hs != NULL && + !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) { + goto err; + } ret = 1; err: @@ -353,17 +363,20 @@ int ssl3_flush_flight(SSL *ssl) { int ssl3_send_finished(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; + const SSL_SESSION *session = SSL_get_session(ssl); + uint8_t finished[EVP_MAX_MD_SIZE]; - size_t finished_len = - ssl->s3->enc_method->final_finish_mac(ssl, ssl->server, finished); - if (finished_len == 0) { + size_t finished_len; + if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, + session, ssl->server, + ssl3_protocol_version(ssl))) { return 0; } /* Log the master secret, if logging is enabled. */ if (!ssl_log_secret(ssl, "CLIENT_RANDOM", - SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length)) { + session->master_key, + session->master_key_length)) { return 0; } @@ -409,10 +422,11 @@ int ssl3_get_finished(SSL_HANDSHAKE *hs) { /* Snapshot the finished hash before incorporating the new message. */ uint8_t finished[EVP_MAX_MD_SIZE]; - size_t finished_len = - ssl->s3->enc_method->final_finish_mac(ssl, !ssl->server, finished); - if (finished_len == 0 || - !ssl_hash_current_message(ssl)) { + size_t finished_len; + if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len, + SSL_get_session(ssl), !ssl->server, + ssl3_protocol_version(ssl)) || + !ssl_hash_current_message(hs)) { return -1; } @@ -482,7 +496,7 @@ size_t ssl_max_handshake_message_len(const SSL *ssl) { if (ssl->server) { /* The largest acceptable post-handshake message for a server is a * KeyUpdate. We will never initiate post-handshake auth. */ - return 0; + return 1; } /* Clients must accept NewSessionTicket and CertificateRequest, so allow the @@ -561,9 +575,11 @@ static int read_v2_client_hello(SSL *ssl) { CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length); /* The V2ClientHello without the length is incorporated into the handshake - * hash. */ - if (!ssl3_update_handshake_hash(ssl, CBS_data(&v2_client_hello), - CBS_len(&v2_client_hello))) { + * hash. This is only ever called at the start of the handshake, so hs is + * guaranteed to be non-NULL. */ + if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, + CBS_data(&v2_client_hello), + CBS_len(&v2_client_hello))) { return -1; } @@ -734,15 +750,15 @@ void ssl3_get_current_message(const SSL *ssl, CBS *out) { CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length); } -int ssl_hash_current_message(SSL *ssl) { +int ssl_hash_current_message(SSL_HANDSHAKE *hs) { /* V2ClientHellos are hashed implicitly. */ - if (ssl->s3->is_v2_hello) { + if (hs->ssl->s3->is_v2_hello) { return 1; } CBS cbs; - ssl->method->get_current_message(ssl, &cbs); - return ssl3_update_handshake_hash(ssl, CBS_data(&cbs), CBS_len(&cbs)); + hs->ssl->method->get_current_message(hs->ssl, &cbs); + return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs)); } void ssl3_release_current_message(SSL *ssl, int free_buffer) { diff --git a/src/ssl/s3_lib.c b/src/ssl/s3_lib.c index 3f44629c..1c723cd2 100644 --- a/src/ssl/s3_lib.c +++ b/src/ssl/s3_lib.c @@ -178,9 +178,6 @@ int ssl3_new(SSL *ssl) { return 0; } - EVP_MD_CTX_init(&s3->handshake_hash); - EVP_MD_CTX_init(&s3->handshake_md5); - ssl->s3 = s3; /* Set the version to the highest supported version. @@ -202,8 +199,6 @@ void ssl3_free(SSL *ssl) { SSL_SESSION_free(ssl->s3->new_session); SSL_SESSION_free(ssl->s3->established_session); - ssl3_free_handshake_buffer(ssl); - ssl3_free_handshake_hash(ssl); ssl_handshake_free(ssl->s3->hs); OPENSSL_free(ssl->s3->next_proto_negotiated); OPENSSL_free(ssl->s3->alpn_selected); @@ -224,14 +219,3 @@ const struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences( return ssl->ctx->cipher_list; } - -/* 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) { - uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf; - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT && - ssl3_protocol_version(ssl) >= TLS1_2_VERSION) { - return SSL_HANDSHAKE_MAC_SHA256; - } - return algorithm_prf; -} diff --git a/src/ssl/s3_pkt.c b/src/ssl/s3_pkt.c index 5d5b7e83..2f919cae 100644 --- a/src/ssl/s3_pkt.c +++ b/src/ssl/s3_pkt.c @@ -140,7 +140,7 @@ again: } CBS body; - uint8_t type, alert; + uint8_t type, alert = SSL_AD_DECODE_ERROR; size_t consumed; enum ssl_open_record_t open_ret = tls_open_record(ssl, &type, &body, &consumed, &alert, diff --git a/src/ssl/ssl_asn1.c b/src/ssl/ssl_asn1.c index 4c1ee89a..3582864e 100644 --- a/src/ssl/ssl_asn1.c +++ b/src/ssl/ssl_asn1.c @@ -575,8 +575,9 @@ static int SSL_SESSION_parse_u16(CBS *cbs, uint16_t *out, unsigned tag, return 1; } -static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { - SSL_SESSION *ret = SSL_SESSION_new(); +SSL_SESSION *SSL_SESSION_parse(CBS *cbs, const SSL_X509_METHOD *x509_method, + CRYPTO_BUFFER_POOL *pool) { + SSL_SESSION *ret = ssl_session_new(x509_method); if (ret == NULL) { goto err; } @@ -738,7 +739,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { if (has_peer) { /* TODO(agl): this should use the |SSL_CTX|'s pool. */ - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, NULL); + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&peer, pool); if (buffer == NULL || !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { CRYPTO_BUFFER_free(buffer); @@ -756,7 +757,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { } /* TODO(agl): this should use the |SSL_CTX|'s pool. */ - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, NULL); + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new_from_CBS(&cert, pool); if (buffer == NULL || !sk_CRYPTO_BUFFER_push(ret->certs, buffer)) { CRYPTO_BUFFER_free(buffer); @@ -766,7 +767,7 @@ static SSL_SESSION *SSL_SESSION_parse(CBS *cbs) { } } - if (!ssl_session_x509_cache_objects(ret)) { + if (!x509_method->session_cache_objects(ret)) { OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION); goto err; } @@ -811,10 +812,11 @@ err: return NULL; } -SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { +SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len, + const SSL_CTX *ctx) { CBS cbs; CBS_init(&cbs, in, in_len); - SSL_SESSION *ret = SSL_SESSION_parse(&cbs); + SSL_SESSION *ret = SSL_SESSION_parse(&cbs, ctx->x509_method, ctx->pool); if (ret == NULL) { return NULL; } @@ -825,25 +827,3 @@ SSL_SESSION *SSL_SESSION_from_bytes(const uint8_t *in, size_t in_len) { } return ret; } - -SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { - if (length < 0) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return NULL; - } - - CBS cbs; - CBS_init(&cbs, *pp, length); - - SSL_SESSION *ret = SSL_SESSION_parse(&cbs); - if (ret == NULL) { - return NULL; - } - - if (a) { - SSL_SESSION_free(*a); - *a = ret; - } - *pp = CBS_data(&cbs); - return ret; -} diff --git a/src/ssl/ssl_cert.c b/src/ssl/ssl_cert.c index 64526201..4177a482 100644 --- a/src/ssl/ssl_cert.c +++ b/src/ssl/ssl_cert.c @@ -141,13 +141,14 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void) { return 0; } -CERT *ssl_cert_new(void) { +CERT *ssl_cert_new(const SSL_X509_METHOD *x509_method) { CERT *ret = OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); return NULL; } OPENSSL_memset(ret, 0, sizeof(CERT)); + ret->x509_method = x509_method; return ret; } @@ -174,6 +175,7 @@ CERT *ssl_cert_dup(CERT *cert) { } ret->key_method = cert->key_method; + ret->x509_method = cert->x509_method; if (cert->dh_tmp != NULL) { ret->dh_tmp = DHparams_dup(cert->dh_tmp); @@ -208,27 +210,13 @@ err: return NULL; } -void ssl_cert_flush_cached_x509_leaf(CERT *cert) { - X509_free(cert->x509_leaf); - cert->x509_leaf = NULL; -} - -static void ssl_cert_flush_cached_x509_chain(CERT *cert) { - sk_X509_pop_free(cert->x509_chain, X509_free); - cert->x509_chain = NULL; -} - /* Free up and clear all certificates and chains */ void ssl_cert_clear_certs(CERT *cert) { if (cert == NULL) { return; } - ssl_cert_flush_cached_x509_leaf(cert); - ssl_cert_flush_cached_x509_chain(cert); - - X509_free(cert->x509_stash); - cert->x509_stash = NULL; + cert->x509_method->cert_clear(cert); sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); cert->chain = NULL; @@ -251,155 +239,97 @@ void ssl_cert_free(CERT *c) { OPENSSL_free(c); } -/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */ -static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) { - STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null(); - if (chain == NULL) { - return NULL; - } - - if (!sk_CRYPTO_BUFFER_push(chain, NULL)) { - sk_CRYPTO_BUFFER_free(chain); - return NULL; - } - - return chain; +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; } -/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised - * contents of |x509|. */ -CRYPTO_BUFFER *x509_to_buffer(X509 *x509) { - uint8_t *buf = NULL; - int cert_len = i2d_X509(x509, &buf); - if (cert_len <= 0) { +int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { + CBS cert_cbs; + CRYPTO_BUFFER_init_CBS(buffer, &cert_cbs); + EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); + if (pubkey == NULL) { return 0; } - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL); - OPENSSL_free(buf); - - return buffer; -} - -/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised - * forms of elements of |chain|. It returns one on success or zero on error, in - * which case no change to |cert->chain| is made. It preverses the existing - * leaf from |cert->chain|, if any. */ -static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) { - STACK_OF(CRYPTO_BUFFER) *new_chain = NULL; - - if (cert->chain != NULL) { - new_chain = sk_CRYPTO_BUFFER_new_null(); - if (new_chain == NULL) { - return 0; - } - - CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); - if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) { - goto err; - } - /* |leaf| might be NULL if it's a “leafless” chain. */ - if (leaf != NULL) { - CRYPTO_BUFFER_up_ref(leaf); - } - } - - for (size_t i = 0; i < sk_X509_num(chain); i++) { - if (new_chain == NULL) { - new_chain = new_leafless_chain(); - if (new_chain == NULL) { - goto err; - } - } - - CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i)); - if (buffer == NULL || - !sk_CRYPTO_BUFFER_push(new_chain, buffer)) { - CRYPTO_BUFFER_free(buffer); - goto err; - } + if (!ssl_is_key_type_supported(pubkey->type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + EVP_PKEY_free(pubkey); + return 0; } - sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); - cert->chain = new_chain; - - return 1; - -err: - sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free); - return 0; -} - -static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { - if (!ssl_cert_set_chain(cert, chain)) { + /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA + * certificates, so sanity-check the key usage extension. */ + if (pubkey->type == EVP_PKEY_EC && + !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); + EVP_PKEY_free(pubkey); return 0; } - sk_X509_pop_free(chain, X509_free); - ssl_cert_flush_cached_x509_chain(cert); - return 1; -} - -static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { - if (!ssl_cert_set_chain(cert, chain)) { - return 0; + if (cert->privatekey != NULL) { + /* Sanity-check that the private key and the certificate match, unless the + * key is opaque (in case of, say, a smartcard). */ + if (!EVP_PKEY_is_opaque(cert->privatekey) && + !ssl_compare_public_and_private_key(pubkey, cert->privatekey)) { + /* don't fail for a cert/key mismatch, just free current private key + * (when switching to a different cert & key, first this function should + * be used, then ssl_set_pkey */ + EVP_PKEY_free(cert->privatekey); + cert->privatekey = NULL; + /* clear error queue */ + ERR_clear_error(); + } } - ssl_cert_flush_cached_x509_chain(cert); - return 1; -} + EVP_PKEY_free(pubkey); -static int ssl_cert_append_cert(CERT *cert, X509 *x509) { - CRYPTO_BUFFER *buffer = x509_to_buffer(x509); - if (buffer == NULL) { - return 0; - } + cert->x509_method->cert_flush_cached_leaf(cert); if (cert->chain != NULL) { - if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { - CRYPTO_BUFFER_free(buffer); - return 0; - } - + CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0)); + sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer); + CRYPTO_BUFFER_up_ref(buffer); return 1; } - cert->chain = new_leafless_chain(); - if (cert->chain == NULL || - !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { - CRYPTO_BUFFER_free(buffer); + cert->chain = sk_CRYPTO_BUFFER_new_null(); + if (cert->chain == NULL) { + return 0; + } + + if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { sk_CRYPTO_BUFFER_free(cert->chain); cert->chain = NULL; return 0; } + CRYPTO_BUFFER_up_ref(buffer); return 1; } -static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { - if (!ssl_cert_append_cert(cert, x509)) { +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, + const uint8_t *der) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { return 0; } - X509_free(cert->x509_stash); - cert->x509_stash = x509; - ssl_cert_flush_cached_x509_chain(cert); - return 1; + const int ok = ssl_set_cert(ctx->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; } -static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { - if (!ssl_cert_append_cert(cert, x509)) { +int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); + if (buffer == NULL) { return 0; } - ssl_cert_flush_cached_x509_chain(cert); - return 1; -} - -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; + const int ok = ssl_set_cert(ssl->cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; } int ssl_verify_cert_chain(SSL *ssl, long *out_verify_result, @@ -590,6 +520,7 @@ STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, if (sk_CRYPTO_BUFFER_num(ret) == 0) { *out_pubkey = ssl_cert_parse_pubkey(&certificate); if (*out_pubkey == NULL) { + *out_alert = SSL_AD_DECODE_ERROR; goto err; } @@ -652,49 +583,6 @@ err: return 0; } -int ssl_auto_chain_if_needed(SSL *ssl) { - /* Only build a chain if there are no intermediates configured and the feature - * isn't disabled. */ - if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || - !ssl_has_certificate(ssl) || - ssl->cert->chain == NULL || - sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) { - return 1; - } - - X509 *leaf = - X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0)); - if (!leaf) { - OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); - return 0; - } - - X509_STORE_CTX ctx; - if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) { - X509_free(leaf); - OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); - return 0; - } - - /* Attempt to build a chain, ignoring the result. */ - X509_verify_cert(&ctx); - X509_free(leaf); - ERR_clear_error(); - - /* Remove the leaf from the generated chain. */ - X509_free(sk_X509_shift(ctx.chain)); - - const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain); - X509_STORE_CTX_cleanup(&ctx); - if (!ok) { - return 0; - } - - ssl_cert_flush_cached_x509_chain(ssl->cert); - - return 1; -} - /* ssl_cert_skip_to_spki parses a DER-encoded, X.509 certificate from |in| and * positions |*out_tbs_cert| to cover the TBSCertificate, starting at the * subjectPublicKeyInfo. */ @@ -986,54 +874,6 @@ int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) { return set_cert_store(&ssl->cert->verify_store, store, 1); } -int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ctx->cert, chain); -} - -int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ctx->cert, chain); -} - -int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set0_chain(ssl->cert, chain); -} - -int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) { - return ssl_cert_set1_chain(ssl->cert, chain); -} - -int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add0_chain_cert(ctx->cert, x509); -} - -int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) { - return ssl_cert_add1_chain_cert(ctx->cert, x509); -} - -int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) { - return SSL_CTX_add0_chain_cert(ctx, x509); -} - -int SSL_add0_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add0_chain_cert(ssl->cert, x509); -} - -int SSL_add1_chain_cert(SSL *ssl, X509 *x509) { - return ssl_cert_add1_chain_cert(ssl->cert, x509); -} - -int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_set0_chain(ctx, NULL); -} - -int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) { - return SSL_CTX_clear_chain_certs(ctx); -} - -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); @@ -1043,80 +883,6 @@ void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { ssl_cert_set_cert_cb(ssl->cert, cb, arg); } -/* ssl_cert_cache_leaf_cert sets |cert->x509_leaf|, if currently NULL, from the - * first element of |cert->chain|. */ -int ssl_cert_cache_leaf_cert(CERT *cert) { - if (cert->x509_leaf != NULL || - cert->chain == NULL) { - return 1; - } - - CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); - if (!leaf) { - return 1; - } - - cert->x509_leaf = X509_parse_from_buffer(leaf); - return cert->x509_leaf != NULL; -} - -/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of - * |cert->chain|. */ -static int ssl_cert_cache_chain_certs(CERT *cert) { - if (cert->x509_chain != NULL || - cert->chain == NULL || - sk_CRYPTO_BUFFER_num(cert->chain) < 2) { - return 1; - } - - STACK_OF(X509) *chain = sk_X509_new_null(); - if (chain == NULL) { - return 0; - } - - for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { - CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(cert->chain, i); - X509 *x509 = X509_parse_from_buffer(buffer); - if (x509 == NULL || - !sk_X509_push(chain, x509)) { - X509_free(x509); - goto err; - } - } - - cert->x509_chain = chain; - return 1; - -err: - sk_X509_pop_free(chain, X509_free); - return 0; -} - -int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { - if (!ssl_cert_cache_chain_certs(ctx->cert)) { - *out_chain = NULL; - return 0; - } - - *out_chain = ctx->cert->x509_chain; - return 1; -} - -int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, - STACK_OF(X509) **out_chain) { - return SSL_CTX_get0_chain_certs(ctx, out_chain); -} - -int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { - if (!ssl_cert_cache_chain_certs(ssl->cert)) { - *out_chain = NULL; - return 0; - } - - *out_chain = ssl->cert->x509_chain; - return 1; -} - int ssl_check_leaf_certificate(SSL *ssl, EVP_PKEY *pkey, const CRYPTO_BUFFER *leaf) { assert(ssl3_protocol_version(ssl) < TLS1_3_VERSION); diff --git a/src/ssl/ssl_cipher.c b/src/ssl/ssl_cipher.c index 480304ff..8f1ad734 100644 --- a/src/ssl/ssl_cipher.c +++ b/src/ssl/ssl_cipher.c @@ -787,10 +787,11 @@ int ssl_cipher_get_evp_aead(const EVP_AEAD **out_aead, return 1; } -const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) { +const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf, + uint16_t version) { switch (algorithm_prf) { case SSL_HANDSHAKE_MAC_DEFAULT: - return EVP_sha1(); + return version >= TLS1_2_VERSION ? EVP_sha256() : EVP_md5_sha1(); case SSL_HANDSHAKE_MAC_SHA256: return EVP_sha256(); case SSL_HANDSHAKE_MAC_SHA384: diff --git a/src/ssl/ssl_file.c b/src/ssl/ssl_file.c index e1ebaa69..59351a32 100644 --- a/src/ssl/ssl_file.c +++ b/src/ssl/ssl_file.c @@ -573,14 +573,3 @@ void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb) { void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data) { ctx->default_passwd_callback_userdata = data; } - -SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { - return ASN1_d2i_bio_of(SSL_SESSION, SSL_SESSION_new, d2i_SSL_SESSION, bio, - out); -} - -int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { - return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); -} - -IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/src/ssl/ssl_lib.c b/src/ssl/ssl_lib.c index 851c81f5..c946b77b 100644 --- a/src/ssl/ssl_lib.c +++ b/src/ssl/ssl_lib.c @@ -248,6 +248,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { OPENSSL_memset(ret, 0, sizeof(SSL_CTX)); ret->method = method->method; + ret->x509_method = method->x509_method; CRYPTO_MUTEX_init(&ret->lock); @@ -261,7 +262,7 @@ SSL_CTX *SSL_CTX_new(const SSL_METHOD *method) { ret->max_cert_list = SSL_MAX_CERT_LIST_DEFAULT; ret->verify_mode = SSL_VERIFY_NONE; - ret->cert = ssl_cert_new(); + ret->cert = ssl_cert_new(method->x509_method); if (ret->cert == NULL) { goto err; } @@ -362,8 +363,8 @@ void SSL_CTX_free(SSL_CTX *ctx) { OPENSSL_free(ctx->psk_identity_hint); OPENSSL_free(ctx->supported_group_list); OPENSSL_free(ctx->alpn_client_proto_list); + CRYPTO_BUFFER_free(ctx->signed_cert_timestamp_list); CRYPTO_BUFFER_free(ctx->ocsp_response); - OPENSSL_free(ctx->signed_cert_timestamp_list); EVP_PKEY_free(ctx->tlsext_channel_id_private); OPENSSL_free(ctx); @@ -471,8 +472,11 @@ SSL *SSL_new(SSL_CTX *ctx) { ssl->signed_cert_timestamps_enabled = ctx->signed_cert_timestamps_enabled; ssl->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled; - ssl->session_timeout = ctx->session_timeout; - ssl->session_psk_dhe_timeout = ctx->session_psk_dhe_timeout; + /* If the context has an SCT list, use it. */ + if (ctx->signed_cert_timestamp_list != NULL) { + CRYPTO_BUFFER_up_ref(ctx->signed_cert_timestamp_list); + ssl->signed_cert_timestamp_list = ctx->signed_cert_timestamp_list; + } /* If the context has an OCSP response, use it. */ if (ctx->ocsp_response != NULL) { @@ -518,6 +522,7 @@ void SSL_free(SSL *ssl) { OPENSSL_free(ssl->psk_identity_hint); sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); + CRYPTO_BUFFER_free(ssl->signed_cert_timestamp_list); CRYPTO_BUFFER_free(ssl->ocsp_response); if (ssl->method != NULL) { @@ -1628,8 +1633,27 @@ int SSL_CTX_set_signed_cert_timestamp_list(SSL_CTX *ctx, const uint8_t *list, return 0; } - return CBS_stow(&sct_list, &ctx->signed_cert_timestamp_list, - &ctx->signed_cert_timestamp_list_length); + CRYPTO_BUFFER_free(ctx->signed_cert_timestamp_list); + ctx->signed_cert_timestamp_list = CRYPTO_BUFFER_new(CBS_data(&sct_list), + CBS_len(&sct_list), + NULL); + return ctx->signed_cert_timestamp_list != NULL; +} + +int SSL_set_signed_cert_timestamp_list(SSL *ssl, const uint8_t *list, + size_t list_len) { + CBS sct_list; + CBS_init(&sct_list, list, list_len); + if (!ssl_is_sct_list_valid(&sct_list)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST); + return 0; + } + + CRYPTO_BUFFER_free(ssl->signed_cert_timestamp_list); + ssl->signed_cert_timestamp_list = CRYPTO_BUFFER_new(CBS_data(&sct_list), + CBS_len(&sct_list), + NULL); + return ssl->signed_cert_timestamp_list != NULL; } int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, @@ -2035,6 +2059,12 @@ SSL_CTX *SSL_set_SSL_CTX(SSL *ssl, SSL_CTX *ctx) { return ssl->ctx; } + /* One cannot change the X.509 callbacks during a connection. */ + if (ssl->ctx->x509_method != ctx->x509_method) { + assert(0); + return NULL; + } + if (ctx == NULL) { ctx = ssl->initial_ctx; } @@ -2353,22 +2383,6 @@ int ssl3_can_false_start(const SSL *ssl) { cipher->algorithm_mac == SSL_AEAD; } -const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) { - switch (version) { - case SSL3_VERSION: - return &SSLv3_enc_data; - - case TLS1_VERSION: - case TLS1_1_VERSION: - case TLS1_2_VERSION: - case TLS1_3_VERSION: - return &TLSv1_enc_data; - - default: - return NULL; - } -} - const struct { uint16_t version; uint32_t flag; diff --git a/src/ssl/ssl_rsa.c b/src/ssl/ssl_privkey.c index 6ad2b71a..79622473 100644 --- a/src/ssl/ssl_rsa.c +++ b/src/ssl/ssl_privkey.c @@ -70,38 +70,30 @@ #include "internal.h" -static int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer); -static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey); - -static int is_key_type_supported(int key_type) { +int ssl_is_key_type_supported(int key_type) { return key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_EC; } -int SSL_use_certificate(SSL *ssl, X509 *x) { - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); +static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) { + if (!ssl_is_key_type_supported(pkey->type)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); return 0; } - CRYPTO_BUFFER *buffer = x509_to_buffer(x); - if (buffer == NULL) { + if (cert->chain != NULL && + sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL && + /* Sanity-check that the private key and the certificate match, unless + * the key is opaque (in case of, say, a smartcard). */ + !EVP_PKEY_is_opaque(pkey) && + !ssl_cert_check_private_key(cert, pkey)) { return 0; } - const int ok = ssl_set_cert(ssl->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; -} - -int SSL_use_certificate_ASN1(SSL *ssl, const uint8_t *der, size_t der_len) { - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); - if (buffer == NULL) { - return 0; - } + EVP_PKEY_free(cert->privatekey); + EVP_PKEY_up_ref(pkey); + cert->privatekey = pkey; - const int ok = ssl_set_cert(ssl->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; + return 1; } int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { @@ -128,28 +120,6 @@ int SSL_use_RSAPrivateKey(SSL *ssl, RSA *rsa) { return ret; } -static int ssl_set_pkey(CERT *cert, EVP_PKEY *pkey) { - if (!is_key_type_supported(pkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - return 0; - } - - if (cert->chain != NULL && - sk_CRYPTO_BUFFER_value(cert->chain, 0) != NULL && - /* Sanity-check that the private key and the certificate match, unless - * the key is opaque (in case of, say, a smartcard). */ - !EVP_PKEY_is_opaque(pkey) && - !ssl_cert_check_private_key(cert, pkey)) { - return 0; - } - - EVP_PKEY_free(cert->privatekey); - EVP_PKEY_up_ref(pkey); - cert->privatekey = pkey; - - return 1; -} - int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { if (pkey == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); @@ -179,98 +149,6 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der, return ret; } -int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { - if (x == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - CRYPTO_BUFFER *buffer = x509_to_buffer(x); - if (buffer == NULL) { - return 0; - } - - const int ok = ssl_set_cert(ctx->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; -} - -static int ssl_set_cert(CERT *cert, CRYPTO_BUFFER *buffer) { - CBS cert_cbs; - CRYPTO_BUFFER_init_CBS(buffer, &cert_cbs); - EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); - if (pubkey == NULL) { - return 0; - } - - if (!is_key_type_supported(pubkey->type)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - EVP_PKEY_free(pubkey); - return 0; - } - - /* An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA - * certificates, so sanity-check the key usage extension. */ - if (pubkey->type == EVP_PKEY_EC && - !ssl_cert_check_digital_signature_key_usage(&cert_cbs)) { - OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); - EVP_PKEY_free(pubkey); - return 0; - } - - if (cert->privatekey != NULL) { - /* Sanity-check that the private key and the certificate match, unless the - * key is opaque (in case of, say, a smartcard). */ - if (!EVP_PKEY_is_opaque(cert->privatekey) && - !ssl_compare_public_and_private_key(pubkey, cert->privatekey)) { - /* don't fail for a cert/key mismatch, just free current private key - * (when switching to a different cert & key, first this function should - * be used, then ssl_set_pkey */ - EVP_PKEY_free(cert->privatekey); - cert->privatekey = NULL; - /* clear error queue */ - ERR_clear_error(); - } - } - - EVP_PKEY_free(pubkey); - - ssl_cert_flush_cached_x509_leaf(cert); - - if (cert->chain != NULL) { - CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(cert->chain, 0)); - sk_CRYPTO_BUFFER_set(cert->chain, 0, buffer); - CRYPTO_BUFFER_up_ref(buffer); - return 1; - } - - cert->chain = sk_CRYPTO_BUFFER_new_null(); - if (cert->chain == NULL) { - return 0; - } - - if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { - sk_CRYPTO_BUFFER_free(cert->chain); - cert->chain = NULL; - return 0; - } - CRYPTO_BUFFER_up_ref(buffer); - - return 1; -} - -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, size_t der_len, - const uint8_t *der) { - CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(der, der_len, NULL); - if (buffer == NULL) { - return 0; - } - - const int ok = ssl_set_cert(ctx->cert, buffer); - CRYPTO_BUFFER_free(buffer); - return ok; -} - int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa) { int ret; EVP_PKEY *pkey; diff --git a/src/ssl/ssl_rsa_cc.cc b/src/ssl/ssl_privkey_cc.cc index 653308c1..653308c1 100644 --- a/src/ssl/ssl_rsa_cc.cc +++ b/src/ssl/ssl_privkey_cc.cc diff --git a/src/ssl/ssl_session.c b/src/ssl/ssl_session.c index 7cddbdff..b71b994c 100644 --- a/src/ssl/ssl_session.c +++ b/src/ssl/ssl_session.c @@ -160,7 +160,7 @@ static void SSL_SESSION_list_remove(SSL_CTX *ctx, SSL_SESSION *session); static void SSL_SESSION_list_add(SSL_CTX *ctx, SSL_SESSION *session); static int remove_session_lock(SSL_CTX *ctx, SSL_SESSION *session, int lock); -SSL_SESSION *SSL_SESSION_new(void) { +SSL_SESSION *ssl_session_new(const SSL_X509_METHOD *x509_method) { SSL_SESSION *session = OPENSSL_malloc(sizeof(SSL_SESSION)); if (session == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -168,6 +168,7 @@ SSL_SESSION *SSL_SESSION_new(void) { } OPENSSL_memset(session, 0, sizeof(SSL_SESSION)); + session->x509_method = x509_method; session->verify_result = X509_V_ERR_INVALID_CALL; session->references = 1; session->timeout = SSL_DEFAULT_SESSION_TIMEOUT; @@ -177,8 +178,12 @@ SSL_SESSION *SSL_SESSION_new(void) { return session; } +SSL_SESSION *SSL_SESSION_new(const SSL_CTX *ctx) { + return ssl_session_new(ctx->x509_method); +} + SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { - SSL_SESSION *new_session = SSL_SESSION_new(); + SSL_SESSION *new_session = ssl_session_new(session->x509_method); if (new_session == NULL) { goto err; } @@ -214,16 +219,11 @@ SSL_SESSION *SSL_SESSION_dup(SSL_SESSION *session, int dup_flags) { CRYPTO_BUFFER_up_ref(buffer); } } - if (session->x509_peer != NULL) { - X509_up_ref(session->x509_peer); - new_session->x509_peer = session->x509_peer; - } - if (session->x509_chain != NULL) { - new_session->x509_chain = X509_chain_up_ref(session->x509_chain); - if (new_session->x509_chain == NULL) { - goto err; - } + + if (!session->x509_method->session_dup(new_session, session)) { + goto err; } + new_session->verify_result = session->verify_result; new_session->ocsp_response_length = session->ocsp_response_length; @@ -367,9 +367,7 @@ void SSL_SESSION_free(SSL_SESSION *session) { OPENSSL_cleanse(session->master_key, sizeof(session->master_key)); OPENSSL_cleanse(session->session_id, sizeof(session->session_id)); sk_CRYPTO_BUFFER_pop_free(session->certs, CRYPTO_BUFFER_free); - X509_free(session->x509_peer); - sk_X509_pop_free(session->x509_chain, X509_free); - sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); + session->x509_method->session_clear(session); OPENSSL_free(session->tlsext_hostname); OPENSSL_free(session->tlsext_tick); OPENSSL_free(session->tlsext_signed_cert_timestamp_list); @@ -494,6 +492,16 @@ void *SSL_SESSION_get_ex_data(const SSL_SESSION *session, int idx) { return CRYPTO_get_ex_data(&session->ex_data, idx); } +const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session, + const SSL *ssl) { + uint16_t version; + if (!ssl->method->version_from_wire(&version, session->ssl_version)) { + return NULL; + } + + return ssl_get_handshake_digest(session->cipher->algorithm_prf, version); +} + int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { SSL *const ssl = hs->ssl; if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) { @@ -501,7 +509,7 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { return 0; } - SSL_SESSION *session = SSL_SESSION_new(); + SSL_SESSION *session = ssl_session_new(ssl->ctx->x509_method); if (session == NULL) { return 0; } @@ -518,13 +526,13 @@ int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) { if (version >= TLS1_3_VERSION) { /* TLS 1.3 uses tickets as authenticators, so we are willing to use them for * longer. */ - session->timeout = ssl->session_psk_dhe_timeout; + session->timeout = ssl->initial_ctx->session_psk_dhe_timeout; session->auth_timeout = SSL_DEFAULT_SESSION_AUTH_TIMEOUT; } else { /* TLS 1.2 resumption does not incorporate new key material, so we use a * much shorter timeout. */ - session->timeout = ssl->session_timeout; - session->auth_timeout = ssl->session_timeout; + session->timeout = ssl->initial_ctx->session_timeout; + session->auth_timeout = ssl->initial_ctx->session_timeout; } if (is_server) { @@ -563,53 +571,6 @@ err: return 0; } -int ssl_session_x509_cache_objects(SSL_SESSION *sess) { - STACK_OF(X509) *chain = NULL; - const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs); - - if (num_certs > 0) { - chain = sk_X509_new_null(); - if (chain == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - - X509 *leaf = NULL; - for (size_t i = 0; i < num_certs; i++) { - X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i)); - if (x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; - } - if (!sk_X509_push(chain, x509)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - X509_free(x509); - goto err; - } - if (i == 0) { - leaf = x509; - } - } - - sk_X509_pop_free(sess->x509_chain, X509_free); - sess->x509_chain = chain; - sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free); - sess->x509_chain_without_leaf = NULL; - - X509_free(sess->x509_peer); - if (leaf != NULL) { - X509_up_ref(leaf); - } - sess->x509_peer = leaf; - - return 1; - -err: - sk_X509_pop_free(chain, X509_free); - return 0; -} - int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session) { int ret = 0; @@ -743,7 +704,8 @@ int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session) { /* If the session contains a client certificate (either the full * certificate or just the hash) then require that the form of the * certificate matches the current configuration. */ - ((session->x509_peer == NULL && !session->peer_sha256_valid) || + ((sk_CRYPTO_BUFFER_num(session->certs) == 0 && + !session->peer_sha256_valid) || session->peer_sha256_valid == ssl->retain_only_sha256_of_client_certs); } @@ -983,16 +945,6 @@ void SSL_CTX_set_session_psk_dhe_timeout(SSL_CTX *ctx, long timeout) { ctx->session_psk_dhe_timeout = timeout; } -long SSL_set_session_timeout(SSL *ssl, long timeout) { - long old_timeout = ssl->session_timeout; - ssl->session_timeout = timeout; - return old_timeout; -} - -void SSL_set_session_psk_dhe_timeout(SSL *ssl, long timeout) { - ssl->session_psk_dhe_timeout = timeout; -} - typedef struct timeout_param_st { SSL_CTX *ctx; long time; diff --git a/src/ssl/ssl_stat.c b/src/ssl/ssl_stat.c index 09a43d1c..479288a2 100644 --- a/src/ssl/ssl_stat.c +++ b/src/ssl/ssl_stat.c @@ -163,15 +163,6 @@ const char *SSL_state_string_long(const SSL *ssl) { case SSL3_ST_SR_CLNT_HELLO_C: return "SSLv3 read client hello C"; - case SSL3_ST_SW_HELLO_REQ_A: - return "SSLv3 write hello request A"; - - case SSL3_ST_SW_HELLO_REQ_B: - return "SSLv3 write hello request B"; - - case SSL3_ST_SW_HELLO_REQ_C: - return "SSLv3 write hello request C"; - case SSL3_ST_SW_SRVR_HELLO_A: return "SSLv3 write server hello A"; @@ -273,15 +264,6 @@ const char *SSL_state_string(const SSL *ssl) { case SSL3_ST_CR_FINISHED_A: return "3RFINA"; - case SSL3_ST_SW_HELLO_REQ_A: - return "3WHR_A"; - - case SSL3_ST_SW_HELLO_REQ_B: - return "3WHR_B"; - - case SSL3_ST_SW_HELLO_REQ_C: - return "3WHR_C"; - case SSL3_ST_SR_CLNT_HELLO_A: return "3RCH_A"; diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index aa265c8f..dfab9769 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -634,7 +634,12 @@ static bool TestSSL_SESSIONEncoding(const char *input_b64) { } // Verify the SSL_SESSION decodes. - bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size())); + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + if (!ssl_ctx) { + return false; + } + bssl::UniquePtr<SSL_SESSION> session( + SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); if (!session) { fprintf(stderr, "SSL_SESSION_from_bytes failed\n"); return false; @@ -703,7 +708,12 @@ static bool TestBadSSL_SESSIONEncoding(const char *input_b64) { } // Verify that the SSL_SESSION fails to decode. - bssl::UniquePtr<SSL_SESSION> session(SSL_SESSION_from_bytes(input.data(), input.size())); + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + if (!ssl_ctx) { + return false; + } + bssl::UniquePtr<SSL_SESSION> session( + SSL_SESSION_from_bytes(input.data(), input.size(), ssl_ctx.get())); if (session) { fprintf(stderr, "SSL_SESSION_from_bytes unexpectedly succeeded\n"); return false; @@ -795,8 +805,13 @@ static bssl::UniquePtr<SSL_SESSION> CreateSessionWithTicket(uint16_t version, if (!DecodeBase64(&der, kOpenSSLSession)) { return nullptr; } + + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + if (!ssl_ctx) { + return nullptr; + } bssl::UniquePtr<SSL_SESSION> session( - SSL_SESSION_from_bytes(der.data(), der.size())); + SSL_SESSION_from_bytes(der.data(), der.size(), ssl_ctx.get())); if (!session) { return nullptr; } @@ -935,24 +950,18 @@ static bool TestPaddingExtension(uint16_t max_version, // Test that |SSL_get_client_CA_list| echoes back the configured parameter even // before configuring as a server. -static bool TestClientCAList() { +TEST(SSLTest, ClientCAList) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); - if (!ctx) { - return false; - } + ASSERT_TRUE(ctx); bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get())); - if (!ssl) { - return false; - } + ASSERT_TRUE(ssl); STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null(); - if (stack == nullptr) { - return false; - } + ASSERT_TRUE(stack); // |SSL_set_client_CA_list| takes ownership. SSL_set_client_CA_list(ssl.get(), stack); - return SSL_get_client_CA_list(ssl.get()) == stack; + EXPECT_EQ(stack, SSL_get_client_CA_list(ssl.get())); } static void AppendSession(SSL_SESSION *session, void *arg) { @@ -995,7 +1004,11 @@ static bool ExpectCache(SSL_CTX *ctx, } static bssl::UniquePtr<SSL_SESSION> CreateTestSession(uint32_t number) { - bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new()); + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + if (!ssl_ctx) { + return nullptr; + } + bssl::UniquePtr<SSL_SESSION> ret(SSL_SESSION_new(ssl_ctx.get())); if (!ret) { return nullptr; } @@ -1456,163 +1469,128 @@ static bool TestOneSidedShutdown(bool is_dtls, const SSL_METHOD *method, return true; } -static bool TestSessionDuplication() { +TEST(SSLTest, SessionDuplication) { bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_method())); bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method())); - if (!client_ctx || !server_ctx) { - return false; - } + ASSERT_TRUE(client_ctx); + ASSERT_TRUE(server_ctx); bssl::UniquePtr<X509> cert = GetTestCertificate(); bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); - if (!cert || !key || - !SSL_CTX_use_certificate(server_ctx.get(), cert.get()) || - !SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())) { - return false; - } + ASSERT_TRUE(cert); + ASSERT_TRUE(key); + ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get())); + ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())); bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr /* no session */)) { - return false; - } + ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), + server_ctx.get(), + nullptr /* no session */)); SSL_SESSION *session0 = SSL_get_session(client.get()); - bssl::UniquePtr<SSL_SESSION> session1(SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL)); - if (!session1) { - return false; - } + bssl::UniquePtr<SSL_SESSION> session1( + SSL_SESSION_dup(session0, SSL_SESSION_DUP_ALL)); + ASSERT_TRUE(session1); session1->not_resumable = 0; uint8_t *s0_bytes, *s1_bytes; size_t s0_len, s1_len; - if (!SSL_SESSION_to_bytes(session0, &s0_bytes, &s0_len)) { - return false; - } + ASSERT_TRUE(SSL_SESSION_to_bytes(session0, &s0_bytes, &s0_len)); bssl::UniquePtr<uint8_t> free_s0(s0_bytes); - if (!SSL_SESSION_to_bytes(session1.get(), &s1_bytes, &s1_len)) { - return false; - } + ASSERT_TRUE(SSL_SESSION_to_bytes(session1.get(), &s1_bytes, &s1_len)); bssl::UniquePtr<uint8_t> free_s1(s1_bytes); - return s0_len == s1_len && OPENSSL_memcmp(s0_bytes, s1_bytes, s0_len) == 0; + EXPECT_EQ(Bytes(s0_bytes, s0_len), Bytes(s1_bytes, s1_len)); } -static bool ExpectFDs(const SSL *ssl, int rfd, int wfd) { - if (SSL_get_rfd(ssl) != rfd || SSL_get_wfd(ssl) != wfd) { - fprintf(stderr, "Got fds %d and %d, wanted %d and %d.\n", SSL_get_rfd(ssl), - SSL_get_wfd(ssl), rfd, wfd); - return false; - } +static void ExpectFDs(const SSL *ssl, int rfd, int wfd) { + EXPECT_EQ(rfd, SSL_get_rfd(ssl)); + EXPECT_EQ(wfd, SSL_get_wfd(ssl)); // The wrapper BIOs are always equal when fds are equal, even if set // individually. - if (rfd == wfd && SSL_get_rbio(ssl) != SSL_get_wbio(ssl)) { - fprintf(stderr, "rbio and wbio did not match.\n"); - return false; + if (rfd == wfd) { + EXPECT_EQ(SSL_get_rbio(ssl), SSL_get_wbio(ssl)); } - - return true; } -static bool TestSetFD() { +TEST(SSLTest, SetFD) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); - if (!ctx) { - return false; - } + ASSERT_TRUE(ctx); // Test setting different read and write FDs. bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_rfd(ssl.get(), 1) || - !SSL_set_wfd(ssl.get(), 2) || - !ExpectFDs(ssl.get(), 1, 2)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2)); + ExpectFDs(ssl.get(), 1, 2); // Test setting the same FD. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_fd(ssl.get(), 1) || - !ExpectFDs(ssl.get(), 1, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_fd(ssl.get(), 1)); + ExpectFDs(ssl.get(), 1, 1); // Test setting the same FD one side at a time. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_rfd(ssl.get(), 1) || - !SSL_set_wfd(ssl.get(), 1) || - !ExpectFDs(ssl.get(), 1, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1)); + ExpectFDs(ssl.get(), 1, 1); // Test setting the same FD in the other order. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_wfd(ssl.get(), 1) || - !SSL_set_rfd(ssl.get(), 1) || - !ExpectFDs(ssl.get(), 1, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1)); + ExpectFDs(ssl.get(), 1, 1); // Test changing the read FD partway through. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_fd(ssl.get(), 1) || - !SSL_set_rfd(ssl.get(), 2) || - !ExpectFDs(ssl.get(), 2, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_fd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_rfd(ssl.get(), 2)); + ExpectFDs(ssl.get(), 2, 1); // Test changing the write FD partway through. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_fd(ssl.get(), 1) || - !SSL_set_wfd(ssl.get(), 2) || - !ExpectFDs(ssl.get(), 1, 2)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_fd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_wfd(ssl.get(), 2)); + ExpectFDs(ssl.get(), 1, 2); // Test a no-op change to the read FD partway through. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_fd(ssl.get(), 1) || - !SSL_set_rfd(ssl.get(), 1) || - !ExpectFDs(ssl.get(), 1, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_fd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_rfd(ssl.get(), 1)); + ExpectFDs(ssl.get(), 1, 1); // Test a no-op change to the write FD partway through. ssl.reset(SSL_new(ctx.get())); - if (!ssl || - !SSL_set_fd(ssl.get(), 1) || - !SSL_set_wfd(ssl.get(), 1) || - !ExpectFDs(ssl.get(), 1, 1)) { - return false; - } + ASSERT_TRUE(ssl); + EXPECT_TRUE(SSL_set_fd(ssl.get(), 1)); + EXPECT_TRUE(SSL_set_wfd(ssl.get(), 1)); + ExpectFDs(ssl.get(), 1, 1); // ASan builds will implicitly test that the internal |BIO| reference-counting // is correct. - - return true; } -static bool TestSetBIO() { +TEST(SSLTest, SetBIO) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); - if (!ctx) { - return false; - } + ASSERT_TRUE(ctx); bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get())); bssl::UniquePtr<BIO> bio1(BIO_new(BIO_s_mem())), bio2(BIO_new(BIO_s_mem())), bio3(BIO_new(BIO_s_mem())); - if (!ssl || !bio1 || !bio2 || !bio3) { - return false; - } + ASSERT_TRUE(ssl); + ASSERT_TRUE(bio1); + ASSERT_TRUE(bio2); + ASSERT_TRUE(bio3); // SSL_set_bio takes one reference when the parameters are the same. BIO_up_ref(bio1.get()); @@ -1655,7 +1633,6 @@ static bool TestSetBIO() { // ASAN builds will implicitly test that the internal |BIO| reference-counting // is correct. - return true; } static int VerifySucceed(X509_STORE_CTX *store_ctx, void *arg) { return 1; } @@ -2207,8 +2184,12 @@ static bool GetServerTicketTime(long *out, const SSL_SESSION *session) { len = static_cast<size_t>(len1 + len2); #endif + bssl::UniquePtr<SSL_CTX> ssl_ctx(SSL_CTX_new(TLS_method())); + if (!ssl_ctx) { + return false; + } bssl::UniquePtr<SSL_SESSION> server_session( - SSL_SESSION_from_bytes(plaintext.get(), len)); + SSL_SESSION_from_bytes(plaintext.get(), len, ssl_ctx.get())); if (!server_session) { return false; } @@ -2410,151 +2391,6 @@ 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 int SetSessionTimeoutCallbackTLS13(SSL *ssl, void *arg) { - long timeout = *(long *) arg; - SSL_set_session_psk_dhe_timeout(ssl, timeout); - return 1; -} - -static bool TestSessionTimeoutCertCallback(bool is_dtls, - const SSL_METHOD *method, - uint16_t version) { - if (version == TLS1_3_VERSION) { - // |SSL_set_session_timeout| only applies to TLS 1.2 style resumption. - return true; - } - - 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; - if (version == TLS1_3_VERSION) { - SSL_CTX_set_cert_cb(server_ctx.get(), SetSessionTimeoutCallbackTLS13, - &timeout); - } else { - 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; - - if (version == TLS1_3_VERSION) { - SSL_CTX_set_session_psk_dhe_timeout(server_ctx.get(), timeout - 10); - } else { - 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); @@ -2622,121 +2458,81 @@ static bool TestSNICallback(bool is_dtls, const SSL_METHOD *method, return true; } -static int SetMaxVersion(const SSL_CLIENT_HELLO *client_hello) { - if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) { - return -1; - } - - return 1; -} - -// TestEarlyCallbackVersionSwitch tests that the early callback can swap the -// maximum version. -static bool TestEarlyCallbackVersionSwitch() { +// Test that the early callback can swap the maximum version. +TEST(SSLTest, EarlyCallbackVersionSwitch) { bssl::UniquePtr<X509> cert = GetTestCertificate(); bssl::UniquePtr<EVP_PKEY> key = GetTestKey(); bssl::UniquePtr<SSL_CTX> server_ctx(SSL_CTX_new(TLS_method())); bssl::UniquePtr<SSL_CTX> client_ctx(SSL_CTX_new(TLS_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_max_proto_version(client_ctx.get(), TLS1_3_VERSION) || - !SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION)) { - return false; - } + ASSERT_TRUE(cert); + ASSERT_TRUE(key); + ASSERT_TRUE(server_ctx); + ASSERT_TRUE(client_ctx); + ASSERT_TRUE(SSL_CTX_use_certificate(server_ctx.get(), cert.get())); + ASSERT_TRUE(SSL_CTX_use_PrivateKey(server_ctx.get(), key.get())); + ASSERT_TRUE(SSL_CTX_set_max_proto_version(client_ctx.get(), TLS1_3_VERSION)); + ASSERT_TRUE(SSL_CTX_set_max_proto_version(server_ctx.get(), TLS1_3_VERSION)); + + SSL_CTX_set_select_certificate_cb( + server_ctx.get(), [](const SSL_CLIENT_HELLO *client_hello) -> int { + if (!SSL_set_max_proto_version(client_hello->ssl, TLS1_2_VERSION)) { + return -1; + } - SSL_CTX_set_select_certificate_cb(server_ctx.get(), SetMaxVersion); + return 1; + }); bssl::UniquePtr<SSL> client, server; - if (!ConnectClientAndServer(&client, &server, client_ctx.get(), - server_ctx.get(), nullptr)) { - return false; - } - - if (SSL_version(client.get()) != TLS1_2_VERSION) { - fprintf(stderr, "Early callback failed to switch the maximum version.\n"); - return false; - } - - return true; + ASSERT_TRUE(ConnectClientAndServer(&client, &server, client_ctx.get(), + server_ctx.get(), nullptr)); + EXPECT_EQ(TLS1_2_VERSION, SSL_version(client.get())); } -static bool TestSetVersion() { +TEST(SSLTest, SetVersion) { bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method())); - if (!ctx) { - return false; - } - - if (!SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION) || - !SSL_CTX_set_max_proto_version(ctx.get(), TLS1_1_VERSION) || - !SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION) || - !SSL_CTX_set_min_proto_version(ctx.get(), TLS1_1_VERSION)) { - fprintf(stderr, "Could not set valid TLS version.\n"); - return false; - } - - if (SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION) || - SSL_CTX_set_max_proto_version(ctx.get(), 0x0200) || - SSL_CTX_set_max_proto_version(ctx.get(), 0x1234) || - SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION) || - SSL_CTX_set_min_proto_version(ctx.get(), 0x0200) || - SSL_CTX_set_min_proto_version(ctx.get(), 0x1234)) { - fprintf(stderr, "Unexpectedly set invalid TLS version.\n"); - return false; - } + ASSERT_TRUE(ctx); - if (!SSL_CTX_set_max_proto_version(ctx.get(), 0) || - !SSL_CTX_set_min_proto_version(ctx.get(), 0)) { - fprintf(stderr, "Could not set default TLS version.\n"); - return false; - } - - if (ctx->min_version != SSL3_VERSION || - ctx->max_version != TLS1_2_VERSION) { - fprintf(stderr, "Default TLS versions were incorrect (%04x and %04x).\n", - ctx->min_version, ctx->max_version); - return false; - } + // Set valid TLS versions. + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION)); + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_1_VERSION)); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION)); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_1_VERSION)); + + // Invalid TLS versions are rejected. + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION)); + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x0200)); + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x0200)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234)); + + // Zero is the default version. + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0)); + EXPECT_EQ(TLS1_2_VERSION, ctx->max_version); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0)); + EXPECT_EQ(SSL3_VERSION, ctx->min_version); ctx.reset(SSL_CTX_new(DTLS_method())); - if (!ctx) { - return false; - } - - if (!SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION) || - !SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_2_VERSION) || - !SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION) || - !SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_2_VERSION)) { - fprintf(stderr, "Could not set valid DTLS version.\n"); - return false; - } - - if (SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION) || - SSL_CTX_set_max_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */) || - SSL_CTX_set_max_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */) || - SSL_CTX_set_max_proto_version(ctx.get(), 0x1234) || - SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION) || - SSL_CTX_set_min_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */) || - SSL_CTX_set_min_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */) || - SSL_CTX_set_min_proto_version(ctx.get(), 0x1234)) { - fprintf(stderr, "Unexpectedly set invalid DTLS version.\n"); - return false; - } + ASSERT_TRUE(ctx); - if (!SSL_CTX_set_max_proto_version(ctx.get(), 0) || - !SSL_CTX_set_min_proto_version(ctx.get(), 0)) { - fprintf(stderr, "Could not set default DTLS version.\n"); - return false; - } + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_VERSION)); + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), DTLS1_2_VERSION)); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_VERSION)); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), DTLS1_2_VERSION)); - if (ctx->min_version != TLS1_1_VERSION || - ctx->max_version != TLS1_2_VERSION) { - fprintf(stderr, "Default DTLS versions were incorrect (%04x and %04x).\n", - ctx->min_version, ctx->max_version); - return false; - } + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), TLS1_VERSION)); + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */)); + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */)); + EXPECT_FALSE(SSL_CTX_set_max_proto_version(ctx.get(), 0x1234)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), TLS1_VERSION)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfefe /* DTLS 1.1 */)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0xfffe /* DTLS 0.1 */)); + EXPECT_FALSE(SSL_CTX_set_min_proto_version(ctx.get(), 0x1234)); - return true; + EXPECT_TRUE(SSL_CTX_set_max_proto_version(ctx.get(), 0)); + EXPECT_EQ(TLS1_2_VERSION, ctx->max_version); + EXPECT_TRUE(SSL_CTX_set_min_proto_version(ctx.get(), 0)); + EXPECT_EQ(TLS1_1_VERSION, ctx->min_version); } static const char *GetVersionName(uint16_t version) { @@ -3279,10 +3075,8 @@ TEST(SSLTest, GetCertificate) { bssl::UniquePtr<uint8_t> free_der3(der3); // They must also encode identically. - ASSERT_EQ(der2_len, der_len); - EXPECT_EQ(0, OPENSSL_memcmp(der, der2, static_cast<size_t>(der_len))); - ASSERT_EQ(der3_len, der_len); - EXPECT_EQ(0, OPENSSL_memcmp(der, der3, static_cast<size_t>(der_len))); + EXPECT_EQ(Bytes(der, der_len), Bytes(der2, der2_len)); + EXPECT_EQ(Bytes(der, der_len), Bytes(der3, der3_len)); } // TODO(davidben): Convert this file to GTest properly. @@ -3313,28 +3107,20 @@ TEST(SSLTest, AllTests) { // Test the padding extension at TLS 1.3 with a TLS 1.3 session, so there // will be a PSK binder after the padding extension. !TestPaddingExtension(TLS1_3_VERSION, TLS1_3_DRAFT_VERSION) || - !TestClientCAList() || !TestInternalSessionCache() || !ForEachVersion(TestSequenceNumber) || !ForEachVersion(TestOneSidedShutdown) || - !TestSessionDuplication() || - !TestSetFD() || - !TestSetBIO() || !ForEachVersion(TestGetPeerCertificate) || !ForEachVersion(TestRetainOnlySHA256OfCerts) || !TestClientHello() || !ForEachVersion(TestSessionIDContext) || !ForEachVersion(TestSessionTimeout) || - !ForEachVersion(TestSessionTimeoutCertCallback) || !ForEachVersion(TestSNICallback) || - !TestEarlyCallbackVersionSwitch() || - !TestSetVersion() || !ForEachVersion(TestVersion) || !ForEachVersion(TestALPNCipherAvailable) || !ForEachVersion(TestSSLClearSessionResumption) || !ForEachVersion(TestAutoChain) || !ForEachVersion(TestSSLWriteRetry)) { - ERR_print_errors_fp(stderr); ADD_FAILURE() << "Tests failed"; } } diff --git a/src/ssl/s3_enc.c b/src/ssl/ssl_transcript.c index bf82e086..9cc37778 100644 --- a/src/ssl/s3_enc.c +++ b/src/ssl/ssl_transcript.c @@ -138,84 +138,22 @@ #include <assert.h> #include <string.h> +#include <openssl/buf.h> +#include <openssl/digest.h> #include <openssl/err.h> -#include <openssl/evp.h> #include <openssl/mem.h> #include <openssl/md5.h> #include <openssl/nid.h> +#include <openssl/sha.h> #include "../crypto/internal.h" #include "internal.h" -static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len) { - EVP_MD_CTX md5; - EVP_MD_CTX sha1; - uint8_t buf[16], smd[SHA_DIGEST_LENGTH]; - uint8_t c = 'A'; - size_t i, j, k; - - k = 0; - EVP_MD_CTX_init(&md5); - EVP_MD_CTX_init(&sha1); - for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) { - k++; - if (k > sizeof(buf)) { - /* bug: 'buf' is too small for this ciphersuite */ - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - for (j = 0; j < k; j++) { - buf[j] = c; - } - c++; - if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; - } - EVP_DigestUpdate(&sha1, buf, k); - EVP_DigestUpdate(&sha1, secret, secret_len); - /* |label| is ignored for SSLv3. */ - if (seed1_len) { - EVP_DigestUpdate(&sha1, seed1, seed1_len); - } - if (seed2_len) { - EVP_DigestUpdate(&sha1, seed2, seed2_len); - } - EVP_DigestFinal_ex(&sha1, smd, NULL); - - if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { - OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); - return 0; - } - EVP_DigestUpdate(&md5, secret, secret_len); - EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH); - if (i + MD5_DIGEST_LENGTH > out_len) { - EVP_DigestFinal_ex(&md5, smd, NULL); - OPENSSL_memcpy(out, smd, out_len - i); - } else { - EVP_DigestFinal_ex(&md5, out, NULL); - } - - out += MD5_DIGEST_LENGTH; - } - - OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); - EVP_MD_CTX_cleanup(&md5); - EVP_MD_CTX_cleanup(&sha1); - - return 1; -} - -int ssl3_init_handshake_buffer(SSL *ssl) { - ssl3_free_handshake_buffer(ssl); - ssl3_free_handshake_hash(ssl); - ssl->s3->handshake_buffer = BUF_MEM_new(); - return ssl->s3->handshake_buffer != NULL; +int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) { + SSL_TRANSCRIPT_cleanup(transcript); + transcript->buffer = BUF_MEM_new(); + return transcript->buffer != NULL; } /* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then @@ -229,78 +167,113 @@ static int init_digest_with_data(EVP_MD_CTX *ctx, const EVP_MD *md, return 1; } -int ssl3_init_handshake_hash(SSL *ssl) { - ssl3_free_handshake_hash(ssl); +int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version, + int algorithm_prf) { + const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version); - uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl); - if (!init_digest_with_data(&ssl->s3->handshake_hash, - ssl_get_handshake_digest(algorithm_prf), - ssl->s3->handshake_buffer)) { - return 0; + /* To support SSL 3.0's Finished and CertificateVerify constructions, + * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed, + * we can simplify this. */ + if (md == EVP_md5_sha1()) { + if (!init_digest_with_data(&transcript->md5, EVP_md5(), + transcript->buffer)) { + return 0; + } + md = EVP_sha1(); } - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT && - !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(), - ssl->s3->handshake_buffer)) { + if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) { return 0; } return 1; } -void ssl3_free_handshake_hash(SSL *ssl) { - EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash); - EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5); +void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) { + SSL_TRANSCRIPT_free_buffer(transcript); + EVP_MD_CTX_cleanup(&transcript->hash); + EVP_MD_CTX_cleanup(&transcript->md5); } -void ssl3_free_handshake_buffer(SSL *ssl) { - BUF_MEM_free(ssl->s3->handshake_buffer); - ssl->s3->handshake_buffer = NULL; +void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) { + BUF_MEM_free(transcript->buffer); + transcript->buffer = NULL; } -int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) { +size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) { + return EVP_MD_size(SSL_TRANSCRIPT_md(transcript)); +} + +const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) { + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + return EVP_md5_sha1(); + } + return EVP_MD_CTX_md(&transcript->hash); +} + +int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in, + size_t in_len) { /* Depending on the state of the handshake, either the handshake buffer may be * active, the rolling hash, or both. */ - - if (ssl->s3->handshake_buffer != NULL) { - size_t new_len = ssl->s3->handshake_buffer->length + in_len; + if (transcript->buffer != NULL) { + size_t new_len = transcript->buffer->length + in_len; if (new_len < in_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); return 0; } - if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) { + if (!BUF_MEM_grow(transcript->buffer, new_len)) { return 0; } - OPENSSL_memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in, - in_len); + OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len); } - if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len); + if (EVP_MD_CTX_md(&transcript->hash) != NULL) { + EVP_DigestUpdate(&transcript->hash, in, in_len); } - if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) { - EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len); + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + EVP_DigestUpdate(&transcript->md5, in, in_len); } + return 1; } -static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, - size_t sender_len, uint8_t *p) { - unsigned int ret; +int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len) { + int ret = 0; + EVP_MD_CTX ctx; + EVP_MD_CTX_init(&ctx); + unsigned md5_len = 0; + if (EVP_MD_CTX_md(&transcript->md5) != NULL) { + if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) || + !EVP_DigestFinal_ex(&ctx, out, &md5_len)) { + goto err; + } + } + + unsigned len; + if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) || + !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) { + goto err; + } + + *out_len = md5_len + len; + ret = 1; + +err: + EVP_MD_CTX_cleanup(&ctx); + return ret; +} + +static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript, + const SSL_SESSION *session, + const EVP_MD_CTX *ctx_template, + const char *sender, size_t sender_len, + uint8_t *p, size_t *out_len) { + unsigned int len; size_t npad, n; unsigned int i; uint8_t md_buf[EVP_MAX_MD_SIZE]; EVP_MD_CTX ctx; - const EVP_MD_CTX *ctx_template; - - if (md_nid == NID_md5) { - ctx_template = &ssl->s3->handshake_md5; - } else if (md_nid == EVP_MD_CTX_type(&ssl->s3->handshake_hash)) { - ctx_template = &ssl->s3->handshake_hash; - } else { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST); - return 0; - } EVP_MD_CTX_init(&ctx); if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) { @@ -325,11 +298,6 @@ static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, n = EVP_MD_CTX_size(&ctx); - SSL_SESSION *session = ssl->session; - if (ssl->s3->new_session != NULL) { - session = ssl->s3->new_session; - } - npad = (48 / n) * n; if (sender != NULL) { EVP_DigestUpdate(&ctx, sender, sender_len); @@ -346,61 +314,92 @@ static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender, EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length); EVP_DigestUpdate(&ctx, kPad2, npad); EVP_DigestUpdate(&ctx, md_buf, i); - EVP_DigestFinal_ex(&ctx, p, &ret); + EVP_DigestFinal_ex(&ctx, p, &len); EVP_MD_CTX_cleanup(&ctx); - return ret; + *out_len = len; + return 1; } -static int ssl3_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) { - const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST - : SSL3_MD_CLIENT_FINISHED_CONST; - const size_t sender_len = 4; - int ret, sha1len; - ret = ssl3_handshake_mac(ssl, NID_md5, sender, sender_len, out); - if (ret == 0) { +int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript, + uint8_t *out, size_t *out_len, + const SSL_SESSION *session, + int signature_algorithm) { + if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - out += ret; + if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) { + size_t md5_len, len; + if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out, + &md5_len) || + !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, + out + md5_len, &len)) { + return 0; + } + *out_len = md5_len + len; + return 1; + } - sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, sender_len, out); - if (sha1len == 0) { - return 0; + if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) { + return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0, + out, out_len); } - ret += sha1len; - return ret; + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; } -int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out, - size_t *out_len, uint16_t signature_algorithm) { - assert(ssl3_protocol_version(ssl) == SSL3_VERSION); - - if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) { - if (ssl3_handshake_mac(ssl, NID_md5, NULL, 0, out) == 0 || - ssl3_handshake_mac(ssl, NID_sha1, NULL, 0, - out + MD5_DIGEST_LENGTH) == 0) { +int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out, + size_t *out_len, const SSL_SESSION *session, + int from_server, uint16_t version) { + if (version == SSL3_VERSION) { + if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - *out_md = EVP_md5_sha1(); - *out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH; - } else if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) { - if (ssl3_handshake_mac(ssl, NID_sha1, NULL, 0, out) == 0) { + + const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST + : SSL3_MD_CLIENT_FINISHED_CONST; + const size_t sender_len = 4; + size_t md5_len, len; + if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender, + sender_len, out, &md5_len) || + !ssl3_handshake_mac(transcript, session, &transcript->hash, sender, + sender_len, out + md5_len, &len)) { return 0; } - *out_md = EVP_sha1(); - *out_len = SHA_DIGEST_LENGTH; - } else { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + + *out_len = md5_len + len; + return 1; + } + + /* At this point, the handshake should have released the handshake buffer on + * its own. */ + assert(transcript->buffer == NULL); + + const char *label = TLS_MD_CLIENT_FINISH_CONST; + size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; + if (from_server) { + label = TLS_MD_SERVER_FINISH_CONST; + label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; + } + + uint8_t digests[EVP_MAX_MD_SIZE]; + size_t digests_len; + if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) { return 0; } + static const size_t kFinishedLen = 12; + if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen, + session->master_key, session->master_key_length, label, + label_len, digests, digests_len, NULL, 0)) { + return 0; + } + + *out_len = kFinishedLen; return 1; } - -const SSL3_ENC_METHOD SSLv3_enc_data = { - ssl3_prf, - ssl3_final_finish_mac, -}; diff --git a/src/ssl/ssl_x509.c b/src/ssl/ssl_x509.c index 5d78deb2..2955c213 100644 --- a/src/ssl/ssl_x509.c +++ b/src/ssl/ssl_x509.c @@ -140,8 +140,15 @@ #include <openssl/ssl.h> +#include <assert.h> + +#include <openssl/asn1.h> +#include <openssl/bytestring.h> +#include <openssl/err.h> +#include <openssl/pem.h> #include <openssl/stack.h> #include <openssl/x509.h> +#include <openssl/x509v3.h> #include <openssl/x509_vfy.h> #include "internal.h" @@ -281,23 +288,6 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { X509_VERIFY_PARAM_set_depth(ctx->param, depth); } -static X509 *ssl_cert_get0_leaf(CERT *cert) { - if (cert->x509_leaf == NULL && - !ssl_cert_cache_leaf_cert(cert)) { - return NULL; - } - - return cert->x509_leaf; -} - -X509 *SSL_get_certificate(const SSL *ssl) { - return ssl_cert_get0_leaf(ssl->cert); -} - -X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { - return ssl_cert_get0_leaf(ctx->cert); -} - int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { return X509_STORE_set_default_paths(ctx->cert_store); } @@ -329,3 +319,497 @@ void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store) { X509_STORE_free(ctx->cert_store); ctx->cert_store = store; } + +static void ssl_crypto_x509_flush_cached_leaf(CERT *cert) { + X509_free(cert->x509_leaf); + cert->x509_leaf = NULL; +} + +static void ssl_crypto_x509_flush_cached_chain(CERT *cert) { + sk_X509_pop_free(cert->x509_chain, X509_free); + cert->x509_chain = NULL; +} + +static void ssl_crypto_x509_clear(CERT *cert) { + ssl_crypto_x509_flush_cached_leaf(cert); + ssl_crypto_x509_flush_cached_chain(cert); + + X509_free(cert->x509_stash); + cert->x509_stash = NULL; +} + +static int ssl_crypto_x509_session_cache_objects(SSL_SESSION *sess) { + STACK_OF(X509) *chain = NULL; + const size_t num_certs = sk_CRYPTO_BUFFER_num(sess->certs); + + if (num_certs > 0) { + chain = sk_X509_new_null(); + if (chain == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + X509 *leaf = NULL; + for (size_t i = 0; i < num_certs; i++) { + X509 *x509 = X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(sess->certs, i)); + if (x509 == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); + goto err; + } + if (!sk_X509_push(chain, x509)) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + X509_free(x509); + goto err; + } + if (i == 0) { + leaf = x509; + } + } + + sk_X509_pop_free(sess->x509_chain, X509_free); + sess->x509_chain = chain; + sk_X509_pop_free(sess->x509_chain_without_leaf, X509_free); + sess->x509_chain_without_leaf = NULL; + + X509_free(sess->x509_peer); + if (leaf != NULL) { + X509_up_ref(leaf); + } + sess->x509_peer = leaf; + + return 1; + +err: + sk_X509_pop_free(chain, X509_free); + return 0; +} + +static int ssl_crypto_x509_session_dup(SSL_SESSION *new_session, + const SSL_SESSION *session) { + if (session->x509_peer != NULL) { + X509_up_ref(session->x509_peer); + new_session->x509_peer = session->x509_peer; + } + if (session->x509_chain != NULL) { + new_session->x509_chain = X509_chain_up_ref(session->x509_chain); + if (new_session->x509_chain == NULL) { + return 0; + } + } + + return 1; +} + +static void ssl_crypto_x509_session_clear(SSL_SESSION *session) { + X509_free(session->x509_peer); + session->x509_peer = NULL; + sk_X509_pop_free(session->x509_chain, X509_free); + session->x509_chain = NULL; + sk_X509_pop_free(session->x509_chain_without_leaf, X509_free); + session->x509_chain_without_leaf = NULL; +} + +const SSL_X509_METHOD ssl_crypto_x509_method = { + ssl_crypto_x509_clear, + ssl_crypto_x509_flush_cached_chain, + ssl_crypto_x509_flush_cached_leaf, + ssl_crypto_x509_session_cache_objects, + ssl_crypto_x509_session_dup, + ssl_crypto_x509_session_clear, +}; + +/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised + * contents of |x509|. */ +static CRYPTO_BUFFER *x509_to_buffer(X509 *x509) { + uint8_t *buf = NULL; + int cert_len = i2d_X509(x509, &buf); + if (cert_len <= 0) { + return 0; + } + + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL); + OPENSSL_free(buf); + + return buffer; +} + +static int ssl_use_certificate(CERT *cert, X509 *x) { + if (x == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + CRYPTO_BUFFER *buffer = x509_to_buffer(x); + if (buffer == NULL) { + return 0; + } + + const int ok = ssl_set_cert(cert, buffer); + CRYPTO_BUFFER_free(buffer); + return ok; +} + +int SSL_use_certificate(SSL *ssl, X509 *x) { + return ssl_use_certificate(ssl->cert, x); +} + +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { + return ssl_use_certificate(ctx->cert, x); +} + +/* ssl_cert_cache_leaf_cert sets |cert->x509_leaf|, if currently NULL, from the + * first element of |cert->chain|. */ +static int ssl_cert_cache_leaf_cert(CERT *cert) { + assert(cert->x509_method); + + if (cert->x509_leaf != NULL || + cert->chain == NULL) { + return 1; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!leaf) { + return 1; + } + + cert->x509_leaf = X509_parse_from_buffer(leaf); + return cert->x509_leaf != NULL; +} + +static X509 *ssl_cert_get0_leaf(CERT *cert) { + if (cert->x509_leaf == NULL && + !ssl_cert_cache_leaf_cert(cert)) { + return NULL; + } + + return cert->x509_leaf; +} + +X509 *SSL_get_certificate(const SSL *ssl) { + return ssl_cert_get0_leaf(ssl->cert); +} + +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { + return ssl_cert_get0_leaf(ctx->cert); +} + +/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */ +static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) { + STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null(); + if (chain == NULL) { + return NULL; + } + + if (!sk_CRYPTO_BUFFER_push(chain, NULL)) { + sk_CRYPTO_BUFFER_free(chain); + return NULL; + } + + return chain; +} + +/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised + * forms of elements of |chain|. It returns one on success or zero on error, in + * which case no change to |cert->chain| is made. It preverses the existing + * leaf from |cert->chain|, if any. */ +static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) { + STACK_OF(CRYPTO_BUFFER) *new_chain = NULL; + + if (cert->chain != NULL) { + new_chain = sk_CRYPTO_BUFFER_new_null(); + if (new_chain == NULL) { + return 0; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) { + goto err; + } + /* |leaf| might be NULL if it's a “leafless” chain. */ + if (leaf != NULL) { + CRYPTO_BUFFER_up_ref(leaf); + } + } + + for (size_t i = 0; i < sk_X509_num(chain); i++) { + if (new_chain == NULL) { + new_chain = new_leafless_chain(); + if (new_chain == NULL) { + goto err; + } + } + + CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i)); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(new_chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + goto err; + } + } + + sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); + cert->chain = new_chain; + + return 1; + +err: + sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free); + return 0; +} + +static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { + if (!ssl_cert_set_chain(cert, chain)) { + return 0; + } + + sk_X509_pop_free(chain, X509_free); + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { + if (!ssl_cert_set_chain(cert, chain)) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_append_cert(CERT *cert, X509 *x509) { + assert(cert->x509_method); + + CRYPTO_BUFFER *buffer = x509_to_buffer(x509); + if (buffer == NULL) { + return 0; + } + + if (cert->chain != NULL) { + if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + return 0; + } + + return 1; + } + + cert->chain = new_leafless_chain(); + if (cert->chain == NULL || + !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + sk_CRYPTO_BUFFER_free(cert->chain); + cert->chain = NULL; + return 0; + } + + return 1; +} + +static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { + if (!ssl_cert_append_cert(cert, x509)) { + return 0; + } + + X509_free(cert->x509_stash); + cert->x509_stash = x509; + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { + if (!ssl_cert_append_cert(cert, x509)) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(cert); + return 1; +} + +int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { + return ssl_cert_set0_chain(ctx->cert, chain); +} + +int SSL_CTX_set1_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { + return ssl_cert_set1_chain(ctx->cert, chain); +} + +int SSL_set0_chain(SSL *ssl, STACK_OF(X509) *chain) { + return ssl_cert_set0_chain(ssl->cert, chain); +} + +int SSL_set1_chain(SSL *ssl, STACK_OF(X509) *chain) { + return ssl_cert_set1_chain(ssl->cert, chain); +} + +int SSL_CTX_add0_chain_cert(SSL_CTX *ctx, X509 *x509) { + return ssl_cert_add0_chain_cert(ctx->cert, x509); +} + +int SSL_CTX_add1_chain_cert(SSL_CTX *ctx, X509 *x509) { + return ssl_cert_add1_chain_cert(ctx->cert, x509); +} + +int SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x509) { + return SSL_CTX_add0_chain_cert(ctx, x509); +} + +int SSL_add0_chain_cert(SSL *ssl, X509 *x509) { + return ssl_cert_add0_chain_cert(ssl->cert, x509); +} + +int SSL_add1_chain_cert(SSL *ssl, X509 *x509) { + return ssl_cert_add1_chain_cert(ssl->cert, x509); +} + +int SSL_CTX_clear_chain_certs(SSL_CTX *ctx) { + return SSL_CTX_set0_chain(ctx, NULL); +} + +int SSL_CTX_clear_extra_chain_certs(SSL_CTX *ctx) { + return SSL_CTX_clear_chain_certs(ctx); +} + +int SSL_clear_chain_certs(SSL *ssl) { + return SSL_set0_chain(ssl, NULL); +} + +int ssl_auto_chain_if_needed(SSL *ssl) { + /* Only build a chain if there are no intermediates configured and the feature + * isn't disabled. */ + if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || + !ssl_has_certificate(ssl) || + ssl->cert->chain == NULL || + sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) { + return 1; + } + + X509 *leaf = + X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0)); + if (!leaf) { + OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + return 0; + } + + X509_STORE_CTX ctx; + if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) { + X509_free(leaf); + OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + return 0; + } + + /* Attempt to build a chain, ignoring the result. */ + X509_verify_cert(&ctx); + X509_free(leaf); + ERR_clear_error(); + + /* Remove the leaf from the generated chain. */ + X509_free(sk_X509_shift(ctx.chain)); + + const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain); + X509_STORE_CTX_cleanup(&ctx); + if (!ok) { + return 0; + } + + ssl_crypto_x509_flush_cached_chain(ssl->cert); + + return 1; +} + +/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of + * |cert->chain|. */ +static int ssl_cert_cache_chain_certs(CERT *cert) { + assert(cert->x509_method); + + if (cert->x509_chain != NULL || + cert->chain == NULL || + sk_CRYPTO_BUFFER_num(cert->chain) < 2) { + return 1; + } + + STACK_OF(X509) *chain = sk_X509_new_null(); + if (chain == NULL) { + return 0; + } + + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(cert->chain, i); + X509 *x509 = X509_parse_from_buffer(buffer); + if (x509 == NULL || + !sk_X509_push(chain, x509)) { + X509_free(x509); + goto err; + } + } + + cert->x509_chain = chain; + return 1; + +err: + sk_X509_pop_free(chain, X509_free); + return 0; +} + +int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ctx->cert)) { + *out_chain = NULL; + return 0; + } + + *out_chain = ctx->cert->x509_chain; + return 1; +} + +int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, + STACK_OF(X509) **out_chain) { + return SSL_CTX_get0_chain_certs(ctx, out_chain); +} + +int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ssl->cert)) { + *out_chain = NULL; + return 0; + } + + *out_chain = ssl->cert->x509_chain; + return 1; +} + +static SSL_SESSION *ssl_session_new_with_crypto_x509(void) { + return ssl_session_new(&ssl_crypto_x509_method); +} + +SSL_SESSION *d2i_SSL_SESSION_bio(BIO *bio, SSL_SESSION **out) { + return ASN1_d2i_bio_of(SSL_SESSION, ssl_session_new_with_crypto_x509, + d2i_SSL_SESSION, bio, out); +} + +int i2d_SSL_SESSION_bio(BIO *bio, const SSL_SESSION *session) { + return ASN1_i2d_bio_of(SSL_SESSION, i2d_SSL_SESSION, bio, session); +} + +IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) + +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { + if (length < 0) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return NULL; + } + + CBS cbs; + CBS_init(&cbs, *pp, length); + + SSL_SESSION *ret = SSL_SESSION_parse(&cbs, &ssl_crypto_x509_method, + NULL /* no buffer pool */); + if (ret == NULL) { + return NULL; + } + + if (a) { + SSL_SESSION_free(*a); + *a = ret; + } + *pp = CBS_data(&cbs); + return ret; +} diff --git a/src/ssl/t1_enc.c b/src/ssl/t1_enc.c index 5e5c3483..d01992e7 100644 --- a/src/ssl/t1_enc.c +++ b/src/ssl/t1_enc.c @@ -224,18 +224,17 @@ err: return ret; } -static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len, - const uint8_t *secret, size_t secret_len, const char *label, - size_t label_len, const uint8_t *seed1, size_t seed1_len, - const uint8_t *seed2, size_t seed2_len) { +int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, const char *label, + size_t label_len, const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { if (out_len == 0) { return 1; } OPENSSL_memset(out, 0, out_len); - uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl); - if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) { + if (digest == EVP_md5_sha1()) { /* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and * MD5, MD5 first. */ size_t secret_half = secret_len - (secret_len / 2); @@ -248,17 +247,82 @@ static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len, /* Note that, if |secret_len| is odd, the two halves share a byte. */ secret = secret + (secret_len - secret_half); secret_len = secret_half; + + digest = EVP_sha1(); } - if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf), - secret, secret_len, (const uint8_t *)label, label_len, - seed1, seed1_len, seed2, seed2_len)) { + if (!tls1_P_hash(out, out_len, digest, secret, secret_len, + (const uint8_t *)label, label_len, seed1, seed1_len, seed2, + seed2_len)) { return 0; } return 1; } +static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret, + size_t secret_len, const char *label, size_t label_len, + const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { + EVP_MD_CTX md5; + EVP_MD_CTX sha1; + uint8_t buf[16], smd[SHA_DIGEST_LENGTH]; + uint8_t c = 'A'; + size_t i, j, k; + + k = 0; + EVP_MD_CTX_init(&md5); + EVP_MD_CTX_init(&sha1); + for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) { + k++; + if (k > sizeof(buf)) { + /* bug: 'buf' is too small for this ciphersuite */ + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + + for (j = 0; j < k; j++) { + buf[j] = c; + } + c++; + if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) { + OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + return 0; + } + EVP_DigestUpdate(&sha1, buf, k); + EVP_DigestUpdate(&sha1, secret, secret_len); + /* |label| is ignored for SSLv3. */ + if (seed1_len) { + EVP_DigestUpdate(&sha1, seed1, seed1_len); + } + if (seed2_len) { + EVP_DigestUpdate(&sha1, seed2, seed2_len); + } + EVP_DigestFinal_ex(&sha1, smd, NULL); + + if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) { + OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP); + return 0; + } + EVP_DigestUpdate(&md5, secret, secret_len); + EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH); + if (i + MD5_DIGEST_LENGTH > out_len) { + EVP_DigestFinal_ex(&md5, smd, NULL); + OPENSSL_memcpy(out, smd, out_len - i); + } else { + EVP_DigestFinal_ex(&md5, out, NULL); + } + + out += MD5_DIGEST_LENGTH; + } + + OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH); + EVP_MD_CTX_cleanup(&md5); + EVP_MD_CTX_cleanup(&sha1); + + return 1; +} + static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (hs->key_block_len != 0) { @@ -385,112 +449,58 @@ size_t SSL_get_key_block_len(const SSL *ssl) { } int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { - return ssl->s3->enc_method->prf( - ssl, out, out_len, SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length, TLS_MD_KEY_EXPANSION_CONST, - TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE); -} - -static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len, - size_t max_out) { - int ret = 0; - EVP_MD_CTX ctx_copy; - EVP_MD_CTX_init(&ctx_copy); - - if (EVP_MD_CTX_size(ctx) > max_out) { - OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); - goto err; + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); } - unsigned len; - if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) || - !EVP_DigestFinal_ex(&ctx_copy, out, &len)) { - goto err; - } - assert(len == EVP_MD_CTX_size(ctx)); - - *out_len = len; - ret = 1; - -err: - EVP_MD_CTX_cleanup(&ctx_copy); - return ret; -} - -/* tls1_handshake_digest calculates the current handshake hash and writes it to - * |out|, which has space for |out_len| bytes. It returns the number of bytes - * written or -1 in the event of an error. This function works on a copy of the - * underlying digests so can be called multiple times and prior to the final - * update etc. */ -int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len) { - size_t md5_len = 0; - if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL && - !append_digest(&ssl->s3->handshake_md5, out, &md5_len, out_len)) { - return -1; - } - - size_t len; - if (!append_digest(&ssl->s3->handshake_hash, out + md5_len, &len, - out_len - md5_len)) { - return -1; - } - - return (int)(md5_len + len); -} -static int tls1_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) { - /* At this point, the handshake should have released the handshake buffer on - * its own. */ - assert(ssl->s3->handshake_buffer == NULL); - - const char *label = TLS_MD_CLIENT_FINISH_CONST; - size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; - if (from_server) { - label = TLS_MD_SERVER_FINISH_CONST; - label_len = TLS_MD_SERVER_FINISH_CONST_SIZE; - } - - uint8_t buf[EVP_MAX_MD_SIZE]; - int digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf)); - if (digests_len < 0) { + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - - static const size_t kFinishedLen = 12; - if (!ssl->s3->enc_method->prf(ssl, out, kFinishedLen, - SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length, label, - label_len, buf, digests_len, NULL, 0)) { - return 0; - } - - return (int)kFinishedLen; + return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, + TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE); } -int tls1_generate_master_secret(SSL *ssl, uint8_t *out, +int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, const uint8_t *premaster, size_t premaster_len) { + const SSL *ssl = hs->ssl; if (ssl->s3->tmp.extended_master_secret) { uint8_t digests[EVP_MAX_MD_SIZE]; - int digests_len = tls1_handshake_digest(ssl, digests, sizeof(digests)); - if (digests_len == -1) { - return 0; - } - - if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster, - premaster_len, - TLS_MD_EXTENDED_MASTER_SECRET_CONST, - TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, - digests, digests_len, NULL, 0)) { + size_t digests_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) || + !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, + SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_EXTENDED_MASTER_SECRET_CONST, + TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests, + digests_len, NULL, 0)) { return 0; } } else { - if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster, - premaster_len, TLS_MD_MASTER_SECRET_CONST, - TLS_MD_MASTER_SECRET_CONST_SIZE, - ssl->s3->client_random, SSL3_RANDOM_SIZE, - ssl->s3->server_random, SSL3_RANDOM_SIZE)) { - return 0; + if (ssl3_protocol_version(ssl) == SSL3_VERSION) { + if (!ssl3_prf(out, SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE)) { + return 0; + } + } else { + if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out, + SSL3_MASTER_SECRET_SIZE, premaster, premaster_len, + TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE, + ssl->s3->client_random, SSL3_RANDOM_SIZE, + ssl->s3->server_random, SSL3_RANDOM_SIZE)) { + return 0; + } } } @@ -538,16 +548,15 @@ int SSL_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len); } - int ret = - ssl->s3->enc_method->prf(ssl, out, out_len, - SSL_get_session(ssl)->master_key, - SSL_get_session(ssl)->master_key_length, label, - label_len, seed, seed_len, NULL, 0); + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + int ret = tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key, + SSL_get_session(ssl)->master_key_length, label, label_len, + seed, seed_len, NULL, 0); OPENSSL_free(seed); return ret; } - -const SSL3_ENC_METHOD TLSv1_enc_data = { - tls1_prf, - tls1_final_finish_mac, -}; diff --git a/src/ssl/t1_lib.c b/src/ssl/t1_lib.c index 8091787a..7723ccd3 100644 --- a/src/ssl/t1_lib.c +++ b/src/ssl/t1_lib.c @@ -1371,15 +1371,16 @@ static int ext_sct_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { /* The extension shouldn't be sent when resuming sessions. */ if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || ssl->s3->session_reused || - ssl->ctx->signed_cert_timestamp_list_length == 0) { + ssl->signed_cert_timestamp_list == NULL) { return 1; } CBB contents; return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) && CBB_add_u16_length_prefixed(out, &contents) && - CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, - ssl->ctx->signed_cert_timestamp_list_length) && + CBB_add_bytes(&contents, + CRYPTO_BUFFER_data(ssl->signed_cert_timestamp_list), + CRYPTO_BUFFER_len(ssl->signed_cert_timestamp_list)) && CBB_flush(out); } @@ -1882,8 +1883,12 @@ static size_t ext_pre_shared_key_clienthello_length(SSL_HANDSHAKE *hs) { return 0; } - const EVP_MD *digest = - ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf); + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + size_t binder_len = EVP_MD_size(digest); return 15 + ssl->session->tlsext_ticklen + binder_len; } @@ -1911,8 +1916,13 @@ static int ext_pre_shared_key_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { /* Fill in a placeholder zero binder of the appropriate length. It will be * computed and filled in later after length prefixes are computed. */ uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0}; - const EVP_MD *digest = - ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf); + + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } + size_t binder_len = EVP_MD_size(digest); CBB contents, identity, ticket, binders, binder; @@ -2961,7 +2971,7 @@ static int ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs, int ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, const SSL_CLIENT_HELLO *client_hello) { SSL *const ssl = hs->ssl; - int alert = -1; + int alert = SSL_AD_DECODE_ERROR; if (ssl_scan_clienthello_tlsext(hs, client_hello, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; @@ -3084,7 +3094,7 @@ static int ssl_check_clienthello_tlsext(SSL_HANDSHAKE *hs) { int ssl_parse_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs) { SSL *const ssl = hs->ssl; - int alert = -1; + int alert = SSL_AD_DECODE_ERROR; if (ssl_scan_serverhello_tlsext(hs, cbs, &alert) <= 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return 0; @@ -3203,7 +3213,8 @@ int tls_process_ticket(SSL *ssl, SSL_SESSION **out_session, #endif /* Decode the session. */ - SSL_SESSION *session = SSL_SESSION_from_bytes(plaintext, plaintext_len); + SSL_SESSION *session = + SSL_SESSION_from_bytes(plaintext, plaintext_len, ssl->ctx); if (session == NULL) { ERR_clear_error(); /* Don't leave an error on the queue. */ goto done; @@ -3324,7 +3335,8 @@ int tls1_choose_signature_algorithm(SSL_HANDSHAKE *hs, uint16_t *out) { return 0; } -int tls1_verify_channel_id(SSL *ssl) { +int tls1_verify_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; int ret = 0; uint16_t extension_type; CBS extension, channel_id; @@ -3383,7 +3395,7 @@ int tls1_verify_channel_id(SSL *ssl) { uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!tls1_channel_id_hash(ssl, digest, &digest_len)) { + if (!tls1_channel_id_hash(hs, digest, &digest_len)) { goto err; } @@ -3412,10 +3424,11 @@ err: return ret; } -int tls1_write_channel_id(SSL *ssl, CBB *cbb) { +int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb) { + SSL *const ssl = hs->ssl; uint8_t digest[EVP_MAX_MD_SIZE]; size_t digest_len; - if (!tls1_channel_id_hash(ssl, digest, &digest_len)) { + if (!tls1_channel_id_hash(hs, digest, &digest_len)) { return 0; } @@ -3461,11 +3474,12 @@ err: return ret; } -int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { +int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) { + SSL *const ssl = hs->ssl; if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) { uint8_t *msg; size_t msg_len; - if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len, + if (!tls13_get_cert_verify_signature_input(hs, &msg, &msg_len, ssl_cert_verify_channel_id)) { return 0; } @@ -3492,13 +3506,12 @@ int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { ssl->session->original_handshake_hash_len); } - uint8_t handshake_hash[EVP_MAX_MD_SIZE]; - int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash, - sizeof(handshake_hash)); - if (handshake_hash_len < 0) { + uint8_t hs_hash[EVP_MAX_MD_SIZE]; + size_t hs_hash_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) { return 0; } - SHA256_Update(&ctx, handshake_hash, (size_t)handshake_hash_len); + SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len); SHA256_Final(out, &ctx); *out_len = SHA256_DIGEST_LENGTH; return 1; @@ -3507,8 +3520,8 @@ int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) { /* tls1_record_handshake_hashes_for_channel_id records the current handshake * hashes in |ssl->s3->new_session| so that Channel ID resumptions can sign that * data. */ -int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) { - int digest_len; +int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; /* This function should never be called for a resumed session because the * handshake hashes that we wish to record are for the original, full * handshake. */ @@ -3516,15 +3529,18 @@ int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) { return -1; } - digest_len = - tls1_handshake_digest( - ssl, ssl->s3->new_session->original_handshake_hash, - sizeof(ssl->s3->new_session->original_handshake_hash)); - if (digest_len < 0) { + OPENSSL_COMPILE_ASSERT( + sizeof(ssl->s3->new_session->original_handshake_hash) == EVP_MAX_MD_SIZE, + original_handshake_hash_is_too_small); + + size_t digest_len; + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, + ssl->s3->new_session->original_handshake_hash, + &digest_len)) { return -1; } - assert(sizeof(ssl->s3->new_session->original_handshake_hash) < 256); + OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE <= 0xff, max_md_size_is_too_large); 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 66a71a0a..381f4c2f 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -1477,7 +1477,7 @@ static bool CheckHandshakeProperties(SSL *ssl, bool is_resume) { } if (expected_sha256_client_cert && - SSL_get_session(ssl)->x509_peer != nullptr) { + SSL_get_session(ssl)->certs != nullptr) { fprintf(stderr, "Have both client cert and SHA-256 hash: is_resume:%d.\n", is_resume); return false; diff --git a/src/ssl/test/runner/common.go b/src/ssl/test/runner/common.go index 668f78ce..2e7b0537 100644 --- a/src/ssl/test/runner/common.go +++ b/src/ssl/test/runner/common.go @@ -668,9 +668,16 @@ type ProtocolBugs struct { // ticket before sending it in a resume handshake. FilterTicket func([]byte) ([]byte, error) - // OversizedSessionId causes the session id that is sent with a ticket - // resumption attempt to be too large (33 bytes). - OversizedSessionId bool + // TicketSessionIDLength, if non-zero, is the length of the session ID + // to send with a ticket resumption offer. + TicketSessionIDLength int + + // EmptyTicketSessionID, if true, causes the client to send an empty + // session ID with a ticket resumption offer. For simplicity, this will + // also cause the client to interpret a ServerHello with empty session + // ID as a resumption. (A client which sends empty session ID is + // normally expected to look ahead for ChangeCipherSpec.) + EmptyTicketSessionID bool // ExpectNoTLS12Session, if true, causes the server to fail the // connection if either a session ID or TLS 1.2 ticket is offered. @@ -1291,6 +1298,10 @@ type ProtocolBugs struct { // SendTicketLifetime, if non-zero, is the ticket lifetime to send in // NewSessionTicket messages. SendTicketLifetime time.Duration + + // SendServerNameAck, if true, causes the server to acknowledge the SNI + // extension. + SendServerNameAck bool } func (c *Config) serverInit() { diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index afc19582..162302e8 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -289,8 +289,11 @@ NextCipherSuite: // server accepted the ticket and is resuming a session // (see RFC 5077). sessionIdLen := 16 - if c.config.Bugs.OversizedSessionId { - sessionIdLen = 33 + if c.config.Bugs.TicketSessionIDLength != 0 { + sessionIdLen = c.config.Bugs.TicketSessionIDLength + } + if c.config.Bugs.EmptyTicketSessionID { + sessionIdLen = 0 } hello.sessionId = make([]byte, sessionIdLen) if _, err := io.ReadFull(c.config.rand(), hello.sessionId); err != nil { @@ -860,6 +863,10 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { hs.finishedHash.addEntropy(zeroSecret) clientTrafficSecret := hs.finishedHash.deriveSecret(clientApplicationTrafficLabel) serverTrafficSecret := hs.finishedHash.deriveSecret(serverApplicationTrafficLabel) + c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) + + // Switch to application data keys on read. In particular, any alerts + // from the client certificate are read over these keys. c.in.useTrafficSecret(c.vers, hs.suite, serverTrafficSecret, serverWrite) // If we're expecting 0.5-RTT messages from the server, read them @@ -966,7 +973,6 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // Switch to application data keys. c.out.useTrafficSecret(c.vers, hs.suite, clientTrafficSecret, clientWrite) - c.exporterSecret = hs.finishedHash.deriveSecret(exporterLabel) c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) return nil } @@ -1346,6 +1352,10 @@ func (hs *clientHandshakeState) processServerExtensions(serverExtensions *server func (hs *clientHandshakeState) serverResumedSession() bool { // If the server responded with the same sessionId then it means the // sessionTicket is being used to resume a TLS session. + // + // Note that, if hs.hello.sessionId is a non-nil empty array, this will + // accept an empty session ID from the server as resumption. See + // EmptyTicketSessionID. return hs.session != nil && hs.hello.sessionId != nil && bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId) } diff --git a/src/ssl/test/runner/handshake_messages.go b/src/ssl/test/runner/handshake_messages.go index 1141797c..4ecb3cb2 100644 --- a/src/ssl/test/runner/handshake_messages.go +++ b/src/ssl/test/runner/handshake_messages.go @@ -1082,6 +1082,7 @@ type serverExtensions struct { hasEarlyData bool keyShare keyShareEntry supportedPoints []uint8 + serverNameAck bool } func (m *serverExtensions) marshal(extensions *byteBuilder) { @@ -1187,6 +1188,10 @@ func (m *serverExtensions) marshal(extensions *byteBuilder) { extensions.addU16(extensionEarlyData) extensions.addBytes([]byte{0, 0}) } + if m.serverNameAck { + extensions.addU16(extensionServerName) + extensions.addU16(0) // zero length + } } func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { @@ -1281,7 +1286,7 @@ func (m *serverExtensions) unmarshal(data []byte, version uint16) bool { if length != 0 { return false } - // Ignore this extension from the server. + m.serverNameAck = true case extensionSupportedPoints: // supported_points is illegal in TLS 1.3. if version >= VersionTLS13 { diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index d8ab1a5c..8aa15879 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -1244,6 +1244,8 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server return errors.New("tls: no GREASE extension found") } + serverExtensions.serverNameAck = c.config.Bugs.SendServerNameAck + return nil } diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index 8c9278e3..d6e984a0 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -2290,7 +2290,16 @@ func addBasicTests() { expectedError: ":WRONG_VERSION_NUMBER:", }, { - name: "KeyUpdate", + name: "KeyUpdate-Client", + config: Config{ + MaxVersion: VersionTLS13, + }, + sendKeyUpdates: 1, + keyUpdateRequest: keyUpdateNotRequested, + }, + { + testType: serverTest, + name: "KeyUpdate-Server", config: Config{ MaxVersion: VersionTLS13, }, @@ -2514,11 +2523,6 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto // NULL ciphers must be explicitly enabled. flags = append(flags, "-cipher", "DEFAULT:NULL-SHA") } - if hasComponent(suite.name, "ECDHE-PSK") && hasComponent(suite.name, "GCM") { - // ECDHE_PSK AES_GCM ciphers must be explicitly enabled - // for now. - flags = append(flags, "-cipher", suite.name) - } var shouldServerFail, shouldClientFail bool if hasComponent(suite.name, "ECDHE") && ver.version == VersionSSL30 { @@ -2558,6 +2562,13 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto sendCipherSuite = suite.id } + // For cipher suites and versions where exporters are defined, verify + // that they interoperate. + var exportKeyingMaterial int + if ver.version > VersionSSL30 { + exportKeyingMaterial = 1024 + } + testCases = append(testCases, testCase{ testType: serverTest, protocol: protocol, @@ -2573,12 +2584,13 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto AdvertiseAllConfiguredCiphers: true, }, }, - certFile: certFile, - keyFile: keyFile, - flags: flags, - resumeSession: true, - shouldFail: shouldServerFail, - expectedError: expectedServerError, + certFile: certFile, + keyFile: keyFile, + flags: flags, + resumeSession: true, + shouldFail: shouldServerFail, + expectedError: expectedServerError, + exportKeyingMaterial: exportKeyingMaterial, }) testCases = append(testCases, testCase{ @@ -2597,10 +2609,11 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto SendCipherSuite: sendCipherSuite, }, }, - flags: flags, - resumeSession: true, - shouldFail: shouldClientFail, - expectedError: expectedClientError, + flags: flags, + resumeSession: true, + shouldFail: shouldClientFail, + expectedError: expectedClientError, + exportKeyingMaterial: exportKeyingMaterial, }) if shouldClientFail { @@ -4751,6 +4764,31 @@ func addExtensionTests() { expectedLocalError: "tls: unexpected server name", }) testCases = append(testCases, testCase{ + testType: clientTest, + name: "TolerateServerNameAck-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + SendServerNameAck: true, + }, + }, + flags: []string{"-host-name", "example.com"}, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: clientTest, + name: "UnsolicitedServerNameAck-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + SendServerNameAck: true, + }, + }, + shouldFail: true, + expectedError: ":UNEXPECTED_EXTENSION:", + expectedLocalError: "remote error: unsupported extension", + }) + testCases = append(testCases, testCase{ testType: serverTest, name: "ServerNameExtensionServer-" + ver.name, config: Config{ @@ -5015,19 +5053,53 @@ func addExtensionTests() { }, }) - // Resume with an oversized session id. + // Resume with various lengths of ticket session id. if ver.version < VersionTLS13 { testCases = append(testCases, testCase{ testType: serverTest, - name: "OversizedSessionId-" + ver.name, + name: "TicketSessionIDLength-0-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + EmptyTicketSessionID: true, + }, + }, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TicketSessionIDLength-16-" + ver.name, config: Config{ MaxVersion: ver.version, Bugs: ProtocolBugs{ - OversizedSessionId: true, + TicketSessionIDLength: 16, + }, + }, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TicketSessionIDLength-32-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + TicketSessionIDLength: 32, + }, + }, + resumeSession: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "TicketSessionIDLength-33-" + ver.name, + config: Config{ + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + TicketSessionIDLength: 33, }, }, resumeSession: true, shouldFail: true, + // The maximum session ID length is 32. expectedError: ":DECODE_ERROR:", }) } @@ -8520,7 +8592,7 @@ func addSessionTicketTests() { flags: []string{ "-resumption-delay", "21", }, - resumeSession: true, + resumeSession: true, expectResumeRejected: true, }) } diff --git a/src/ssl/tls13_both.c b/src/ssl/tls13_both.c index a49ee141..19dd555b 100644 --- a/src/ssl/tls13_both.c +++ b/src/ssl/tls13_both.c @@ -102,7 +102,7 @@ int tls13_handshake(SSL_HANDSHAKE *hs) { } int tls13_get_cert_verify_signature_input( - SSL *ssl, uint8_t **out, size_t *out_len, + SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len, enum ssl_cert_verify_context_t cert_verify_context) { CBB cbb; if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) { @@ -140,7 +140,8 @@ int tls13_get_cert_verify_signature_input( uint8_t context_hash[EVP_MAX_MD_SIZE]; size_t context_hash_len; - if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) || + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len) || !CBB_add_bytes(&cbb, context_hash, context_hash_len) || !CBB_finish(&cbb, out, out_len)) { goto err; @@ -232,7 +233,7 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { {TLSEXT_TYPE_certificate_timestamp, &have_sct, &sct}, }; - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_parse_extensions(&extensions, &alert, ext_types, OPENSSL_ARRAY_SIZE(ext_types), 0 /* reject unknown */)) { @@ -306,7 +307,7 @@ int tls13_process_certificate(SSL_HANDSHAKE *hs, int allow_anonymous) { ssl->s3->new_session->certs = certs; certs = NULL; - if (!ssl_session_x509_cache_objects(ssl->s3->new_session)) { + if (!ssl->ctx->x509_method->session_cache_objects(ssl->s3->new_session)) { OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); goto err; @@ -372,7 +373,7 @@ int tls13_process_certificate_verify(SSL_HANDSHAKE *hs) { ssl->s3->new_session->peer_signature_algorithm = signature_algorithm; if (!tls13_get_cert_verify_signature_input( - ssl, &msg, &msg_len, + hs, &msg, &msg_len, ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; @@ -451,13 +452,13 @@ int tls13_add_certificate(SSL_HANDSHAKE *hs) { goto err; } - if (hs->scts_requested && - ssl->ctx->signed_cert_timestamp_list_length != 0) { + if (hs->scts_requested && ssl->signed_cert_timestamp_list != NULL) { CBB contents; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) || !CBB_add_u16_length_prefixed(&extensions, &contents) || - !CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list, - ssl->ctx->signed_cert_timestamp_list_length) || + !CBB_add_bytes(&contents, + CRYPTO_BUFFER_data(ssl->signed_cert_timestamp_list), + CRYPTO_BUFFER_len(ssl->signed_cert_timestamp_list)) || !CBB_flush(&extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; @@ -536,7 +537,7 @@ enum ssl_private_key_result_t tls13_add_certificate_verify(SSL_HANDSHAKE *hs, enum ssl_private_key_result_t sign_result; if (is_first_run) { if (!tls13_get_cert_verify_signature_input( - ssl, &msg, &msg_len, + hs, &msg, &msg_len, ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); goto err; diff --git a/src/ssl/tls13_client.c b/src/ssl/tls13_client.c index 74d3646e..50f7e5a6 100644 --- a/src/ssl/tls13_client.c +++ b/src/ssl/tls13_client.c @@ -74,7 +74,7 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { {TLSEXT_TYPE_cookie, &have_cookie, &cookie}, }; - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_parse_extensions(&extensions, &alert, ext_types, OPENSSL_ARRAY_SIZE(ext_types), 0 /* reject unknown */)) { @@ -135,7 +135,7 @@ static enum ssl_hs_wait_t do_process_hello_retry_request(SSL_HANDSHAKE *hs) { hs->retry_group = group_id; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -207,7 +207,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { {TLSEXT_TYPE_short_header, &have_short_header, &short_header}, }; - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_parse_extensions(&extensions, &alert, ext_types, OPENSSL_ARRAY_SIZE(ext_types), 0 /* reject unknown */)) { @@ -261,7 +261,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { /* Resumption incorporates fresh key material, so refresh the timeout. */ ssl_session_renew_timeout(ssl, ssl->s3->new_session, - ssl->session_psk_dhe_timeout); + ssl->initial_ctx->session_psk_dhe_timeout); } else if (!ssl_get_new_session(hs, 0)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; @@ -271,8 +271,6 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { ssl->s3->tmp.new_cipher = cipher; /* 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; } @@ -283,7 +281,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { ssl->s3->new_session->master_key_length)) { return ssl_hs_error; } - } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) { + } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) { return ssl_hs_error; } @@ -297,6 +295,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { /* Resolve ECDHE and incorporate it into the secret. */ uint8_t *dhe_secret; size_t dhe_secret_len; + alert = SSL_AD_DECODE_ERROR; if (!ssl_ext_key_share_parse_serverhello(hs, &dhe_secret, &dhe_secret_len, &alert, &key_share)) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); @@ -326,7 +325,7 @@ static enum ssl_hs_wait_t do_process_server_hello(SSL_HANDSHAKE *hs) { ssl->s3->short_header = 1; } - if (!ssl_hash_current_message(ssl) || + if (!ssl_hash_current_message(hs) || !tls13_derive_handshake_secrets(hs) || !tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret, hs->hash_len) || @@ -357,7 +356,7 @@ static enum ssl_hs_wait_t do_process_encrypted_extensions(SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -392,7 +391,7 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { return ssl_hs_error; } - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); if (ca_sk == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); @@ -413,7 +412,7 @@ static enum ssl_hs_wait_t do_process_certificate_request(SSL_HANDSHAKE *hs) { sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); hs->ca_names = ca_sk; - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -425,7 +424,7 @@ static enum ssl_hs_wait_t do_process_server_certificate(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || !tls13_process_certificate(hs, 0 /* certificate required */) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -438,7 +437,7 @@ static enum ssl_hs_wait_t do_process_server_certificate_verify( SSL *const ssl = hs->ssl; if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -450,7 +449,7 @@ static enum ssl_hs_wait_t do_process_server_finished(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) || !tls13_process_finished(hs) || - !ssl_hash_current_message(ssl) || + !ssl_hash_current_message(hs) || /* Update the secret to the master secret and derive traffic keys. */ !tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) || !tls13_derive_application_secrets(hs)) { @@ -535,7 +534,7 @@ static enum ssl_hs_wait_t do_complete_second_flight(SSL_HANDSHAKE *hs) { CBB cbb, body; if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) || - !tls1_write_channel_id(ssl, &body) || + !tls1_write_channel_id(hs, &body) || !ssl_add_message_cbb(ssl, &cbb)) { CBB_cleanup(&cbb); return ssl_hs_error; @@ -616,9 +615,8 @@ enum ssl_hs_wait_t tls13_client_handshake(SSL_HANDSHAKE *hs) { int tls13_process_new_session_ticket(SSL *ssl) { int ret = 0; - SSL_SESSION *session = - SSL_SESSION_dup(ssl->s3->established_session, - SSL_SESSION_INCLUDE_NONAUTH); + SSL_SESSION *session = SSL_SESSION_dup(ssl->s3->established_session, + SSL_SESSION_INCLUDE_NONAUTH); if (session == NULL) { return 0; } @@ -662,7 +660,7 @@ int tls13_process_new_session_ticket(SSL *ssl) { &early_data_info}, }; - uint8_t alert; + uint8_t alert = SSL_AD_DECODE_ERROR; if (!ssl_parse_extensions(&extensions, &alert, ext_types, OPENSSL_ARRAY_SIZE(ext_types), 1 /* ignore unknown */)) { diff --git a/src/ssl/tls13_enc.c b/src/ssl/tls13_enc.c index ea9dce84..4d140e3c 100644 --- a/src/ssl/tls13_enc.c +++ b/src/ssl/tls13_enc.c @@ -29,28 +29,25 @@ 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)); + if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl), + hs->ssl->s3->tmp.new_cipher->algorithm_prf)) { + return 0; + } - hs->hash_len = EVP_MD_size(digest); + + hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); /* Initialize the secret to the zero key. */ OPENSSL_memset(hs->secret, 0, hs->hash_len); - /* Initialize the rolling hashes and release the handshake buffer. */ - if (!ssl3_init_handshake_hash(ssl)) { - return 0; - } - ssl3_free_handshake_buffer(ssl); + SSL_TRANSCRIPT_free_buffer(&hs->transcript); return 1; } 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, + return HKDF_extract(hs->secret, &hs->hash_len, + SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret, hs->hash_len); } @@ -83,35 +80,21 @@ static int hkdf_expand_label(uint8_t *out, const EVP_MD *digest, return ret; } -int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) { - EVP_MD_CTX ctx; - EVP_MD_CTX_init(&ctx); - unsigned handshake_len = 0; - int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) && - EVP_DigestFinal_ex(&ctx, out, &handshake_len); - EVP_MD_CTX_cleanup(&ctx); - if (ok) { - *out_len = handshake_len; - } - return ok; -} - /* 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_HANDSHAKE *hs, uint8_t *out, size_t len, const uint8_t *label, size_t label_len) { - 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]; size_t context_hash_len; - if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len)) { + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len)) { return 0; } - return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label, - label_len, context_hash, context_hash_len, len); + return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret, + hs->hash_len, label, label_len, context_hash, + context_hash_len, len); } int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, @@ -124,7 +107,6 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, /* Look up cipher suite properties. */ const EVP_AEAD *aead; - const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); size_t discard; if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard, SSL_get_session(ssl)->cipher, @@ -132,6 +114,9 @@ int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction, return 0; } + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); + /* Derive the key. */ size_t key_len = EVP_AEAD_key_length(aead); uint8_t key[EVP_AEAD_MAX_KEY_LENGTH]; @@ -226,7 +211,8 @@ static const char kTLS13LabelApplicationTraffic[] = "application traffic secret"; int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) { - const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); uint8_t *secret; size_t secret_len; @@ -287,7 +273,6 @@ static int tls13_verify_data(const EVP_MD *digest, uint8_t *out, 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; if (is_server == ssl->server) { @@ -298,9 +283,11 @@ int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, uint8_t context_hash[EVP_MAX_MD_SIZE]; size_t context_hash_len; - if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) || - !tls13_verify_data(digest, out, out_len, traffic_secret, hs->hash_len, - context_hash, context_hash_len)) { + if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash, + &context_hash_len) || + !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len, + traffic_secret, hs->hash_len, context_hash, + context_hash_len)) { return 0; } return 1; @@ -310,7 +297,8 @@ int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, const char *label, size_t label_len, const uint8_t *context, size_t context_len, int use_context) { - const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)); + const EVP_MD *digest = ssl_get_handshake_digest( + SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl)); const uint8_t *hash = NULL; size_t hash_len = 0; @@ -325,8 +313,8 @@ int tls13_export_keying_material(SSL *ssl, uint8_t *out, size_t out_len, static const char kTLS13LabelPSKBinder[] = "resumption psk binder key"; -static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest, - uint8_t *psk, size_t psk_len, uint8_t *context, +static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk, + size_t psk_len, uint8_t *context, size_t context_len, size_t hash_len) { uint8_t binder_context[EVP_MAX_MD_SIZE]; unsigned binder_context_len; @@ -355,9 +343,13 @@ static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest, return 1; } -int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) { - const EVP_MD *digest = - ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf); +int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) { + SSL *const ssl = hs->ssl; + const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl); + if (digest == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } size_t hash_len = EVP_MD_size(digest); if (len < hash_len + 3) { @@ -370,8 +362,8 @@ int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) { uint8_t context[EVP_MAX_MD_SIZE]; unsigned context_len; if (!EVP_DigestInit_ex(&ctx, digest, NULL) || - !EVP_DigestUpdate(&ctx, ssl->s3->handshake_buffer->data, - ssl->s3->handshake_buffer->length) || + !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data, + hs->transcript.buffer->length) || !EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) || !EVP_DigestFinal_ex(&ctx, context, &context_len)) { EVP_MD_CTX_cleanup(&ctx); @@ -381,9 +373,9 @@ int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) { EVP_MD_CTX_cleanup(&ctx); uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; - if (!tls13_psk_binder(ssl, verify_data, digest, ssl->session->master_key, - ssl->session->master_key_length, context, - context_len, hash_len)) { + if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key, + ssl->session->master_key_length, context, context_len, + hash_len)) { return 0; } @@ -391,16 +383,14 @@ int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) { return 1; } -int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, +int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, CBS *binders) { - const EVP_MD *digest = - ssl_get_handshake_digest(session->cipher->algorithm_prf); - size_t hash_len = EVP_MD_size(digest); + size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript); /* Get the full ClientHello, including message header. It must be large enough * to exclude the binders. */ CBS message; - ssl->method->get_current_message(ssl, &message); + hs->ssl->method->get_current_message(hs->ssl, &message); if (CBS_len(&message) < CBS_len(binders) + 2) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; @@ -411,23 +401,25 @@ int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, uint8_t context[EVP_MAX_MD_SIZE]; unsigned context_len; if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2, - context, &context_len, digest, NULL)) { + context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript), + NULL)) { return 0; } uint8_t verify_data[EVP_MAX_MD_SIZE] = {0}; CBS binder; - if (!tls13_psk_binder(ssl, verify_data, digest, session->master_key, - session->master_key_length, context, context_len, - hash_len) || + if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript), + session->master_key, session->master_key_length, + context, context_len, hash_len) || /* We only consider the first PSK, so compare against the first binder. */ !CBS_get_u8_length_prefixed(binders, &binder)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } - int binder_ok = CBS_len(&binder) == hash_len && - CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0; + int binder_ok = + CBS_len(&binder) == hash_len && + CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0; #if defined(BORINGSSL_UNSAFE_FUZZER_MODE) binder_ok = 1; #endif diff --git a/src/ssl/tls13_server.c b/src/ssl/tls13_server.c index 319fe4c2..0278b500 100644 --- a/src/ssl/tls13_server.c +++ b/src/ssl/tls13_server.c @@ -157,6 +157,14 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { return ssl_hs_error; } + /* The PRF hash is now known. Set up the key schedule and hash the + * ClientHello. */ + if (!tls13_init_key_schedule(hs) || + !ssl_hash_current_message(hs)) { + return ssl_hs_error; + } + + /* Decode the ticket if we agree on a PSK key exchange mode. */ uint8_t alert = SSL_AD_DECODE_ERROR; SSL_SESSION *session = NULL; @@ -207,7 +215,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { } } else { /* Check the PSK binder. */ - if (!tls13_verify_psk_binder(ssl, session, &binders)) { + if (!tls13_verify_psk_binder(hs, session, &binders)) { SSL_SESSION_free(session); ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR); return ssl_hs_error; @@ -224,7 +232,7 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { /* Resumption incorporates fresh key material, so refresh the timeout. */ ssl_session_renew_timeout(ssl, ssl->s3->new_session, - ssl->session_psk_dhe_timeout); + ssl->initial_ctx->session_psk_dhe_timeout); } if (ssl->ctx->dos_protection_cb != NULL && @@ -237,27 +245,19 @@ static enum ssl_hs_wait_t do_select_parameters(SSL_HANDSHAKE *hs) { /* HTTP/2 negotiation depends on the cipher suite, so ALPN negotiation was * deferred. Complete it now. */ + alert = SSL_AD_DECODE_ERROR; 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. Set up the key schedule and hash the - * ClientHello. */ - size_t hash_len = - EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl))); - if (!tls13_init_key_schedule(hs) || - !ssl_hash_current_message(ssl)) { - return ssl_hs_error; - } - /* Incorporate the PSK into the running secret. */ if (ssl->s3->session_reused) { if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key, ssl->s3->new_session->master_key_length)) { return ssl_hs_error; } - } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) { + } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) { return ssl_hs_error; } @@ -322,7 +322,7 @@ static enum ssl_hs_wait_t do_process_second_client_hello(SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!ssl_hash_current_message(ssl)) { + if (!ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -484,7 +484,7 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) { if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) || !tls13_process_certificate(hs, allow_anonymous) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -495,7 +495,7 @@ static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) { static enum ssl_hs_wait_t do_process_client_certificate_verify( SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - if (ssl->s3->new_session->x509_peer == NULL) { + if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) { /* Skip this state. */ hs->tls13_state = state_process_channel_id; return ssl_hs_ok; @@ -503,7 +503,7 @@ static enum ssl_hs_wait_t do_process_client_certificate_verify( if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) || !tls13_process_certificate_verify(hs) || - !ssl_hash_current_message(ssl)) { + !ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -512,15 +512,14 @@ static enum ssl_hs_wait_t do_process_client_certificate_verify( } 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) { + if (!hs->ssl->s3->tlsext_channel_id_valid) { hs->tls13_state = state_process_client_finished; return ssl_hs_ok; } - if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) || - !tls1_verify_channel_id(ssl) || - !ssl_hash_current_message(ssl)) { + if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) || + !tls1_verify_channel_id(hs) || + !ssl_hash_current_message(hs)) { return ssl_hs_error; } @@ -532,7 +531,7 @@ static enum ssl_hs_wait_t do_process_client_finished(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) || !tls13_process_finished(hs) || - !ssl_hash_current_message(ssl) || + !ssl_hash_current_message(hs) || /* evp_aead_seal keys have already been switched. */ !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0, hs->hash_len) || diff --git a/src/ssl/tls_method.c b/src/ssl/tls_method.c index 70683e47..eaad2caf 100644 --- a/src/ssl/tls_method.c +++ b/src/ssl/tls_method.c @@ -161,6 +161,7 @@ const SSL_METHOD *TLS_method(void) { static const SSL_METHOD kMethod = { 0, &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -175,6 +176,7 @@ const SSL_METHOD *TLSv1_2_method(void) { static const SSL_METHOD kMethod = { TLS1_2_VERSION, &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -183,6 +185,7 @@ const SSL_METHOD *TLSv1_1_method(void) { static const SSL_METHOD kMethod = { TLS1_1_VERSION, &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -191,6 +194,7 @@ const SSL_METHOD *TLSv1_method(void) { static const SSL_METHOD kMethod = { TLS1_VERSION, &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -199,6 +203,7 @@ const SSL_METHOD *SSLv3_method(void) { static const SSL_METHOD kMethod = { SSL3_VERSION, &kTLSProtocolMethod, + &ssl_crypto_x509_method, }; return &kMethod; } @@ -252,3 +257,24 @@ const SSL_METHOD *TLS_server_method(void) { const SSL_METHOD *TLS_client_method(void) { return TLS_method(); } + +static void ssl_noop_x509_clear(CERT *cert) {} +static void ssl_noop_x509_flush_cached_leaf(CERT *cert) {} +static void ssl_noop_x509_flush_cached_chain(CERT *cert) {} +static int ssl_noop_x509_session_cache_objects(SSL_SESSION *sess) { + return 1; +} +static int ssl_noop_x509_session_dup(SSL_SESSION *new_session, + const SSL_SESSION *session) { + return 1; +} +static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} + +const SSL_X509_METHOD ssl_noop_x509_method = { + ssl_noop_x509_clear, + ssl_noop_x509_flush_cached_chain, + ssl_noop_x509_flush_cached_leaf, + ssl_noop_x509_session_cache_objects, + ssl_noop_x509_session_dup, + ssl_noop_x509_session_clear, +}; diff --git a/src/tool/client.cc b/src/tool/client.cc index 0301a816..8e0ef2d0 100644 --- a/src/tool/client.cc +++ b/src/tool/client.cc @@ -282,16 +282,16 @@ bool Client(const std::vector<std::string> &args) { return false; } - if (args_map.count("-max-version") != 0) { - uint16_t version; - if (!VersionFromString(&version, args_map["-max-version"])) { - fprintf(stderr, "Unknown protocol version: '%s'\n", - args_map["-max-version"].c_str()); - return false; - } - if (!SSL_CTX_set_max_proto_version(ctx.get(), version)) { - return false; - } + uint16_t max_version = TLS1_3_VERSION; + if (args_map.count("-max-version") != 0 && + !VersionFromString(&max_version, args_map["-max-version"])) { + fprintf(stderr, "Unknown protocol version: '%s'\n", + args_map["-max-version"].c_str()); + return false; + } + + if (!SSL_CTX_set_max_proto_version(ctx.get(), max_version)) { + return false; } if (args_map.count("-min-version") != 0) { diff --git a/src/tool/server.cc b/src/tool/server.cc index 94abbbd9..f203df12 100644 --- a/src/tool/server.cc +++ b/src/tool/server.cc @@ -193,16 +193,16 @@ bool Server(const std::vector<std::string> &args) { return false; } - if (args_map.count("-max-version") != 0) { - uint16_t version; - if (!VersionFromString(&version, args_map["-max-version"])) { - fprintf(stderr, "Unknown protocol version: '%s'\n", - args_map["-max-version"].c_str()); - return false; - } - if (!SSL_CTX_set_max_proto_version(ctx.get(), version)) { - return false; - } + uint16_t max_version = TLS1_3_VERSION; + if (args_map.count("-max-version") != 0 && + !VersionFromString(&max_version, args_map["-max-version"])) { + fprintf(stderr, "Unknown protocol version: '%s'\n", + args_map["-max-version"].c_str()); + return false; + } + + if (!SSL_CTX_set_max_proto_version(ctx.get(), max_version)) { + return false; } if (args_map.count("-min-version") != 0) { diff --git a/src/util/all_tests.go b/src/util/all_tests.go index d4bb8023..3cf23206 100644 --- a/src/util/all_tests.go +++ b/src/util/all_tests.go @@ -186,10 +186,9 @@ func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) { } else { cmd = exec.Command(prog, args...) } - var stdoutBuf bytes.Buffer - var stderrBuf bytes.Buffer - cmd.Stdout = &stdoutBuf - cmd.Stderr = &stderrBuf + var outBuf bytes.Buffer + cmd.Stdout = &outBuf + cmd.Stderr = &outBuf if mallocNumToFail >= 0 { cmd.Env = os.Environ() cmd.Env = append(cmd.Env, "MALLOC_NUMBER_TO_FAIL="+strconv.FormatInt(mallocNumToFail, 10)) @@ -208,13 +207,12 @@ func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) { return false, errMoreMallocs } } - fmt.Print(string(stderrBuf.Bytes())) + fmt.Print(string(outBuf.Bytes())) return false, err } - fmt.Print(string(stderrBuf.Bytes())) // Account for Windows line-endings. - stdout := bytes.Replace(stdoutBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1) + stdout := bytes.Replace(outBuf.Bytes(), []byte("\r\n"), []byte("\n"), -1) if bytes.HasSuffix(stdout, []byte("PASS\n")) && (len(stdout) == 5 || stdout[len(stdout)-6] == '\n') { @@ -228,6 +226,7 @@ func runTestOnce(test test, mallocNumToFail int64) (passed bool, err error) { return true, nil } + fmt.Print(string(outBuf.Bytes())) return false, nil } diff --git a/src/util/all_tests.json b/src/util/all_tests.json index 4589ee76..76637b2c 100644 --- a/src/util/all_tests.json +++ b/src/util/all_tests.json @@ -40,7 +40,6 @@ ["crypto/ecdsa/ecdsa_sign_test", "crypto/ecdsa/ecdsa_sign_tests.txt"], ["crypto/ecdsa/ecdsa_test"], ["crypto/ecdsa/ecdsa_verify_test", "crypto/ecdsa/ecdsa_verify_tests.txt"], - ["crypto/err/err_test"], ["crypto/evp/evp_extra_test"], ["crypto/evp/evp_test", "crypto/evp/evp_tests.txt"], ["crypto/evp/pbkdf_test"], |