diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-11-06 11:12:36 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-11-06 11:12:36 +0000 |
commit | da0d1461616a796a3ec17ab0bde246e5620204d6 (patch) | |
tree | 30766ced8c56a5366f45459127f3c5901c95d367 | |
parent | e0833bdba5638aea2a64fc7cbada60f29ccf8aae (diff) | |
parent | 03d1abe83d2d93223668f4de58a32ee4cc484ed5 (diff) | |
download | src-da0d1461616a796a3ec17ab0bde246e5620204d6.tar.gz |
Merge from Chromium at DEPS revision db3f05efe0f9android-m-previewmaster-soong
This commit was generated by merge_to_master.py.
Change-Id: Ia542726d5df7935b2f79e8de6880d101853bb4c9
74 files changed, 2823 insertions, 1582 deletions
@@ -25,4 +25,9 @@ BORINGSSL_IMPLEMENTATION. On Windows, where functions need to be tagged with BORINGSSL_SHARED_LIBRARY defined in the code which #includes the BoringSSL headers. +To build on Windows, Yasm[2] is required for assembly. Either ensure yasm.exe +is in %PATH% or configure CMAKE_ASM_NASM_COMPILER appropriately. Note that +full Windows support is still in progress. + [1] http://martine.github.io/ninja/ +[2] http://yasm.tortall.net/ diff --git a/CMakeLists.txt b/CMakeLists.txt index add0c1a..bdfaee4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,6 +8,7 @@ if(CMAKE_COMPILER_IS_GNUCXX OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") elseif(MSVC) # Disable warnings for implicit integer narrowing. set(CMAKE_C_FLAGS "/wd4267") + set(CMAKE_CXX_FLAGS "/wd4267") endif() add_definitions(-DBORINGSSL_IMPLEMENTATION) diff --git a/crypto/CMakeLists.txt b/crypto/CMakeLists.txt index 5d656ec..d820e82 100644 --- a/crypto/CMakeLists.txt +++ b/crypto/CMakeLists.txt @@ -10,14 +10,16 @@ elseif(UNIX) enable_language(ASM) else() if (CMAKE_CL_64) - message("Using masm") - set(PERLASM_STYLE masm) + message("Using nasm") + set(PERLASM_STYLE nasm) else() message("Using win32n") set(PERLASM_STYLE win32n) endif() + + # On Windows, we use the NASM output, specifically built with Yasm. set(ASM_EXT asm) - enable_language(ASM_MASM) + enable_language(ASM_NASM) endif() function(perlasm dest src) @@ -27,9 +29,10 @@ function(perlasm dest src) DEPENDS ${src} ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86_64-xlate.pl - ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl - ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86asm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86gas.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86masm.pl + ${PROJECT_SOURCE_DIR}/crypto/perlasm/x86nasm.pl WORKING_DIRECTORY . ) endfunction() diff --git a/crypto/asn1/asn1_locl.h b/crypto/asn1/asn1_locl.h index 1444390..ca5f612 100644 --- a/crypto/asn1/asn1_locl.h +++ b/crypto/asn1/asn1_locl.h @@ -71,25 +71,3 @@ struct asn1_pctx_st unsigned long oid_flags; unsigned long str_flags; } /* ASN1_PCTX */; - -/* ASN1 public key method structure */ - - -/* Method to handle CRL access. - * In general a CRL could be very large (several Mb) and can consume large - * amounts of resources if stored in memory by multiple processes. - * This method allows general CRL operations to be redirected to more - * efficient callbacks: for example a CRL entry database. - */ - -#define X509_CRL_METHOD_DYNAMIC 1 - -struct x509_crl_method_st - { - int flags; - int (*crl_init)(X509_CRL *crl); - int (*crl_free)(X509_CRL *crl); - int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, - ASN1_INTEGER *ser, X509_NAME *issuer); - int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk); - }; diff --git a/crypto/bio/CMakeLists.txt b/crypto/bio/CMakeLists.txt index 86092f0..9178931 100644 --- a/crypto/bio/CMakeLists.txt +++ b/crypto/bio/CMakeLists.txt @@ -26,3 +26,6 @@ add_executable( ) target_link_libraries(bio_test crypto) +if (WIN32) + target_link_libraries(bio_test ws2_32) +endif() diff --git a/crypto/bn/asm/x86_64-gcc.c b/crypto/bn/asm/x86_64-gcc.c index be119aa..1de0f42 100644 --- a/crypto/bn/asm/x86_64-gcc.c +++ b/crypto/bn/asm/x86_64-gcc.c @@ -56,6 +56,8 @@ * machine. */ + /* TODO(davidben): Get this file working on Windows x64. */ + #undef mul #undef mul_add diff --git a/crypto/bn/generic.c b/crypto/bn/generic.c index b745750..53b5ce1 100644 --- a/crypto/bn/generic.c +++ b/crypto/bn/generic.c @@ -61,8 +61,13 @@ #include "internal.h" -#if defined(OPENSSL_WINDOWS) || defined(OPENSSL_NO_ASM) || \ - (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) +/* Generic implementations of most operations are needed for: + * - Configurations without inline assembly. + * - Architectures other than x86 or x86_64. + * - Windows x84_64; x86_64-gcc.c does not build on MSVC. */ +#if defined(OPENSSL_NO_ASM) || \ + (!defined(OPENSSL_X86_64) && !defined(OPENSSL_X86)) || \ + (defined(OPENSSL_X86_64) && defined(OPENSSL_WINDOWS)) #if defined(OPENSSL_WINDOWS) #define alloca _alloca @@ -817,9 +822,9 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, #endif /* !BN_LLONG */ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { -#ifdef BN_LLONG +#if defined(BN_LLONG) BN_ULLONG t; -#else +#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH) BN_ULONG bl, bh; #endif BN_ULONG t1, t2; @@ -925,9 +930,9 @@ void bn_mul_comba8(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { } void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { -#ifdef BN_LLONG +#if defined(BN_LLONG) BN_ULLONG t; -#else +#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH) BN_ULONG bl, bh; #endif BN_ULONG t1, t2; @@ -969,9 +974,9 @@ void bn_mul_comba4(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b) { } void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { -#ifdef BN_LLONG +#if defined(BN_LLONG) BN_ULLONG t, tt; -#else +#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH) BN_ULONG bl, bh; #endif BN_ULONG t1, t2; @@ -1049,9 +1054,9 @@ void bn_sqr_comba8(BN_ULONG *r, const BN_ULONG *a) { } void bn_sqr_comba4(BN_ULONG *r, const BN_ULONG *a) { -#ifdef BN_LLONG +#if defined(BN_LLONG) BN_ULLONG t, tt; -#else +#elif !defined(BN_UMULT_LOHI) && !defined(BN_UMULT_HIGH) BN_ULONG bl, bh; #endif BN_ULONG t1, t2; diff --git a/crypto/bn/internal.h b/crypto/bn/internal.h index 88ab547..ab09c6e 100644 --- a/crypto/bn/internal.h +++ b/crypto/bn/internal.h @@ -138,7 +138,6 @@ BIGNUM *bn_expand(BIGNUM *bn, unsigned bits); #if defined(OPENSSL_64_BIT) #define BN_ULLONG unsigned long long -#define BN_LONG long #define BN_BITS 128 #define BN_BYTES 8 #define BN_BITS4 32 @@ -158,7 +157,6 @@ BIGNUM *bn_expand(BIGNUM *bn, unsigned bits); #define BN_ULLONG unsigned long long #define BN_MASK (0xffffffffffffffffLL) -#define BN_LONG int32_t #define BN_BITS 64 #define BN_BYTES 4 #define BN_BITS4 16 diff --git a/crypto/bytestring/bytestring_test.c b/crypto/bytestring/bytestring_test.c index f30179d..ba70bcf 100644 --- a/crypto/bytestring/bytestring_test.c +++ b/crypto/bytestring/bytestring_test.c @@ -19,6 +19,7 @@ #include <openssl/bytestring.h> #include "internal.h" +#include "../internal.h" static int test_skip(void) { @@ -105,8 +106,14 @@ static int test_get_asn1(void) { static const uint8_t kData3[] = {0x30, 0x80}; static const uint8_t kData4[] = {0x30, 0x81, 1, 1}; static const uint8_t kData5[] = {0x30, 0x82, 0, 1, 1}; + static const uint8_t kData6[] = {0xa1, 3, 0x4, 1, 1}; + static const uint8_t kData7[] = {0xa1, 3, 0x4, 2, 1}; + static const uint8_t kData8[] = {0xa1, 3, 0x2, 1, 1}; + static const uint8_t kData9[] = {0xa1, 3, 0x2, 1, 0xff}; CBS data, contents; + int present; + uint64_t value; CBS_init(&data, kData1, sizeof(kData1)); if (CBS_peek_asn1_tag(&data, 0x1) || @@ -150,10 +157,106 @@ static int test_get_asn1(void) { } CBS_init(&data, NULL, 0); + /* peek at empty data. */ if (CBS_peek_asn1_tag(&data, 0x30)) { return 0; } + CBS_init(&data, NULL, 0); + /* optional elements at empty data. */ + if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || + present || + !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || + present || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_octet_string(&data, &contents, NULL, 0xa0) || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || + value != 42) { + return 0; + } + + CBS_init(&data, kData6, sizeof(kData6)); + /* optional element. */ + if (!CBS_get_optional_asn1(&data, &contents, &present, 0xa0) || + present || + !CBS_get_optional_asn1(&data, &contents, &present, 0xa1) || + !present || + CBS_len(&contents) != 3 || + memcmp(CBS_data(&contents), "\x04\x01\x01", 3) != 0) { + return 0; + } + + CBS_init(&data, kData6, sizeof(kData6)); + /* optional octet string. */ + if (!CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa0) || + present || + CBS_len(&contents) != 0 || + !CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1) || + !present || + CBS_len(&contents) != 1 || + CBS_data(&contents)[0] != 1) { + return 0; + } + + CBS_init(&data, kData7, sizeof(kData7)); + /* invalid optional octet string. */ + if (CBS_get_optional_asn1_octet_string(&data, &contents, &present, 0xa1)) { + return 0; + } + + CBS_init(&data, kData8, sizeof(kData8)); + /* optional octet string. */ + if (!CBS_get_optional_asn1_uint64(&data, &value, 0xa0, 42) || + value != 42 || + !CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42) || + value != 1) { + return 0; + } + + CBS_init(&data, kData9, sizeof(kData9)); + /* invalid optional integer. */ + if (CBS_get_optional_asn1_uint64(&data, &value, 0xa1, 42)) { + return 0; + } + + return 1; +} + +static int test_get_optional_asn1_bool(void) { + CBS data; + int val; + + static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff}; + static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00}; + static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01}; + + CBS_init(&data, NULL, 0); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || + val != 0) { + return 0; + } + + CBS_init(&data, kTrue, sizeof(kTrue)); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) || + val != 1) { + return 0; + } + + CBS_init(&data, kFalse, sizeof(kFalse)); + val = 2; + if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) || + val != 0) { + return 0; + } + + CBS_init(&data, kInvalid, sizeof(kInvalid)); + if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) { + return 0; + } + return 1; } @@ -443,6 +546,89 @@ static int test_ber_convert(void) { sizeof(kNSSBER)); } +typedef struct { + uint64_t value; + const char *encoding; + size_t encoding_len; +} ASN1_UINT64_TEST; + +static const ASN1_UINT64_TEST kAsn1Uint64Tests[] = { + {0, "\x02\x01\x00", 3}, + {1, "\x02\x01\x01", 3}, + {127, "\x02\x01\x7f", 3}, + {128, "\x02\x02\x00\x80", 4}, + {0xdeadbeef, "\x02\x05\x00\xde\xad\xbe\xef", 7}, + {OPENSSL_U64(0x0102030405060708), + "\x02\x08\x01\x02\x03\x04\x05\x06\x07\x08", 10}, + {OPENSSL_U64(0xffffffffffffffff), + "\x02\x09\x00\xff\xff\xff\xff\xff\xff\xff\xff", 11}, +}; + +typedef struct { + const char *encoding; + size_t encoding_len; +} ASN1_INVALID_UINT64_TEST; + +static const ASN1_INVALID_UINT64_TEST kAsn1InvalidUint64Tests[] = { + /* Bad tag. */ + {"\x03\x01\x00", 3}, + /* Empty contents. */ + {"\x02\x00", 2}, + /* Negative number. */ + {"\x02\x01\x80", 3}, + /* Overflow */ + {"\x02\x09\x01\x00\x00\x00\x00\x00\x00\x00\x00", 11}, +}; + +static int test_asn1_uint64(void) { + size_t i; + + for (i = 0; i < sizeof(kAsn1Uint64Tests) / sizeof(kAsn1Uint64Tests[0]); i++) { + const ASN1_UINT64_TEST *test = &kAsn1Uint64Tests[i]; + CBS cbs; + uint64_t value; + CBB cbb; + uint8_t *out; + size_t len; + + CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len); + if (!CBS_get_asn1_uint64(&cbs, &value) || + CBS_len(&cbs) != 0 || + value != test->value) { + return 0; + } + + if (!CBB_init(&cbb, 0)) { + return 0; + } + if (!CBB_add_asn1_uint64(&cbb, test->value) || + !CBB_finish(&cbb, &out, &len)) { + CBB_cleanup(&cbb); + return 0; + } + if (len != test->encoding_len || memcmp(out, test->encoding, len) != 0) { + free(out); + return 0; + } + free(out); + } + + for (i = 0; + i < sizeof(kAsn1InvalidUint64Tests) / sizeof(kAsn1InvalidUint64Tests[0]); + i++) { + const ASN1_INVALID_UINT64_TEST *test = &kAsn1InvalidUint64Tests[i]; + CBS cbs; + uint64_t value; + + CBS_init(&cbs, (const uint8_t *)test->encoding, test->encoding_len); + if (CBS_get_asn1_uint64(&cbs, &value)) { + return 0; + } + } + + return 1; +} + int main(void) { CRYPTO_library_init(); @@ -457,7 +643,9 @@ int main(void) { !test_cbb_misuse() || !test_cbb_prefixed() || !test_cbb_asn1() || - !test_ber_convert()) { + !test_ber_convert() || + !test_asn1_uint64() || + !test_get_optional_asn1_bool()) { return 1; } diff --git a/crypto/bytestring/cbb.c b/crypto/bytestring/cbb.c index 6767b9d..f8e1070 100644 --- a/crypto/bytestring/cbb.c +++ b/crypto/bytestring/cbb.c @@ -336,3 +336,39 @@ int CBB_add_u24(CBB *cbb, uint32_t value) { return cbb_buffer_add_u(cbb->base, value, 3); } + +int CBB_add_asn1_uint64(CBB *cbb, uint64_t value) { + CBB child; + size_t i; + int started = 0; + + if (!CBB_add_asn1(cbb, &child, CBS_ASN1_INTEGER)) { + return 0; + } + + for (i = 0; i < 8; i++) { + uint8_t byte = (value >> 8*(7-i)) & 0xff; + if (!started) { + if (byte == 0) { + /* Don't encode leading zeros. */ + continue; + } + /* If the high bit is set, add a padding byte to make it + * unsigned. */ + if ((byte & 0x80) && !CBB_add_u8(&child, 0)) { + return 0; + } + started = 1; + } + if (!CBB_add_u8(&child, byte)) { + return 0; + } + } + + /* 0 is encoded as a single 0, not the empty string. */ + if (!started && !CBB_add_u8(&child, 0)) { + return 0; + } + + return CBB_flush(cbb); +} diff --git a/crypto/bytestring/cbs.c b/crypto/bytestring/cbs.c index 07cc126..b417716 100644 --- a/crypto/bytestring/cbs.c +++ b/crypto/bytestring/cbs.c @@ -284,7 +284,12 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { data = CBS_data(&bytes); len = CBS_len(&bytes); - if (len > 0 && (data[0] & 0x80) != 0) { + if (len == 0) { + /* An INTEGER is encoded with at least one octet. */ + return 0; + } + + if ((data[0] & 0x80) != 0) { /* negative number */ return 0; } @@ -300,3 +305,84 @@ int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out) { return 1; } + +int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, unsigned tag) { + if (CBS_peek_asn1_tag(cbs, tag)) { + if (!CBS_get_asn1(cbs, out, tag)) { + return 0; + } + *out_present = 1; + } else { + *out_present = 0; + } + return 1; +} + +int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, int *out_present, + unsigned tag) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1(&child, out, CBS_ASN1_OCTETSTRING) || + CBS_len(&child) != 0) { + return 0; + } + } else { + CBS_init(out, NULL, 0); + } + if (out_present) { + *out_present = present; + } + return 1; +} + +int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag, + uint64_t default_value) { + CBS child; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + if (!CBS_get_asn1_uint64(&child, out) || + CBS_len(&child) != 0) { + return 0; + } + } else { + *out = default_value; + } + return 1; +} + +int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value) { + CBS child, child2; + int present; + if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) { + return 0; + } + if (present) { + uint8_t boolean; + + if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + CBS_len(&child2) != 1 || + CBS_len(&child) != 0) { + return 0; + } + + boolean = CBS_data(&child2)[0]; + if (boolean == 0) { + *out = 0; + } else if (boolean == 0xff) { + *out = 1; + } else { + return 0; + } + } else { + *out = default_value; + } + return 1; +} diff --git a/crypto/err/err.c b/crypto/err/err.c index 3c5ea99..d0425d8 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -645,7 +645,6 @@ static const char *const kLibraryNames[ERR_NUM_LIBS] = { "PKCS7 routines", /* ERR_LIB_PKCS7 */ "PKCS8 routines", /* ERR_LIB_PKCS8 */ "X509 V3 routines", /* ERR_LIB_X509V3 */ - "PKCS12 routines", /* ERR_LIB_PKCS12 */ "random number generator", /* ERR_LIB_RAND */ "ENGINE routines", /* ERR_LIB_ENGINE */ "OCSP routines", /* ERR_LIB_OCSP */ diff --git a/crypto/evp/CMakeLists.txt b/crypto/evp/CMakeLists.txt index 43e351a..dc1734c 100644 --- a/crypto/evp/CMakeLists.txt +++ b/crypto/evp/CMakeLists.txt @@ -23,9 +23,9 @@ add_library( add_executable( - example_sign + evp_test - example_sign.c + evp_test.c ) -target_link_libraries(example_sign crypto) +target_link_libraries(evp_test crypto) diff --git a/crypto/evp/asn1.c b/crypto/evp/asn1.c index 50bdb06..27ae017 100644 --- a/crypto/evp/asn1.c +++ b/crypto/evp/asn1.c @@ -128,9 +128,6 @@ EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp, long len) { } else if (sk_ASN1_TYPE_num(inkey) == 4) { keytype = EVP_PKEY_EC; } else if (sk_ASN1_TYPE_num(inkey) == 3) { - OPENSSL_PUT_ERROR(EVP, d2i_AutoPrivateKey, EVP_R_UNSUPPORTED_PUBLIC_KEY_TYPE); - return 0; - /* This seems to be PKCS8, not traditional format */ PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, inp, len); EVP_PKEY *ret; diff --git a/crypto/evp/digestsign.c b/crypto/evp/digestsign.c index 08968ed..c86b805 100644 --- a/crypto/evp/digestsign.c +++ b/crypto/evp/digestsign.c @@ -168,22 +168,15 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig, if (has_signctx || !r) { return r; } - if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen) <= 0) { - return 0; - } + return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen); } else { if (has_signctx) { - if (ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx) <= 0) { - return 0; - } + return ctx->pctx->pmeth->signctx(ctx->pctx, out_sig, out_sig_len, ctx); } else { size_t s = EVP_MD_size(ctx->digest); - if (EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s) <= 0) { - return 0; - } + return EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, NULL, s); } } - return 1; } int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, @@ -196,7 +189,7 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, EVP_MD_CTX_init(&tmp_ctx); if (!EVP_MD_CTX_copy_ex(&tmp_ctx, ctx)) { - return -1; + return 0; } if (has_verifyctx) { r = tmp_ctx.pctx->pmeth->verifyctx(tmp_ctx.pctx, sig, sig_len, &tmp_ctx); diff --git a/crypto/evp/example_sign.c b/crypto/evp/evp_test.c index 42a19ec..670df37 100644 --- a/crypto/evp/example_sign.c +++ b/crypto/evp/evp_test.c @@ -155,6 +155,80 @@ static const uint8_t kExamplePSSCert[] = { 0x8c, 0x16, }; +/* kExampleRSAKeyPKCS8 is kExampleRSAKeyDER encoded in a PKCS #8 + * PrivateKeyInfo. */ +static const uint8_t kExampleRSAKeyPKCS8[] = { + 0x30, 0x82, 0x02, 0x76, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, + 0x02, 0x60, 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, + 0x00, 0xf8, 0xb8, 0x6c, 0x83, 0xb4, 0xbc, 0xd9, 0xa8, 0x57, 0xc0, 0xa5, + 0xb4, 0x59, 0x76, 0x8c, 0x54, 0x1d, 0x79, 0xeb, 0x22, 0x52, 0x04, 0x7e, + 0xd3, 0x37, 0xeb, 0x41, 0xfd, 0x83, 0xf9, 0xf0, 0xa6, 0x85, 0x15, 0x34, + 0x75, 0x71, 0x5a, 0x84, 0xa8, 0x3c, 0xd2, 0xef, 0x5a, 0x4e, 0xd3, 0xde, + 0x97, 0x8a, 0xdd, 0xff, 0xbb, 0xcf, 0x0a, 0xaa, 0x86, 0x92, 0xbe, 0xb8, + 0x50, 0xe4, 0xcd, 0x6f, 0x80, 0x33, 0x30, 0x76, 0x13, 0x8f, 0xca, 0x7b, + 0xdc, 0xec, 0x5a, 0xca, 0x63, 0xc7, 0x03, 0x25, 0xef, 0xa8, 0x8a, 0x83, + 0x58, 0x76, 0x20, 0xfa, 0x16, 0x77, 0xd7, 0x79, 0x92, 0x63, 0x01, 0x48, + 0x1a, 0xd8, 0x7b, 0x67, 0xf1, 0x52, 0x55, 0x49, 0x4e, 0xd6, 0x6e, 0x4a, + 0x5c, 0xd7, 0x7a, 0x37, 0x36, 0x0c, 0xde, 0xdd, 0x8f, 0x44, 0xe8, 0xc2, + 0xa7, 0x2c, 0x2b, 0xb5, 0xaf, 0x64, 0x4b, 0x61, 0x07, 0x02, 0x03, 0x01, + 0x00, 0x01, 0x02, 0x81, 0x80, 0x74, 0x88, 0x64, 0x3f, 0x69, 0x45, 0x3a, + 0x6d, 0xc7, 0x7f, 0xb9, 0xa3, 0xc0, 0x6e, 0xec, 0xdc, 0xd4, 0x5a, 0xb5, + 0x32, 0x85, 0x5f, 0x19, 0xd4, 0xf8, 0xd4, 0x3f, 0x3c, 0xfa, 0xc2, 0xf6, + 0x5f, 0xee, 0xe6, 0xba, 0x87, 0x74, 0x2e, 0xc7, 0x0c, 0xd4, 0x42, 0xb8, + 0x66, 0x85, 0x9c, 0x7b, 0x24, 0x61, 0xaa, 0x16, 0x11, 0xf6, 0xb5, 0xb6, + 0xa4, 0x0a, 0xc9, 0x55, 0x2e, 0x81, 0xa5, 0x47, 0x61, 0xcb, 0x25, 0x8f, + 0xc2, 0x15, 0x7b, 0x0e, 0x7c, 0x36, 0x9f, 0x3a, 0xda, 0x58, 0x86, 0x1c, + 0x5b, 0x83, 0x79, 0xe6, 0x2b, 0xcc, 0xe6, 0xfa, 0x2c, 0x61, 0xf2, 0x78, + 0x80, 0x1b, 0xe2, 0xf3, 0x9d, 0x39, 0x2b, 0x65, 0x57, 0x91, 0x3d, 0x71, + 0x99, 0x73, 0xa5, 0xc2, 0x79, 0x20, 0x8c, 0x07, 0x4f, 0xe5, 0xb4, 0x60, + 0x1f, 0x99, 0xa2, 0xb1, 0x4f, 0x0c, 0xef, 0xbc, 0x59, 0x53, 0x00, 0x7d, + 0xb1, 0x02, 0x41, 0x00, 0xfc, 0x7e, 0x23, 0x65, 0x70, 0xf8, 0xce, 0xd3, + 0x40, 0x41, 0x80, 0x6a, 0x1d, 0x01, 0xd6, 0x01, 0xff, 0xb6, 0x1b, 0x3d, + 0x3d, 0x59, 0x09, 0x33, 0x79, 0xc0, 0x4f, 0xde, 0x96, 0x27, 0x4b, 0x18, + 0xc6, 0xd9, 0x78, 0xf1, 0xf4, 0x35, 0x46, 0xe9, 0x7c, 0x42, 0x7a, 0x5d, + 0x9f, 0xef, 0x54, 0xb8, 0xf7, 0x9f, 0xc4, 0x33, 0x6c, 0xf3, 0x8c, 0x32, + 0x46, 0x87, 0x67, 0x30, 0x7b, 0xa7, 0xac, 0xe3, 0x02, 0x41, 0x00, 0xfc, + 0x2c, 0xdf, 0x0c, 0x0d, 0x88, 0xf5, 0xb1, 0x92, 0xa8, 0x93, 0x47, 0x63, + 0x55, 0xf5, 0xca, 0x58, 0x43, 0xba, 0x1c, 0xe5, 0x9e, 0xb6, 0x95, 0x05, + 0xcd, 0xb5, 0x82, 0xdf, 0xeb, 0x04, 0x53, 0x9d, 0xbd, 0xc2, 0x38, 0x16, + 0xb3, 0x62, 0xdd, 0xa1, 0x46, 0xdb, 0x6d, 0x97, 0x93, 0x9f, 0x8a, 0xc3, + 0x9b, 0x64, 0x7e, 0x42, 0xe3, 0x32, 0x57, 0x19, 0x1b, 0xd5, 0x6e, 0x85, + 0xfa, 0xb8, 0x8d, 0x02, 0x41, 0x00, 0xbc, 0x3d, 0xde, 0x6d, 0xd6, 0x97, + 0xe8, 0xba, 0x9e, 0x81, 0x37, 0x17, 0xe5, 0xa0, 0x64, 0xc9, 0x00, 0xb7, + 0xe7, 0xfe, 0xf4, 0x29, 0xd9, 0x2e, 0x43, 0x6b, 0x19, 0x20, 0xbd, 0x99, + 0x75, 0xe7, 0x76, 0xf8, 0xd3, 0xae, 0xaf, 0x7e, 0xb8, 0xeb, 0x81, 0xf4, + 0x9d, 0xfe, 0x07, 0x2b, 0x0b, 0x63, 0x0b, 0x5a, 0x55, 0x90, 0x71, 0x7d, + 0xf1, 0xdb, 0xd9, 0xb1, 0x41, 0x41, 0x68, 0x2f, 0x4e, 0x39, 0x02, 0x40, + 0x5a, 0x34, 0x66, 0xd8, 0xf5, 0xe2, 0x7f, 0x18, 0xb5, 0x00, 0x6e, 0x26, + 0x84, 0x27, 0x14, 0x93, 0xfb, 0xfc, 0xc6, 0x0f, 0x5e, 0x27, 0xe6, 0xe1, + 0xe9, 0xc0, 0x8a, 0xe4, 0x34, 0xda, 0xe9, 0xa2, 0x4b, 0x73, 0xbc, 0x8c, + 0xb9, 0xba, 0x13, 0x6c, 0x7a, 0x2b, 0x51, 0x84, 0xa3, 0x4a, 0xe0, 0x30, + 0x10, 0x06, 0x7e, 0xed, 0x17, 0x5a, 0x14, 0x00, 0xc9, 0xef, 0x85, 0xea, + 0x52, 0x2c, 0xbc, 0x65, 0x02, 0x40, 0x51, 0xe3, 0xf2, 0x83, 0x19, 0x9b, + 0xc4, 0x1e, 0x2f, 0x50, 0x3d, 0xdf, 0x5a, 0xa2, 0x18, 0xca, 0x5f, 0x2e, + 0x49, 0xaf, 0x6f, 0xcc, 0xfa, 0x65, 0x77, 0x94, 0xb5, 0xa1, 0x0a, 0xa9, + 0xd1, 0x8a, 0x39, 0x37, 0xf4, 0x0b, 0xa0, 0xd7, 0x82, 0x27, 0x5e, 0xae, + 0x17, 0x17, 0xa1, 0x1e, 0x54, 0x34, 0xbf, 0x6e, 0xc4, 0x8e, 0x99, 0x5d, + 0x08, 0xf1, 0x2d, 0x86, 0x9d, 0xa5, 0x20, 0x1b, 0xe5, 0xdf, +}; + +/* kExampleECKeyDER is a sample EC private key encoded as an ECPrivateKey + * structure. */ +static const uint8_t kExampleECKeyDER[] = { + 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x07, 0x0f, 0x08, 0x72, 0x7a, + 0xd4, 0xa0, 0x4a, 0x9c, 0xdd, 0x59, 0xc9, 0x4d, 0x89, 0x68, 0x77, 0x08, + 0xb5, 0x6f, 0xc9, 0x5d, 0x30, 0x77, 0x0e, 0xe8, 0xd1, 0xc9, 0xce, 0x0a, + 0x8b, 0xb4, 0x6a, 0xa0, 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0xe6, 0x2b, 0x69, + 0xe2, 0xbf, 0x65, 0x9f, 0x97, 0xbe, 0x2f, 0x1e, 0x0d, 0x94, 0x8a, 0x4c, + 0xd5, 0x97, 0x6b, 0xb7, 0xa9, 0x1e, 0x0d, 0x46, 0xfb, 0xdd, 0xa9, 0xa9, + 0x1e, 0x9d, 0xdc, 0xba, 0x5a, 0x01, 0xe7, 0xd6, 0x97, 0xa8, 0x0a, 0x18, + 0xf9, 0xc3, 0xc4, 0xa3, 0x1e, 0x56, 0xe2, 0x7c, 0x83, 0x48, 0xdb, 0x16, + 0x1a, 0x1c, 0xf5, 0x1d, 0x7e, 0xf1, 0x94, 0x2d, 0x4b, 0xcf, 0x72, 0x22, + 0xc1, +}; + static EVP_PKEY *load_example_rsa_key(void) { EVP_PKEY *ret = NULL; const uint8_t *derp = kExampleRSAKeyDER; @@ -184,7 +258,7 @@ out: return ret; } -static int example_EVP_DigestSignInit(void) { +static int test_EVP_DigestSignInit(void) { int ret = 0; EVP_PKEY *pkey = NULL; uint8_t *sig = NULL; @@ -196,12 +270,12 @@ static int example_EVP_DigestSignInit(void) { pkey = load_example_rsa_key(); if (pkey == NULL || - EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 || - EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1) { + !EVP_DigestSignInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) || + !EVP_DigestSignUpdate(&md_ctx, kMsg, sizeof(kMsg))) { goto out; } /* Determine the size of the signature. */ - if (EVP_DigestSignFinal(&md_ctx, NULL, &sig_len) != 1) { + if (!EVP_DigestSignFinal(&md_ctx, NULL, &sig_len)) { goto out; } /* Sanity check for testing. */ @@ -211,14 +285,14 @@ static int example_EVP_DigestSignInit(void) { } sig = malloc(sig_len); - if (sig == NULL || EVP_DigestSignFinal(&md_ctx, sig, &sig_len) != 1) { + if (sig == NULL || !EVP_DigestSignFinal(&md_ctx, sig, &sig_len)) { goto out; } /* Ensure that the signature round-trips. */ - if (EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) != 1 || - EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 || - EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) { + if (!EVP_DigestVerifyInit(&md_ctx_verify, NULL, EVP_sha256(), NULL, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) || + !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) { goto out; } @@ -241,7 +315,7 @@ out: return ret; } -static int example_EVP_DigestVerifyInit(void) { +static int test_EVP_DigestVerifyInit(void) { int ret = 0; EVP_PKEY *pkey = NULL; EVP_MD_CTX md_ctx; @@ -250,9 +324,9 @@ static int example_EVP_DigestVerifyInit(void) { pkey = load_example_rsa_key(); if (pkey == NULL || - EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) != 1 || - EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) != 1 || - EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature)) != 1) { + !EVP_DigestVerifyInit(&md_ctx, NULL, EVP_sha256(), NULL, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx, kMsg, sizeof(kMsg)) || + !EVP_DigestVerifyFinal(&md_ctx, kSignature, sizeof(kSignature))) { goto out; } ret = 1; @@ -282,7 +356,7 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) { EVP_MD_CTX_init(&md_ctx_verify); - if (EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg)) != 1) { + if (!EVP_DigestSignUpdate(md_ctx, kMsg, sizeof(kMsg))) { goto out; } @@ -293,7 +367,7 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) { } /* Determine the size of the signature. */ - if (EVP_DigestSignFinal(md_ctx, NULL, &sig_len) != 1) { + if (!EVP_DigestSignFinal(md_ctx, NULL, &sig_len)) { goto out; } /* Sanity check for testing. */ @@ -303,14 +377,14 @@ static int test_algorithm_roundtrip(EVP_MD_CTX *md_ctx, EVP_PKEY *pkey) { } sig = malloc(sig_len); - if (sig == NULL || EVP_DigestSignFinal(md_ctx, sig, &sig_len) != 1) { + if (sig == NULL || !EVP_DigestSignFinal(md_ctx, sig, &sig_len)) { goto out; } /* Ensure that the signature round-trips. */ - if (EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) != 1 || - EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) != 1 || - EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len) != 1) { + if (!EVP_DigestVerifyInitFromAlgorithm(&md_ctx_verify, algor, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx_verify, kMsg, sizeof(kMsg)) || + !EVP_DigestVerifyFinal(&md_ctx_verify, sig, sig_len)) { goto out; } @@ -342,7 +416,7 @@ static int test_EVP_DigestSignAlgorithm(void) { } /* Test a simple AlgorithmIdentifier. */ - if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 || + if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) || !test_algorithm_roundtrip(&md_ctx, pkey)) { fprintf(stderr, "RSA with SHA-256 failed\n"); goto out; @@ -352,7 +426,7 @@ static int test_EVP_DigestSignAlgorithm(void) { EVP_MD_CTX_init(&md_ctx); /* Test RSA-PSS with custom parameters. */ - if (EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) != 1 || + if (!EVP_DigestSignInit(&md_ctx, &pkey_ctx, EVP_sha256(), NULL, pkey) || EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING) != 1 || EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, EVP_sha512()) != 1 || !test_algorithm_roundtrip(&md_ctx, pkey)) { @@ -375,7 +449,7 @@ out: return ret; } -static int example_EVP_DigestVerifyInitFromAlgorithm(void) { +static int test_EVP_DigestVerifyInitFromAlgorithm(void) { int ret = 0; CBS cert, cert_body, tbs_cert, algorithm, signature; uint8_t padding; @@ -412,11 +486,11 @@ static int example_EVP_DigestVerifyInitFromAlgorithm(void) { pkey = load_example_rsa_key(); if (pkey == NULL || - EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) != 1|| - EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert), - CBS_len(&tbs_cert)) != 1 || - EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), - CBS_len(&signature)) != 1) { + !EVP_DigestVerifyInitFromAlgorithm(&md_ctx, algor, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(&tbs_cert), + CBS_len(&tbs_cert)) || + !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), + CBS_len(&signature))) { goto out; } ret = 1; @@ -434,16 +508,47 @@ out: return ret; } +static int test_d2i_AutoPrivateKey(const uint8_t *input, size_t input_len, + int expected_id) { + int ret = 0; + const uint8_t *p; + EVP_PKEY *pkey = NULL; + + p = input; + pkey = d2i_AutoPrivateKey(NULL, &p, input_len); + if (pkey == NULL || p != input + input_len) { + fprintf(stderr, "d2i_AutoPrivateKey failed\n"); + goto done; + } + + if (EVP_PKEY_id(pkey) != expected_id) { + fprintf(stderr, "Did not decode expected type\n"); + goto done; + } + + ret = 1; + +done: + if (!ret) { + BIO_print_errors_fp(stderr); + } + + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + return ret; +} + int main(void) { CRYPTO_library_init(); ERR_load_crypto_strings(); - if (!example_EVP_DigestSignInit()) { + if (!test_EVP_DigestSignInit()) { fprintf(stderr, "EVP_DigestSignInit failed\n"); return 1; } - if (!example_EVP_DigestVerifyInit()) { + if (!test_EVP_DigestVerifyInit()) { fprintf(stderr, "EVP_DigestVerifyInit failed\n"); return 1; } @@ -453,11 +558,29 @@ int main(void) { return 1; } - if (!example_EVP_DigestVerifyInitFromAlgorithm()) { + if (!test_EVP_DigestVerifyInitFromAlgorithm()) { fprintf(stderr, "EVP_DigestVerifyInitFromAlgorithm failed\n"); return 1; } + if (!test_d2i_AutoPrivateKey(kExampleRSAKeyDER, sizeof(kExampleRSAKeyDER), + EVP_PKEY_RSA)) { + fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyDER) failed\n"); + return 1; + } + + if (!test_d2i_AutoPrivateKey(kExampleRSAKeyPKCS8, sizeof(kExampleRSAKeyPKCS8), + EVP_PKEY_RSA)) { + fprintf(stderr, "d2i_AutoPrivateKey(kExampleRSAKeyPKCS8) failed\n"); + return 1; + } + + if (!test_d2i_AutoPrivateKey(kExampleECKeyDER, sizeof(kExampleECKeyDER), + EVP_PKEY_EC)) { + fprintf(stderr, "d2i_AutoPrivateKey(kExampleECKeyDER) failed\n"); + return 1; + } + printf("PASS\n"); return 0; } diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h index d92c9e5..0e9dfb2 100644 --- a/crypto/evp/internal.h +++ b/crypto/evp/internal.h @@ -65,13 +65,11 @@ extern "C" { /* These values are flags for EVP_PKEY_ASN1_METHOD.flags. */ -#define ASN1_PKEY_ALIAS 0x1 -#define ASN1_PKEY_DYNAMIC 0x2 /* ASN1_PKEY_SIGPARAM_NULL controls whether the default behavior of * EVP_DigestSignAlgorithm writes an explicit NULL parameter in the * AlgorithmIdentifier. */ -#define ASN1_PKEY_SIGPARAM_NULL 0x4 +#define ASN1_PKEY_SIGPARAM_NULL 0x1 /* evp_digest_sign_algorithm_result_t is the return value of the * digest_sign_algorithm function in EVP_PKEY_ASN1_METHOD. */ diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c index 40012b3..179d96b 100644 --- a/crypto/evp/p_rsa_asn1.c +++ b/crypto/evp/p_rsa_asn1.c @@ -717,9 +717,3 @@ const EVP_PKEY_ASN1_METHOD rsa_asn1_meth = { rsa_digest_verify_init_from_algorithm, rsa_digest_sign_algorithm, }; - -const EVP_PKEY_ASN1_METHOD rsa_asn1_meth_2 = { - EVP_PKEY_RSA2, - EVP_PKEY_RSA, - ASN1_PKEY_ALIAS, -}; diff --git a/crypto/evp/sign.c b/crypto/evp/sign.c index c32e5ce..1faf7c6 100644 --- a/crypto/evp/sign.c +++ b/crypto/evp/sign.c @@ -91,12 +91,6 @@ int EVP_SignFinal(const EVP_MD_CTX *ctx, uint8_t *sig, } EVP_MD_CTX_cleanup(&tmp_ctx); -/* TODO(fork): this used to be used only with SHA-family hashes. Now we've - * removed the flag completely. Why was it added for just those hashes? */ -#if 0 - if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { -#endif - pkctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pkctx || EVP_PKEY_sign_init(pkctx) <= 0 || EVP_PKEY_CTX_set_signature_md(pkctx, ctx->digest) <= 0 || @@ -142,11 +136,6 @@ int EVP_VerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len, } EVP_MD_CTX_cleanup(&tmp_ctx); -/* TODO(fork): this used to be used only with SHA-family hashes. Now we've - * removed the flag completely. Why was it added for just those hashes? */ -#if 0 - if (ctx->digest->flags & EVP_MD_FLAG_PKEY_METHOD_SIGNATURE) { -#endif pkctx = EVP_PKEY_CTX_new(pkey, NULL); if (!pkctx || EVP_PKEY_verify_init(pkctx) <= 0 || diff --git a/crypto/perlasm/x86asm.pl b/crypto/perlasm/x86asm.pl index bab15e7..3c7be40 100644 --- a/crypto/perlasm/x86asm.pl +++ b/crypto/perlasm/x86asm.pl @@ -235,9 +235,9 @@ sub ::asciz sub ::asm_finish { &file_end(); - print "#if defined(__i386__)\n"; + print "#if defined(__i386__)\n" unless $win32; print @out; - print "#endif\n"; + print "#endif\n" unless $win32; } sub ::asm_init diff --git a/crypto/perlasm/x86masm.pl b/crypto/perlasm/x86masm.pl index 1741342..a491529 100644 --- a/crypto/perlasm/x86masm.pl +++ b/crypto/perlasm/x86masm.pl @@ -82,7 +82,7 @@ TITLE $_[0].asm IF \@Version LT 800 ECHO MASM version 8.00 or later is strongly recommended. ENDIF -.486 +.686 .MODEL FLAT OPTION DOTNAME IF \@Version LT 800 @@ -166,7 +166,10 @@ sub ::data_short { push(@out,("DW\t").join(',',@_)."\n"); } sub ::data_word -{ push(@out,("DD\t").join(',',@_)."\n"); } +{ # MASM can't handle long lines, so emit one word at a time. + foreach(@_) + { push(@out,"DD\t$_\n"); } +} sub ::align { push(@out,"ALIGN\t$_[0]\n"); } diff --git a/crypto/perlasm/x86nasm.pl b/crypto/perlasm/x86nasm.pl index 5d92f60..f8332bb 100644 --- a/crypto/perlasm/x86nasm.pl +++ b/crypto/perlasm/x86nasm.pl @@ -83,7 +83,15 @@ sub ::file %ifidn __OUTPUT_FORMAT__,obj section code use32 class=code align=64 %elifidn __OUTPUT_FORMAT__,win32 +%ifdef __YASM_VERSION_ID__ +%if __YASM_VERSION_ID__ < 01010000h +%error yasm version 1.1.0 or later needed. +%endif +; Yasm automatically includes @feat.00 and complains about redefining it. +; https://www.tortall.net/projects/yasm/manual/html/objfmt-win32-safeseh.html +%else \$\@feat.00 equ 1 +%endif section .text code align=64 %else section .text code diff --git a/crypto/rand/windows.c b/crypto/rand/windows.c index 967dd9b..ed6e5e9 100644 --- a/crypto/rand/windows.c +++ b/crypto/rand/windows.c @@ -14,57 +14,36 @@ #include <openssl/rand.h> -#include <openssl/thread.h> - - #if defined(OPENSSL_WINDOWS) +#include <limits.h> #include <stdlib.h> #include <Windows.h> -#include <Wincrypt.h> -static char global_provider_init; -static HCRYPTPROV global_provider; +/* #define needed to link in RtlGenRandom(), a.k.a. SystemFunction036. See the + * "Community Additions" comment on MSDN here: + * http://msdn.microsoft.com/en-us/library/windows/desktop/aa387694.aspx */ +#define SystemFunction036 NTAPI SystemFunction036 +#include <NTSecAPI.h> +#undef SystemFunction036 + void RAND_cleanup(void) { - CRYPTO_w_lock(CRYPTO_LOCK_RAND); - CryptReleaseContext(global_provider, 0); - global_provider_init = 0; - CRYPTO_w_unlock(CRYPTO_LOCK_RAND); } int RAND_bytes(uint8_t *out, size_t requested) { - HCRYPTPROV provider = 0; - int ok; - - CRYPTO_r_lock(CRYPTO_LOCK_RAND); - if (!global_provider_init) { - CRYPTO_r_unlock(CRYPTO_LOCK_RAND); - CRYPTO_w_lock(CRYPTO_LOCK_RAND); - if (!global_provider_init) { - if (CryptAcquireContext(&global_provider, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { - global_provider_init = 1; - } + while (requested > 0) { + ULONG output_bytes_this_pass = ULONG_MAX; + if (requested < output_bytes_this_pass) { + output_bytes_this_pass = requested; } - CRYPTO_w_unlock(CRYPTO_LOCK_RAND); - CRYPTO_r_lock(CRYPTO_LOCK_RAND); - } - - ok = global_provider_init; - provider = global_provider; - CRYPTO_r_unlock(CRYPTO_LOCK_RAND); - - if (!ok) { - abort(); - return ok; - } - - if (TRUE != CryptGenRandom(provider, requested, out)) { - abort(); - return 0; + if (RtlGenRandom(out, output_bytes_this_pass) == FALSE) { + abort(); + return 0; + } + requested -= output_bytes_this_pass; + out += output_bytes_this_pass; } - return 1; } diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c index 21785dc..8e64f76 100644 --- a/crypto/x509/x_crl.c +++ b/crypto/x509/x_crl.c @@ -64,8 +64,24 @@ #include <openssl/x509.h> #include <openssl/x509v3.h> -#include "../asn1/asn1_locl.h" +/* Method to handle CRL access. + * In general a CRL could be very large (several Mb) and can consume large + * amounts of resources if stored in memory by multiple processes. + * This method allows general CRL operations to be redirected to more + * efficient callbacks: for example a CRL entry database. + */ + +#define X509_CRL_METHOD_DYNAMIC 1 +struct x509_crl_method_st + { + int flags; + int (*crl_init)(X509_CRL *crl); + int (*crl_free)(X509_CRL *crl); + int (*crl_lookup)(X509_CRL *crl, X509_REVOKED **ret, + ASN1_INTEGER *ser, X509_NAME *issuer); + int (*crl_verify)(X509_CRL *crl, EVP_PKEY *pk); + }; static int X509_REVOKED_cmp(const X509_REVOKED **a, const X509_REVOKED **b); diff --git a/crypto/x509v3/v3nametest.c b/crypto/x509v3/v3nametest.c index 6a2ea85..b2e9c09 100644 --- a/crypto/x509v3/v3nametest.c +++ b/crypto/x509v3/v3nametest.c @@ -53,9 +53,9 @@ * Hudson (tjh@cryptsoft.com). */ #include <string.h> -#include <strings.h> #include <openssl/crypto.h> +#include <openssl/mem.h> #include <openssl/x509.h> #include <openssl/x509v3.h> @@ -326,7 +326,7 @@ static void run_cert(X509 *crt, const char *nameincert, const char *const *pname = names; while (*pname) { - int samename = strcasecmp(nameincert, *pname) == 0; + int samename = OPENSSL_strcasecmp(nameincert, *pname) == 0; size_t namelen = strlen(*pname); char *name = malloc(namelen); int match, ret; diff --git a/include/openssl/base.h b/include/openssl/base.h index 52cb1e9..6207c54 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -159,7 +159,6 @@ typedef struct X509_POLICY_NODE_st X509_POLICY_NODE; typedef struct X509_POLICY_TREE_st X509_POLICY_TREE; typedef struct X509_algor_st X509_ALGOR; typedef struct X509_crl_st X509_CRL; -typedef struct X509_name_st X509_NAME; typedef struct X509_pubkey_st X509_PUBKEY; typedef struct bignum_ctx BN_CTX; typedef struct bignum_st BIGNUM; diff --git a/include/openssl/bytestring.h b/include/openssl/bytestring.h index acaba8e..d5e6cf9 100644 --- a/include/openssl/bytestring.h +++ b/include/openssl/bytestring.h @@ -166,6 +166,41 @@ OPENSSL_EXPORT int CBS_get_any_asn1_element(CBS *cbs, CBS *out, * in 64 bits. */ OPENSSL_EXPORT int CBS_get_asn1_uint64(CBS *cbs, uint64_t *out); +/* CBS_get_optional_asn1 gets an optional explicitly-tagged element + * from |cbs| tagged with |tag| and sets |*out| to its contents. If + * present, it sets |*out_present| to one, otherwise zero. It returns + * one on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1(CBS *cbs, CBS *out, int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_octet_string gets an optional + * explicitly-tagged OCTET STRING from |cbs|. If present, it sets + * |*out| to the string and |*out_present| to one. Otherwise, it sets + * |*out| to empty and |*out_present| to zero. |out_present| may be + * NULL. It returns one on success, whether or not the element was + * present, and zero on decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_octet_string(CBS *cbs, CBS *out, + int *out_present, + unsigned tag); + +/* CBS_get_optional_asn1_uint64 gets an optional explicitly-tagged + * INTEGER from |cbs|. If present, it sets |*out| to the + * value. Otherwise, it sets |*out| to |default_value|. It returns one + * on success, whether or not the element was present, and zero on + * decode failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, + unsigned tag, + uint64_t default_value); + +/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from + * |cbs|. If present, it sets |*out| to either zero or one, based on the + * boolean. Otherwise, it sets |*out| to |default_value|. It returns one on + * success, whether or not the element was present, and zero on decode + * failure. */ +OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag, + int default_value); + /* CRYPTO ByteBuilder. * @@ -277,6 +312,10 @@ OPENSSL_EXPORT int CBB_add_u16(CBB *cbb, uint16_t value); * returns one on success and zero otherwise. */ OPENSSL_EXPORT int CBB_add_u24(CBB *cbb, uint32_t value); +/* CBB_add_asn1_uint64 writes an ASN.1 INTEGER into |cbb| using |CBB_add_asn1| + * and writes |value| in its contents. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int CBB_add_asn1_uint64(CBB *cbb, uint64_t value); #if defined(__cplusplus) } /* extern C */ diff --git a/include/openssl/dtls1.h b/include/openssl/dtls1.h index 5aef0c4..a9e3ada 100644 --- a/include/openssl/dtls1.h +++ b/include/openssl/dtls1.h @@ -72,11 +72,6 @@ extern "C" { /* Special value for method supporting multiple versions */ #define DTLS_ANY_VERSION 0x1FFFF -#if 0 -/* this alert description is not specified anywhere... */ -#define DTLS1_AD_MISSING_HANDSHAKE_MESSAGE 110 -#endif - /* lengths of messages */ #define DTLS1_COOKIE_LENGTH 256 @@ -89,11 +84,7 @@ extern "C" { #define DTLS1_CCS_HEADER_LENGTH 1 -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE -#define DTLS1_AL_HEADER_LENGTH 7 -#else #define DTLS1_AL_HEADER_LENGTH 2 -#endif #ifndef OPENSSL_NO_SSL_INTERN diff --git a/include/openssl/err.h b/include/openssl/err.h index a7f30c7..b9c48c3 100644 --- a/include/openssl/err.h +++ b/include/openssl/err.h @@ -392,7 +392,6 @@ enum { ERR_LIB_PKCS7, ERR_LIB_PKCS8, ERR_LIB_X509V3, - ERR_LIB_PKCS12, ERR_LIB_RAND, ERR_LIB_ENGINE, ERR_LIB_OCSP, @@ -426,7 +425,6 @@ enum { #define ERR_R_PKCS7_LIB ERR_LIB_PKCS7 #define ERR_R_PKCS8_LIB ERR_LIB_PKCS8 #define ERR_R_X509V3_LIB ERR_LIB_X509V3 -#define ERR_R_PKCS12_LIB ERR_LIB_PKCS12 #define ERR_R_RAND_LIB ERR_LIB_RAND #define ERR_R_DSO_LIB ERR_LIB_DSO #define ERR_R_ENGINE_LIB ERR_LIB_ENGINE diff --git a/include/openssl/evp.h b/include/openssl/evp.h index e3922a3..1f60145 100644 --- a/include/openssl/evp.h +++ b/include/openssl/evp.h @@ -290,10 +290,7 @@ OPENSSL_EXPORT int EVP_DigestVerifyUpdate(EVP_MD_CTX *ctx, const void *data, /* EVP_DigestVerifyFinal verifies that |sig_len| bytes of |sig| are a valid * signature for the data that has been included by one or more calls to - * |EVP_DigestVerifyUpdate|. - * - * It returns one on success and <= 0 on error. WARNING: this differs from the - * usual return value convention. */ + * |EVP_DigestVerifyUpdate|. It returns one on success and zero otherwise. */ OPENSSL_EXPORT int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len); @@ -462,8 +459,8 @@ OPENSSL_EXPORT int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx); * space available at |sig|. If sufficient, the signature will be written to * |sig| and |*sig_len| updated with the true length. * - * WARNING: Setting |out| to NULL only gives the maximum size of the - * plaintext. The actual plaintext may be smaller. + * WARNING: Setting |sig| to NULL only gives the maximum size of the + * signature. The actual signature may be smaller. * * It returns one on success or zero on error. (Note: this differs from * OpenSSL, which can also return negative values to indicate an error. ) */ diff --git a/include/openssl/srtp.h b/include/openssl/srtp.h index c11608e..860362b 100644 --- a/include/openssl/srtp.h +++ b/include/openssl/srtp.h @@ -115,14 +115,15 @@ Copyright (C) 2011, RTFM, Inc. */ -#ifndef HEADER_D1_SRTP_H -#define HEADER_D1_SRTP_H +#ifndef OPENSSL_HEADER_SRTP_H +#define OPENSSL_HEADER_SRTP_H #ifdef __cplusplus extern "C" { #endif - + +/* Constants for SRTP profiles */ #define SRTP_AES128_CM_SHA1_80 0x0001 #define SRTP_AES128_CM_SHA1_32 0x0002 #define SRTP_AES128_F8_SHA1_80 0x0003 @@ -130,32 +131,47 @@ extern "C" { #define SRTP_NULL_SHA1_80 0x0005 #define SRTP_NULL_SHA1_32 0x0006 -/* SSL_CTX_set_tlsext_use_srtp enables SRTP for all SSL objects - * created from |ctx|. |profile| contains a colon-separated list of - * profile names. It returns zero on success and one on failure. +/* SSL_CTX_set_srtp_profiles enables SRTP for all SSL objects created from + * |ctx|. |profile| contains a colon-separated list of profile names. It returns + * one on success and zero on failure. */ +OPENSSL_EXPORT int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, + const char *profiles); + +/* SSL_set_srtp_profiles enables SRTP for |ssl|. |profile| contains a + * colon-separated list of profile names. It returns one on success and zero on + * failure. */ +OPENSSL_EXPORT int SSL_set_srtp_profiles(SSL *ctx, const char *profiles); + +/* SSL_get_srtp_profiles returns the SRTP profiles supported by |ssl|. */ +OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles( + SSL *ssl); + +/* SSL_get_selected_srtp_profile returns the selected SRTP profile, or NULL if + * SRTP was not negotiated. */ +OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s); + + +/* Deprecated functions */ + +/* SSL_CTX_set_tlsext_use_srtp calls SSL_CTX_set_srtp_profiles. It returns zero + * on success and one on failure. * - * WARNING: this function is dangerous because it breaks the usual - * return value convention. */ + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_CTX_set_srtp_profiles instead. */ OPENSSL_EXPORT int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles); -/* SSL_set_tlsext_use_srtp enables SRTP for |ssl| with a profile list. - * |profile| contains a colon-separated list of profile names. It - * returns zero on success and one on failure. +/* SSL_set_tlsext_use_srtp calls SSL_set_srtp_profiles. It returns zero on + * success and one on failure. * - * WARNING: this function is dangerous because it breaks the usual - * return value convention. */ + * WARNING: this function is dangerous because it breaks the usual return value + * convention. Use SSL_set_srtp_profiles instead. */ OPENSSL_EXPORT int SSL_set_tlsext_use_srtp(SSL *ctx, const char *profiles); -OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s); - -OPENSSL_EXPORT STACK_OF(SRTP_PROTECTION_PROFILE) * - SSL_get_srtp_profiles(SSL *ssl); -OPENSSL_EXPORT SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s); #ifdef __cplusplus -} +} /* extern C */ #endif -#endif +#endif /* OPENSSL_HEADER_SRTP_H */ diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 2168613..31ff5db 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -359,34 +359,8 @@ struct ssl_method_st long (*ssl_ctx_callback_ctrl)(SSL_CTX *s, int cb_id, void (*fp)(void)); }; -/* Lets make this into an ASN.1 type structure as follows - * SSL_SESSION_ID ::= SEQUENCE { - * version INTEGER, -- structure version number - * SSLversion INTEGER, -- SSL version number - * Cipher OCTET STRING, -- the 3 byte cipher ID - * Session_ID OCTET STRING, -- the Session ID - * Master_key OCTET STRING, -- the master key - * Key_Arg [ 0 ] IMPLICIT OCTET STRING, -- the optional Key argument - * Time [ 1 ] EXPLICIT INTEGER, -- optional Start Time - * Timeout [ 2 ] EXPLICIT INTEGER, -- optional Timeout ins seconds - * Peer [ 3 ] EXPLICIT X509, -- optional Peer Certificate - * Session_ID_context [ 4 ] EXPLICIT OCTET STRING, -- the Session ID context - * Verify_result [ 5 ] EXPLICIT INTEGER, -- X509_V_... code for `Peer' - * HostName [ 6 ] EXPLICIT OCTET STRING, -- optional HostName from servername TLS extension - * PSK_identity_hint [ 7 ] EXPLICIT OCTET STRING, -- optional PSK identity hint - * PSK_identity [ 8 ] EXPLICIT OCTET STRING, -- optional PSK identity - * Ticket_lifetime_hint [9] EXPLICIT INTEGER, -- server's lifetime hint for session ticket - * Ticket [10] EXPLICIT OCTET STRING, -- session ticket (clients only) - * Compression_meth [11] EXPLICIT OCTET STRING, -- optional compression method - * SRP_username [ 12 ] EXPLICIT OCTET STRING -- optional SRP username - * Peer SHA256 [13] EXPLICIT OCTET STRING, -- optional SHA256 hash of Peer certifiate - * original handshake hash [14] EXPLICIT OCTET STRING, -- optional original handshake hash - * tlsext_signed_cert_timestamp_list [15] EXPLICIT OCTET STRING, -- optional signed cert timestamp list extension - * ocsp_response [16] EXPLICIT OCTET STRING, -- optional saved OCSP response from the server - * } - * Look in ssl/ssl_asn1.c for more details - * I'm using EXPLICIT tags so I can read the damn things using asn1parse :-). - */ +/* An SSL_SESSION represents an SSL session that may be resumed in an + * abbreviated handshake. */ struct ssl_session_st { int ssl_version; /* what ssl version session info is @@ -458,6 +432,11 @@ struct ssl_session_st * resumption. */ unsigned char original_handshake_hash[EVP_MAX_MD_SIZE]; unsigned int original_handshake_hash_len; + + /* extended_master_secret is true if the master secret in this session + * was generated using EMS and thus isn't vulnerable to the Triple + * Handshake attack. */ + char extended_master_secret; }; #endif @@ -529,9 +508,6 @@ struct ssl_session_st * the misconception that non-blocking SSL_write() behaves like * non-blocking write(): */ #define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L -/* Never bother the application with retries if the transport - * is blocking: */ -#define SSL_MODE_AUTO_RETRY 0x00000004L /* Don't attempt to automatically build certificate chain */ #define SSL_MODE_NO_AUTO_CHAIN 0x00000008L /* Save RAM by releasing read and write buffers when they're empty. (SSL3 and @@ -539,6 +515,10 @@ struct ssl_session_st * just freed (depending on the context's setting for freelist_max_len). */ #define SSL_MODE_RELEASE_BUFFERS 0x00000010L +/* The following flags do nothing and are included only to make it easier to + * compile code with BoringSSL. */ +#define SSL_MODE_AUTO_RETRY 0 + /* Send the current time in the Random fields of the ClientHello and * ServerHello records for compatibility with hypothetical implementations * that require it. @@ -1978,18 +1958,52 @@ OPENSSL_EXPORT int SSL_SESSION_print_fp(FILE *fp,const SSL_SESSION *ses); OPENSSL_EXPORT int SSL_SESSION_print(BIO *fp,const SSL_SESSION *ses); #endif OPENSSL_EXPORT void SSL_SESSION_free(SSL_SESSION *ses); -OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in,unsigned char **pp); OPENSSL_EXPORT int SSL_set_session(SSL *to, SSL_SESSION *session); OPENSSL_EXPORT int SSL_CTX_add_session(SSL_CTX *s, SSL_SESSION *c); OPENSSL_EXPORT int SSL_CTX_remove_session(SSL_CTX *,SSL_SESSION *c); OPENSSL_EXPORT int SSL_CTX_set_generate_session_id(SSL_CTX *, GEN_SESSION_CB); OPENSSL_EXPORT int SSL_set_generate_session_id(SSL *, GEN_SESSION_CB); OPENSSL_EXPORT int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, unsigned int id_len); -OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a,const unsigned char **pp, long length); -#ifdef HEADER_X509_H +/* SSL_SESSION_to_bytes serializes |in| into a newly allocated buffer + * and sets |*out_data| to that buffer and |*out_len| to its + * length. The caller takes ownership of the buffer and must call + * |OPENSSL_free| when done. It returns one on success and zero on + * error. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, + size_t *out_len); + +/* SSL_SESSION_to_bytes_for_ticket serializes |in|, but excludes the + * session ID which is not necessary in a session ticket. */ +OPENSSL_EXPORT int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, + uint8_t **out_data, + size_t *out_len); + +/* Deprecated: i2d_SSL_SESSION serializes |in| to the bytes pointed to + * by |*pp|. On success, it returns the number of bytes written and + * advances |*pp| by that many bytes. On failure, it returns -1. If + * |pp| is NULL, no bytes are written and only the length is + * returned. + * + * Use SSL_SESSION_to_bytes instead. */ +OPENSSL_EXPORT int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp); + +/* d2i_SSL_SESSION deserializes a serialized buffer contained in the + * |length| bytes pointed to by |*pp|. It returns the new SSL_SESSION + * and advances |*pp| by the number of bytes consumed on success and + * NULL on failure. If |a| is NULL, the caller takes ownership of the + * new session and must call |SSL_SESSION_free| when done. + * + * If |a| and |*a| are not NULL, the SSL_SESSION at |*a| is overridden + * with the deserialized session rather than allocating a new one. In + * addition, |a| is not NULL, but |*a| is, |*a| is set to the new + * SSL_SESSION. + * + * Passing a value other than NULL to |a| is deprecated. */ +OPENSSL_EXPORT SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, + long length); + OPENSSL_EXPORT X509 * SSL_get_peer_certificate(const SSL *s); -#endif OPENSSL_EXPORT STACK_OF(X509) *SSL_get_peer_cert_chain(const SSL *s); @@ -2461,6 +2475,12 @@ OPENSSL_EXPORT void ERR_load_SSL_strings(void); #define SSL_F_ssl3_cert_verify_hash 284 #define SSL_F_ssl_ctx_log_rsa_client_key_exchange 285 #define SSL_F_ssl_ctx_log_master_secret 286 +#define SSL_F_d2i_SSL_SESSION 287 +#define SSL_F_i2d_SSL_SESSION 288 +#define SSL_F_d2i_SSL_SESSION_get_octet_string 289 +#define SSL_F_d2i_SSL_SESSION_get_string 290 +#define SSL_F_ssl3_send_new_session_ticket 291 +#define SSL_F_SSL_SESSION_to_bytes_full 292 #define SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS 100 #define SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC 101 #define SSL_R_INVALID_NULL_CMD_NAME 102 @@ -2774,6 +2794,7 @@ OPENSSL_EXPORT void ERR_load_SSL_strings(void); #define SSL_R_UNPROCESSED_HANDSHAKE_DATA 440 #define SSL_R_HANDSHAKE_RECORD_BEFORE_CCS 441 #define SSL_R_SESSION_MAY_NOT_BE_CREATED 442 +#define SSL_R_INVALID_SSL_SESSION 443 #define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000 #define SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE 1010 #define SSL_R_SSLV3_ALERT_BAD_RECORD_MAC 1020 diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 2a201aa..3d62763 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -485,6 +485,15 @@ typedef struct ssl3_state_st * this extension to the client. */ uint16_t *peer_ellipticcurvelist; size_t peer_ellipticcurvelist_length; + + /* extended_master_secret indicates whether the extended master + * secret computation is used in this handshake. Note that this + * is different from whether it was used for the current + * session. If this is a resumption handshake then EMS might be + * negotiated in the client and server hello messages, but it + * doesn't matter if the session that's being resumed didn't + * use it to create the master secret initially. */ + char extended_master_secret; } tmp; /* Connection binding to prevent renegotiation attacks */ diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 08ad8e8..d2682dd 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -240,6 +240,9 @@ extern "C" { */ #define TLSEXT_TYPE_padding 21 +/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */ +#define TLSEXT_TYPE_extended_master_secret 23 + /* ExtensionType value from RFC4507 */ #define TLSEXT_TYPE_session_ticket 35 @@ -704,6 +707,8 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb) #define TLS_MD_IV_BLOCK_CONST_SIZE 8 #define TLS_MD_MASTER_SECRET_CONST "master secret" #define TLS_MD_MASTER_SECRET_CONST_SIZE 13 +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret" +#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22 /* TLS Session Ticket extension struct */ diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 398bec7..9766f74 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -143,7 +143,7 @@ DECLARE_STACK_OF(X509_NAME_ENTRY) DECLARE_ASN1_SET_OF(X509_NAME_ENTRY) /* we always keep X509_NAMEs in 2 forms. */ -struct X509_name_st +typedef struct X509_name_st { STACK_OF(X509_NAME_ENTRY) *entries; int modified; /* true if 'bytes' needs to be built */ @@ -155,7 +155,7 @@ struct X509_name_st /* unsigned long hash; Keep the hash around for lookups */ unsigned char *canon_enc; int canon_enclen; - } /* X509_NAME */; + } X509_NAME; DECLARE_STACK_OF(X509_NAME) diff --git a/ssl/d1_both.c b/ssl/d1_both.c index 2d944d8..82d4a86 100644 --- a/ssl/d1_both.c +++ b/ssl/d1_both.c @@ -229,7 +229,7 @@ dtls1_hm_fragment_free(hm_fragment *frag) } /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ -int dtls1_do_write(SSL *s, int type) +int dtls1_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash) { int ret; int curr_mtu; @@ -365,7 +365,8 @@ int dtls1_do_write(SSL *s, int type) * message got sent. but why would this happen? */ assert(len == (unsigned int)ret); - if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting) + if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting && + should_add_to_finished_hash == add_to_finished_hash) { /* should not be done for 'Hello Request's, but in that case * we'll ignore the result anyway */ @@ -967,7 +968,7 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b) } /* SSL3_ST_CW_CHANGE_B */ - return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC)); + return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash)); } int dtls1_read_failed(SSL *s, int code) @@ -991,21 +992,6 @@ int dtls1_read_failed(SSL *s, int code) return code; } -#if 0 /* for now, each alert contains only one record number */ - item = pqueue_peek(state->rcvd_records); - if ( item ) - { - /* send an alert immediately for all the missing records */ - } - else -#endif - -#if 0 /* no more alert sending, just retransmit the last set of messages */ - if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT) - ssl3_send_alert(s,SSL3_AL_WARNING, - DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); -#endif - return dtls1_handle_timeout(s); } @@ -1181,7 +1167,7 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off, } ret = dtls1_do_write(s, frag->msg_header.is_ccs ? - SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE); + SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE, add_to_finished_hash); /* restore current state */ s->enc_write_ctx = saved_state.enc_write_ctx; diff --git a/ssl/d1_enc.c b/ssl/d1_enc.c index dec0ea5..11d06cb 100644 --- a/ssl/d1_enc.c +++ b/ssl/d1_enc.c @@ -179,10 +179,6 @@ int dtls1_enc(SSL *s, int send) enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); } -#ifdef KSSL_DEBUG - printf("dtls1_enc(%d)\n", send); -#endif /* KSSL_DEBUG */ - if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { @@ -208,24 +204,6 @@ int dtls1_enc(SSL *s, int send) rec->length+=i; } -#ifdef KSSL_DEBUG - { - unsigned long ui; - printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", - ds,rec->data,rec->input,l); - printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", - ds->buf_len, ds->cipher->key_len, - DES_KEY_SZ, DES_SCHEDULE_SZ, - ds->cipher->iv_len); - printf("\t\tIV: "); - for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); - printf("\n"); - printf("\trec->input="); - for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]); - printf("\n"); - } -#endif /* KSSL_DEBUG */ - if (!send) { if (l == 0 || l%bs != 0) @@ -234,15 +212,6 @@ int dtls1_enc(SSL *s, int send) EVP_Cipher(ds,rec->data,rec->input,l); -#ifdef KSSL_DEBUG - { - unsigned long i; - printf("\trec->data="); - for (i=0; i<l; i++) - printf(" %02x", rec->data[i]); printf("\n"); - } -#endif /* KSSL_DEBUG */ - if ((bs != 1) && !send) return tls1_cbc_remove_padding(s, rec, bs, mac_size); } diff --git a/ssl/d1_lib.c b/ssl/d1_lib.c index 96ce496..650d8e7 100644 --- a/ssl/d1_lib.c +++ b/ssl/d1_lib.c @@ -74,8 +74,9 @@ static void get_current_time(OPENSSL_timeval *t); static OPENSSL_timeval* dtls1_get_timeout(SSL *s, OPENSSL_timeval* timeleft); static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len); -static int dtls1_handshake_write(SSL *s); +static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash); int dtls1_listen(SSL *s, struct sockaddr *client); +static void dtls1_add_to_finished_hash(SSL *s); SSL3_ENC_METHOD DTLSv1_enc_data={ tls1_enc, @@ -93,7 +94,8 @@ SSL3_ENC_METHOD DTLSv1_enc_data={ SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, - dtls1_handshake_write + dtls1_handshake_write, + dtls1_add_to_finished_hash, }; SSL3_ENC_METHOD DTLSv1_2_enc_data={ @@ -113,7 +115,8 @@ SSL3_ENC_METHOD DTLSv1_2_enc_data={ |SSL_ENC_FLAG_SHA256_PRF|SSL_ENC_FLAG_TLS1_2_CIPHERS, DTLS1_HM_HEADER_LENGTH, dtls1_set_handshake_header, - dtls1_handshake_write + dtls1_handshake_write, + dtls1_add_to_finished_hash, }; int dtls1_new(SSL *s) @@ -502,7 +505,25 @@ static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len) dtls1_buffer_message(s, 0); } -static int dtls1_handshake_write(SSL *s) +static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash) { - return dtls1_do_write(s, SSL3_RT_HANDSHAKE); + return dtls1_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash); + } + +static void dtls1_add_to_finished_hash(SSL *s) + { + uint8_t *record = (uint8_t *) &s->init_buf->data[s->init_off]; + const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr; + uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH]; + uint8_t *p = serialised_header; + + /* Construct the message header as if it were a single fragment. */ + *p++ = msg_hdr->type; + l2n3(msg_hdr->msg_len, p); + s2n (msg_hdr->seq, p); + l2n3(0, p); + l2n3(msg_hdr->msg_len, p); + ssl3_finish_mac(s, serialised_header, sizeof(serialised_header)); + ssl3_finish_mac(s, record + DTLS1_HM_HEADER_LENGTH, + s->init_num - DTLS1_HM_HEADER_LENGTH); } diff --git a/ssl/d1_pkt.c b/ssl/d1_pkt.c index e2855b8..0ecbb2e 100644 --- a/ssl/d1_pkt.c +++ b/ssl/d1_pkt.c @@ -918,14 +918,6 @@ start: * may be fragmented--don't always expect dest_maxlen bytes */ if ( rr->length < dest_maxlen) { -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - /* - * for normal alerts rr->length is 2, while - * dest_maxlen is 7 if we were to handle this - * non-existing alert... - */ - FIX ME -#endif s->rstate=SSL_ST_READ_HEADER; rr->length = 0; goto start; @@ -984,23 +976,6 @@ start: OPENSSL_PUT_ERROR(SSL, dtls1_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return(-1); } - - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } } } /* we either finished a handshake or ignored the request, @@ -1038,31 +1013,6 @@ start: s->shutdown |= SSL_RECEIVED_SHUTDOWN; return(0); } -#if 0 - /* XXX: this is a possible improvement in the future */ - /* now check if it's a missing record */ - if (alert_descr == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) - { - unsigned short seq; - unsigned int frag_off; - unsigned char *p = &(s->d1->alert_fragment[2]); - - n2s(p, seq); - n2l3(p, frag_off); - - dtls1_retransmit_message(s, - dtls1_get_queue_priority(frag->msg_header.seq, 0), - frag_off, &found); - if ( ! found && SSL_in_init(s)) - { - /* fprintf( stderr,"in init = %d\n", SSL_in_init(s)); */ - /* requested a message not yet sent, - send an alert ourselves */ - ssl3_send_alert(s,SSL3_AL_WARNING, - DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); - } - } -#endif } else if (alert_level == 2) /* fatal */ { @@ -1188,22 +1138,6 @@ start: return(-1); } - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } goto start; } @@ -1577,24 +1511,6 @@ int dtls1_dispatch_alert(SSL *s) *ptr++ = s->s3->send_alert[0]; *ptr++ = s->s3->send_alert[1]; -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - if (s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE) - { - s2n(s->d1->handshake_read_seq, ptr); -#if 0 - if ( s->d1->r_msg_hdr.frag_off == 0) /* waiting for a new msg */ - - else - s2n(s->d1->r_msg_hdr.seq, ptr); /* partial msg read */ -#endif - -#if 0 - fprintf(stderr, "s->d1->handshake_read_seq = %d, s->d1->r_msg_hdr.seq = %d\n",s->d1->handshake_read_seq,s->d1->r_msg_hdr.seq); -#endif - l2n3(s->d1->r_msg_hdr.frag_off, ptr); - } -#endif - i = do_dtls1_write(s, SSL3_RT_ALERT, &buf[0], sizeof(buf)); if (i <= 0) { @@ -1603,11 +1519,7 @@ int dtls1_dispatch_alert(SSL *s) } else { - if (s->s3->send_alert[0] == SSL3_AL_FATAL -#ifdef DTLS1_AD_MISSING_HANDSHAKE_MESSAGE - || s->s3->send_alert[1] == DTLS1_AD_MISSING_HANDSHAKE_MESSAGE -#endif - ) + if (s->s3->send_alert[0] == SSL3_AL_FATAL) (void)BIO_flush(s->wbio); if (s->msg_callback) diff --git a/ssl/d1_srtp.c b/ssl/d1_srtp.c index bc278c3..69b11ad 100644 --- a/ssl/d1_srtp.c +++ b/ssl/d1_srtp.c @@ -114,8 +114,6 @@ Copyright (C) 2011, RTFM, Inc. */ -#ifndef OPENSSL_NO_SRTP - #include <stdio.h> #include <openssl/bytestring.h> @@ -226,20 +224,17 @@ static int ssl_ctx_make_profiles(const char *profiles_string,STACK_OF(SRTP_PROTE return 1; } - -int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx,const char *profiles) + +int SSL_CTX_set_srtp_profiles(SSL_CTX *ctx, const char *profiles) { - /* This API inverts its return value. */ - return !ssl_ctx_make_profiles(profiles,&ctx->srtp_profiles); + return ssl_ctx_make_profiles(profiles, &ctx->srtp_profiles); } -int SSL_set_tlsext_use_srtp(SSL *s,const char *profiles) +int SSL_set_srtp_profiles(SSL *s, const char *profiles) { - /* This API inverts its return value. */ - return !ssl_ctx_make_profiles(profiles,&s->srtp_profiles); + return ssl_ctx_make_profiles(profiles, &s->srtp_profiles); } - STACK_OF(SRTP_PROTECTION_PROFILE) *SSL_get_srtp_profiles(SSL *s) { if(s != NULL) @@ -263,6 +258,18 @@ SRTP_PROTECTION_PROFILE *SSL_get_selected_srtp_profile(SSL *s) return s->srtp_profile; } +int SSL_CTX_set_tlsext_use_srtp(SSL_CTX *ctx, const char *profiles) + { + /* This API inverts its return value. */ + return !SSL_CTX_set_srtp_profiles(ctx, profiles); + } + +int SSL_set_tlsext_use_srtp(SSL *s, const char *profiles) + { + /* This API inverts its return value. */ + return !SSL_set_srtp_profiles(s, profiles); + } + /* Note: this function returns 0 length if there are no profiles specified */ int ssl_add_clienthello_use_srtp_ext(SSL *s, unsigned char *p, int *len, int maxlen) @@ -464,6 +471,3 @@ int ssl_parse_serverhello_use_srtp_ext(SSL *s, CBS *cbs, int *out_alert) *out_alert = SSL_AD_ILLEGAL_PARAMETER; return 0; } - - -#endif diff --git a/ssl/d1_srvr.c b/ssl/d1_srvr.c index 79da484..e1c5616 100644 --- a/ssl/d1_srvr.c +++ b/ssl/d1_srvr.c @@ -687,5 +687,5 @@ int dtls1_send_hello_verify_request(SSL *s) } /* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */ - return(dtls1_do_write(s,SSL3_RT_HANDSHAKE)); + return(dtls1_do_write(s,SSL3_RT_HANDSHAKE, add_to_finished_hash)); } diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 6604fc7..65eb3ba 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c @@ -127,17 +127,19 @@ #include "ssl_locl.h" /* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */ -int ssl3_do_write(SSL *s, int type) +int ssl3_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash) { int ret; ret=ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off], s->init_num); if (ret < 0) return(-1); - if (type == SSL3_RT_HANDSHAKE) + if (type == SSL3_RT_HANDSHAKE && should_add_to_finished_hash == add_to_finished_hash) + { /* should not be done for 'Hello Request's, but in that case * we'll ignore the result anyway */ ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret); + } if (ret == s->init_num) { @@ -320,7 +322,7 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b) } /* SSL3_ST_CW_CHANGE_B */ - return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC)); + return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash)); } unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk) @@ -417,18 +419,6 @@ long ssl3_get_message(SSL *s, int st1, int stn, int mt, long max, int hash_messa OPENSSL_PUT_ERROR(SSL, ssl3_get_message, SSL_R_UNEXPECTED_MESSAGE); goto f_err; } - if ((mt < 0) && (*p == SSL3_MT_CLIENT_HELLO) && - (st1 == SSL3_ST_SR_CERT_A) && - (stn == SSL3_ST_SR_CERT_B)) - { - /* At this point we have got an MS SGC second client - * hello (maybe we should always allow the client to - * start a new handshake?). We need to restart the mac. - * Don't increment {num,total}_renegotiations because - * we have not completed the handshake. */ - ssl3_init_finished_mac(s); - } - s->s3->tmp.message_type= *(p++); n2l3(p,l); diff --git a/ssl/s3_clnt.c b/ssl/s3_clnt.c index 6574f5a..64bccfa 100644 --- a/ssl/s3_clnt.c +++ b/ssl/s3_clnt.c @@ -982,7 +982,7 @@ int ssl3_get_server_hello(SSL *s) /* Don't digest cached records if no sigalgs: we may need them for * client authentication. */ - if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s)) + if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, free_handshake_buffer)) goto f_err; /* Only the NULL compression algorithm is supported. */ @@ -1550,11 +1550,11 @@ int ssl3_get_server_key_exchange(SSL *s) } else { - EVP_VerifyInit_ex(&md_ctx, md, NULL); - EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); - EVP_VerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)); - if (EVP_VerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature), pkey) <= 0) + if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) || + !EVP_DigestVerifyUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || + !EVP_DigestVerifyUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || + !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)) || + !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature))) { /* bad signature */ al=SSL_AD_DECRYPT_ERROR; @@ -1637,7 +1637,7 @@ int ssl3_get_certificate_request(SSL *s) */ if (s->s3->handshake_buffer) { - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) goto err; } return(1); @@ -1909,6 +1909,8 @@ int ssl3_send_client_key_exchange(SSL *s) BN_CTX * bn_ctx = NULL; unsigned int psk_len = 0; unsigned char psk[PSK_MAX_PSK_LEN]; + uint8_t *pms = NULL; + size_t pms_len = 0; if (s->state == SSL3_ST_CW_KEY_EXCH_A) { @@ -1917,16 +1919,12 @@ int ssl3_send_client_key_exchange(SSL *s) alg_k=s->s3->tmp.new_cipher->algorithm_mkey; alg_a=s->s3->tmp.new_cipher->algorithm_auth; + /* If using a PSK key exchange, prepare the pre-shared key. */ if (alg_a & SSL_aPSK) { char identity[PSK_MAX_IDENTITY_LEN + 1]; size_t identity_len; - unsigned char *t = NULL; - unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4]; - unsigned int pre_ms_len = 0; - int psk_err = 1; - n = 0; if (s->psk_client_callback == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_NO_CLIENT_CB); @@ -1939,40 +1937,19 @@ int ssl3_send_client_key_exchange(SSL *s) if (psk_len > PSK_MAX_PSK_LEN) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR); - goto psk_err; + goto err; } else if (psk_len == 0) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND); - goto psk_err; + ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); + goto err; } identity_len = OPENSSL_strnlen(identity, sizeof(identity)); if (identity_len > PSK_MAX_IDENTITY_LEN) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR); - goto psk_err; - } - - if (!(alg_k & SSL_kEECDH)) - { - /* Create the shared secret now if we're not using ECDHE-PSK. - * TODO(davidben): Refactor this logic similarly - * to ssl3_get_client_key_exchange. */ - pre_ms_len = 2+psk_len+2+psk_len; - t = pre_ms; - s2n(psk_len, t); - memset(t, 0, psk_len); - t+=psk_len; - s2n(psk_len, t); - memcpy(t, psk, psk_len); - - s->session->master_key_length = - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key, - pre_ms, pre_ms_len); - s2n(identity_len, p); - memcpy(p, identity, identity_len); - n = 2 + identity_len; + goto err; } if (s->session->psk_identity != NULL) @@ -1981,23 +1958,30 @@ int ssl3_send_client_key_exchange(SSL *s) if (s->session->psk_identity == NULL) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); - goto psk_err; - } - psk_err = 0; - psk_err: - OPENSSL_cleanse(identity, sizeof(identity)); - OPENSSL_cleanse(pre_ms, sizeof(pre_ms)); - if (psk_err != 0) - { - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); goto err; } + + /* Write out psk_identity. */ + s2n(identity_len, p); + memcpy(p, identity, identity_len); + p += identity_len; + n = 2 + identity_len; } + /* Depending on the key exchange method, compute |pms| + * and |pms_len|. */ if (alg_k & SSL_kRSA) { RSA *rsa; - unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH]; + size_t enc_pms_len; + + pms_len = SSL_MAX_MASTER_KEY_LENGTH; + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); + goto err; + } if (s->session->sess_cert == NULL) { @@ -2022,49 +2006,47 @@ int ssl3_send_client_key_exchange(SSL *s) EVP_PKEY_free(pkey); } - tmp_buf[0]=s->client_version>>8; - tmp_buf[1]=s->client_version&0xff; - if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0) + pms[0]=s->client_version>>8; + pms[1]=s->client_version&0xff; + if (RAND_bytes(&pms[2],SSL_MAX_MASTER_KEY_LENGTH-2) <= 0) goto err; - s->session->master_key_length=sizeof tmp_buf; + s->session->master_key_length=SSL_MAX_MASTER_KEY_LENGTH; q=p; - /* Fix buf for TLS and beyond */ + /* In TLS and beyond, reserve space for the length prefix. */ if (s->version > SSL3_VERSION) - p+=2; - n=RSA_public_encrypt(sizeof tmp_buf, - tmp_buf,p,rsa,RSA_PKCS1_PADDING); - if (n <= 0) + { + p += 2; + n += 2; + } + if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa), + pms, pms_len, RSA_PKCS1_PADDING)) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_RSA_ENCRYPT); goto err; } + n += enc_pms_len; /* Log the premaster secret, if logging is enabled. */ if (!ssl_ctx_log_rsa_client_key_exchange(s->ctx, - p, n, tmp_buf, sizeof(tmp_buf))) + p, enc_pms_len, pms, pms_len)) { goto err; } - /* Fix buf for TLS and beyond */ + /* Fill in the length prefix. */ if (s->version > SSL3_VERSION) { - s2n(n,q); - n+=2; + s2n(enc_pms_len, q); } - - s->session->master_key_length= - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key, - tmp_buf,sizeof tmp_buf); - OPENSSL_cleanse(tmp_buf,sizeof tmp_buf); } else if (alg_k & SSL_kEDH) { - DH *dh_srvr,*dh_clnt; + DH *dh_srvr, *dh_clnt; SESS_CERT *scert = s->session->sess_cert; + int dh_len; + size_t pub_len; if (scert == NULL) { @@ -2093,44 +2075,38 @@ int ssl3_send_client_key_exchange(SSL *s) goto err; } - /* use the 'p' output buffer for the DH key, but - * make sure to clear it out afterwards */ + pms_len = DH_size(dh_clnt); + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); + DH_free(dh_clnt); + goto err; + } - n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt); - if (n <= 0) + dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt); + if (dh_len <= 0) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB); DH_free(dh_clnt); goto err; } - - /* generate master key from the result */ - s->session->master_key_length= - s->method->ssl3_enc->generate_master_secret(s, - s->session->master_key,p,n); - /* clean up */ - memset(p,0,n); + pms_len = dh_len; /* send off the data */ - n=BN_num_bytes(dh_clnt->pub_key); - s2n(n,p); - BN_bn2bin(dh_clnt->pub_key,p); - n+=2; + pub_len = BN_num_bytes(dh_clnt->pub_key); + s2n(pub_len, p); + BN_bn2bin(dh_clnt->pub_key, p); + n += 2 + pub_len; DH_free(dh_clnt); - - /* perhaps clean things up a bit EAY EAY EAY EAY*/ } else if (alg_k & SSL_kEECDH) { const EC_GROUP *srvr_group = NULL; EC_KEY *tkey; - int field_size = 0; - unsigned char *pre_ms; - unsigned char *t; - unsigned int pre_ms_len; - unsigned int i; + int field_size = 0, ecdh_len; if (s->session->sess_cert == NULL) { @@ -2173,54 +2149,28 @@ int ssl3_send_client_key_exchange(SSL *s) goto err; } - /* use the 'p' output buffer for the ECDH key, but - * make sure to clear it out afterwards - */ - field_size = EC_GROUP_get_degree(srvr_group); if (field_size <= 0) { OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); goto err; } - n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL); - if (n <= 0) + + pms_len = (field_size + 7) / 8; + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) { - OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); goto err; } - /* ECDHE PSK ciphersuites from RFC 5489 */ - if ((alg_a & SSL_aPSK) && psk_len != 0) - { - pre_ms_len = 2+psk_len+2+n; - pre_ms = OPENSSL_malloc(pre_ms_len); - if (pre_ms == NULL) - { - OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); - goto err; - } - memset(pre_ms, 0, pre_ms_len); - t = pre_ms; - s2n(psk_len, t); - memcpy(t, psk, psk_len); - t += psk_len; - s2n(n, t); - memcpy(t, p, n); - s->session->master_key_length = s->method->ssl3_enc \ - -> generate_master_secret(s, - s->session->master_key, pre_ms, pre_ms_len); - OPENSSL_cleanse(pre_ms, pre_ms_len); - OPENSSL_free(pre_ms); - } - if (!(alg_a & SSL_aPSK)) + ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL); + if (ecdh_len <= 0) { - /* generate master key from the result */ - s->session->master_key_length = s->method->ssl3_enc \ - -> generate_master_secret(s, - s->session->master_key, p, n); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB); + goto err; } - memset(p, 0, n); /* clean up */ + pms_len = ecdh_len; /* First check the size of encoding and * allocate memory accordingly. @@ -2248,32 +2198,39 @@ int ssl3_send_client_key_exchange(SSL *s) POINT_CONVERSION_UNCOMPRESSED, encodedPoint, encoded_pt_len, bn_ctx); - n = 0; - if ((alg_a & SSL_aPSK) && psk_len != 0) - { - i = strlen(s->session->psk_identity); - s2n(i, p); - memcpy(p, s->session->psk_identity, i); - p += i; - n = i + 2; - } - *p = encoded_pt_len; /* length of encoded point */ /* Encoded point will be copied here */ p += 1; n += 1; /* copy the point */ - memcpy((unsigned char *)p, encodedPoint, encoded_pt_len); + memcpy(p, encodedPoint, encoded_pt_len); /* increment n to account for length field */ n += encoded_pt_len; /* Free allocated memory */ BN_CTX_free(bn_ctx); + bn_ctx = NULL; OPENSSL_free(encodedPoint); + encodedPoint = NULL; EC_KEY_free(clnt_ecdh); + clnt_ecdh = NULL; EVP_PKEY_free(srvr_pub_pkey); + srvr_pub_pkey = NULL; + } + else if (alg_k & SSL_kPSK) + { + /* For plain PSK, other_secret is a block of 0s with the same + * length as the pre-shared key. */ + pms_len = psk_len; + pms = OPENSSL_malloc(pms_len); + if (pms == NULL) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); + goto err; + } + memset(pms, 0, pms_len); } - else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK))) + else { ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); @@ -2281,19 +2238,71 @@ int ssl3_send_client_key_exchange(SSL *s) goto err; } + /* For a PSK cipher suite, other_secret is combined + * with the pre-shared key. */ + if ((alg_a & SSL_aPSK) && psk_len != 0) + { + CBB cbb, child; + uint8_t *new_pms; + size_t new_pms_len; + + if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len)) + { + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE); + goto err; + } + if (!CBB_add_u16_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, pms, pms_len) || + !CBB_add_u16_length_prefixed(&cbb, &child) || + !CBB_add_bytes(&child, psk, psk_len) || + !CBB_finish(&cbb, &new_pms, &new_pms_len)) + { + CBB_cleanup(&cbb); + OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR); + goto err; + } + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); + pms = new_pms; + pms_len = new_pms_len; + } + ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n); s->state=SSL3_ST_CW_KEY_EXCH_B; + + /* The message must be added to the finished hash before + * calculating the master secret. */ + s->method->ssl3_enc->add_to_finished_hash(s); + + s->session->master_key_length = + s->method->ssl3_enc->generate_master_secret(s, + s->session->master_key, + pms, pms_len); + if (s->session->master_key_length == 0) + { + goto err; + } + s->session->extended_master_secret = s->s3->tmp.extended_master_secret; + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); } /* SSL3_ST_CW_KEY_EXCH_B */ - return ssl_do_write(s); + /* The message has already been added to the finished hash. */ + return s->method->ssl3_enc->do_write(s, dont_add_to_finished_hash); + err: BN_CTX_free(bn_ctx); if (encodedPoint != NULL) OPENSSL_free(encodedPoint); if (clnt_ecdh != NULL) EC_KEY_free(clnt_ecdh); EVP_PKEY_free(srvr_pub_pkey); - return(-1); + if (pms) + { + OPENSSL_cleanse(pms, pms_len); + OPENSSL_free(pms); + } + return -1; } int ssl3_send_cert_verify(SSL *s) @@ -2332,7 +2341,7 @@ int ssl3_send_cert_verify(SSL *s) goto err; /* The handshake buffer is no longer necessary. */ - if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer)) goto err; /* Sign the digest. */ @@ -2583,7 +2592,7 @@ int ssl3_send_next_proto(SSL *s) s->init_off = 0; } - return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash); } @@ -2597,7 +2606,7 @@ int ssl3_send_channel_id(SSL *s) unsigned char *public_key = NULL, *derp, *der_sig = NULL; if (s->state != SSL3_ST_CW_CHANNEL_ID_A) - return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash); if (!s->tlsext_channel_id_private && s->ctx->channel_id_cb) { @@ -2700,7 +2709,7 @@ int ssl3_send_channel_id(SSL *s) s->init_num = 4 + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE; s->init_off = 0; - ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE); + ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash); err: EVP_MD_CTX_cleanup(&md_ctx); diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index b0ca507..fc94a94 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -510,7 +510,7 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len) } } -int ssl3_digest_cached_records(SSL *s) +int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer) { int i; long mask; @@ -542,9 +542,13 @@ int ssl3_digest_cached_records(SSL *s) s->s3->handshake_dgst[i]=NULL; } } - /* Free handshake_buffer BIO */ - BIO_free(s->s3->handshake_buffer); - s->s3->handshake_buffer = NULL; + + if (should_free_handshake_buffer == free_handshake_buffer) + { + /* Free handshake_buffer BIO */ + BIO_free(s->s3->handshake_buffer); + s->s3->handshake_buffer = NULL; + } return 1; } @@ -581,7 +585,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid, EVP_MD_CTX ctx,*d=NULL; if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) return 0; /* Search for digest of specified type in the handshake_dgst diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 215b3f6..3060684 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -942,7 +942,8 @@ SSL3_ENC_METHOD SSLv3_enc_data={ 0, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, - ssl3_handshake_write + ssl3_handshake_write, + ssl3_add_to_finished_hash, }; int ssl3_num_ciphers(void) @@ -975,9 +976,14 @@ void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len) s->init_off = 0; } -int ssl3_handshake_write(SSL *s) +int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash) { - return ssl3_do_write(s, SSL3_RT_HANDSHAKE); + return ssl3_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash); + } + +void ssl3_add_to_finished_hash(SSL *s) + { + ssl3_finish_mac(s, (uint8_t*) s->init_buf->data, s->init_num); } int ssl3_new(SSL *s) @@ -1385,9 +1391,9 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg) } case SSL_CTRL_GET_EC_POINT_FORMATS: { + const uint8_t **pformat = parg; if (!s->s3->tmp.peer_ecpointformatlist) return 0; - const uint8_t **pformat = parg; *pformat = s->s3->tmp.peer_ecpointformatlist; return (int)s->s3->tmp.peer_ecpointformatlist_length; } @@ -1850,10 +1856,6 @@ const SSL_CIPHER *ssl3_choose_cipher(SSL *s, STACK_OF(SSL_CIPHER) *clnt, ssl_set_cert_masks(cert,c); mask_k = cert->mask_k; mask_a = cert->mask_a; - -#ifdef KSSL_DEBUG -/* printf("ssl3_choose_cipher %d alg= %lx\n", i,c->algorithms);*/ -#endif /* KSSL_DEBUG */ alg_k=c->algorithm_mkey; alg_a=c->algorithm_auth; diff --git a/ssl/s3_pkt.c b/ssl/s3_pkt.c index 0df6a3c..d0e1856 100644 --- a/ssl/s3_pkt.c +++ b/ssl/s3_pkt.c @@ -1151,23 +1151,6 @@ start: OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_SSL_HANDSHAKE_FAILURE); return(-1); } - - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } } } /* we either finished a handshake or ignored the request, @@ -1237,10 +1220,6 @@ start: OPENSSL_PUT_ERROR(SSL, ssl3_read_bytes, SSL_R_NO_RENEGOTIATION); goto f_err; } -#ifdef SSL_AD_MISSING_SRP_USERNAME - else if (alert_descr == SSL_AD_MISSING_SRP_USERNAME) - return(0); -#endif } else if (alert_level == 2) /* fatal */ { @@ -1339,22 +1318,6 @@ start: return(-1); } - if (!(s->mode & SSL_MODE_AUTO_RETRY)) - { - if (s->s3->rbuf.left == 0) /* no read-ahead left? */ - { - BIO *bio; - /* In the case where we try to read application data, - * but we trigger an SSL handshake, we return -1 with - * the retry option set. Otherwise renegotiation may - * cause nasty problems in the blocking world */ - s->rwstate=SSL_READING; - bio=SSL_get_rbio(s); - BIO_clear_retry_flags(bio); - BIO_set_retry_read(bio); - return(-1); - } - } goto start; } diff --git a/ssl/s3_srvr.c b/ssl/s3_srvr.c index 149d9e7..29448db 100644 --- a/ssl/s3_srvr.c +++ b/ssl/s3_srvr.c @@ -444,7 +444,7 @@ int ssl3_accept(SSL *s) s->s3->tmp.cert_request=0; s->state=SSL3_ST_SW_SRVR_DONE_A; if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) return -1; } else @@ -993,7 +993,8 @@ int ssl3_get_client_hello(SSL *s) goto f_err; } - if (ssl_bytes_to_cipher_list(s, &cipher_suites, &ciphers) == NULL) + ciphers = ssl_bytes_to_cipher_list(s, &cipher_suites); + if (ciphers == NULL) { goto err; } @@ -1143,7 +1144,7 @@ int ssl3_get_client_hello(SSL *s) if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER)) { - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) goto f_err; } @@ -1608,6 +1609,8 @@ int ssl3_send_server_key_exchange(SSL *s) else if (md) { + size_t sig_len = EVP_PKEY_size(pkey); + /* send signature algorithm */ if (SSL_USE_SIGALGS(s)) { @@ -1620,24 +1623,19 @@ int ssl3_send_server_key_exchange(SSL *s) } p+=2; } -#ifdef SSL_DEBUG - fprintf(stderr, "Using hash %s\n", - EVP_MD_name(md)); -#endif - EVP_SignInit_ex(&md_ctx, md, NULL); - EVP_SignUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE); - EVP_SignUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE); - EVP_SignUpdate(&md_ctx,d,n); - if (!EVP_SignFinal(&md_ctx,&(p[2]), - (unsigned int *)&i,pkey)) + if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) || + !EVP_DigestSignUpdate(&md_ctx, d, n) || + !EVP_DigestSignFinal(&md_ctx, &p[2], &sig_len)) { OPENSSL_PUT_ERROR(SSL, ssl3_send_server_key_exchange, ERR_LIB_EVP); goto err; } - s2n(i,p); - n+=i+2; + s2n(sig_len, p); + n += sig_len + 2; if (SSL_USE_SIGALGS(s)) - n+= 2; + n += 2; } else { @@ -2140,9 +2138,13 @@ int ssl3_get_client_key_exchange(SSL *s) } EVP_PKEY_free(clnt_pub_pkey); + clnt_pub_pkey = NULL; EC_POINT_free(clnt_ecpoint); + clnt_ecpoint = NULL; EC_KEY_free(srvr_ecdh); + srvr_ecdh = NULL; BN_CTX_free(bn_ctx); + bn_ctx = NULL; EC_KEY_free(s->s3->tmp.ecdh); s->s3->tmp.ecdh = NULL; @@ -2202,6 +2204,9 @@ int ssl3_get_client_key_exchange(SSL *s) s->session->master_key_length = s->method->ssl3_enc ->generate_master_secret(s, s->session->master_key, premaster_secret, premaster_secret_len); + if (s->session->master_key_length == 0) + goto err; + s->session->extended_master_secret = s->s3->tmp.extended_master_secret; OPENSSL_cleanse(premaster_secret, premaster_secret_len); OPENSSL_free(premaster_secret); @@ -2242,7 +2247,7 @@ int ssl3_get_cert_verify(SSL *s) * client certificate. */ if (peer == NULL) { - if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer)) return -1; return 1; } @@ -2283,7 +2288,7 @@ int ssl3_get_cert_verify(SSL *s) /* The handshake buffer is no longer necessary, and we may hash the * current message.*/ - if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer)) goto err; ssl3_hash_current_message(s); @@ -2452,7 +2457,7 @@ int ssl3_get_client_certificate(SSL *s) goto f_err; } /* No client certificate so digest cached records */ - if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s)) + if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer)) { al=SSL_AD_INTERNAL_ERROR; goto f_err; @@ -2531,61 +2536,62 @@ int ssl3_send_new_session_ticket(SSL *s) { if (s->state == SSL3_ST_SW_SESSION_TICKET_A) { - unsigned char *p, *senc, *macstart; - const unsigned char *const_p; - int len, slen_full, slen; - SSL_SESSION *sess; + uint8_t *session; + size_t session_len; + uint8_t *p, *macstart; + int len; unsigned int hlen; EVP_CIPHER_CTX ctx; HMAC_CTX hctx; SSL_CTX *tctx = s->initial_ctx; unsigned char iv[EVP_MAX_IV_LENGTH]; unsigned char key_name[16]; + /* The maximum overhead of encrypting the session is 16 (key + * name) + IV + one block of encryption overhead + HMAC. */ + const size_t max_ticket_overhead = 16 + EVP_MAX_IV_LENGTH + + EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE; - /* get session encoding length */ - slen_full = i2d_SSL_SESSION(s->session, NULL); - /* Some length values are 16 bits, so forget it if session is - * too long - */ - if (slen_full > 0xFF00) - return -1; - senc = OPENSSL_malloc(slen_full); - if (!senc) - return -1; - p = senc; - i2d_SSL_SESSION(s->session, &p); - - /* create a fresh copy (not shared with other threads) to clean up */ - const_p = senc; - sess = d2i_SSL_SESSION(NULL, &const_p, slen_full); - if (sess == NULL) + /* Serialize the SSL_SESSION to be encoded into the ticket. */ + if (!SSL_SESSION_to_bytes_for_ticket(s->session, &session, + &session_len)) { - OPENSSL_free(senc); return -1; } - sess->session_id_length = 0; /* ID is irrelevant for the ticket */ - slen = i2d_SSL_SESSION(sess, NULL); - if (slen > slen_full) /* shouldn't ever happen */ + /* If the session is too long, emit a dummy value rather than + * abort the connection. */ + if (session_len > 0xFFFF - max_ticket_overhead) { - OPENSSL_free(senc); - return -1; + const char kTicketPlaceholder[] = "TICKET TOO LARGE"; + size_t placeholder_len = strlen(kTicketPlaceholder); + + OPENSSL_free(session); + + p = ssl_handshake_start(s); + /* Emit ticket_lifetime_hint. */ + l2n(0, p); + /* Emit ticket. */ + s2n(placeholder_len, p); + memcpy(p, kTicketPlaceholder, placeholder_len); + p += placeholder_len; + + len = p - ssl_handshake_start(s); + ssl_set_handshake_header(s, SSL3_MT_NEWSESSION_TICKET, len); + s->state = SSL3_ST_SW_SESSION_TICKET_B; + return ssl_do_write(s); } - p = senc; - i2d_SSL_SESSION(sess, &p); - SSL_SESSION_free(sess); /* Grow buffer if need be: the length calculation is as - * follows handshake_header_length + + * follows: handshake_header_length + * 4 (ticket lifetime hint) + 2 (ticket length) + - * 16 (key name) + max_iv_len (iv length) + - * session_length + max_enc_block_size (max encrypted session - * length) + max_md_size (HMAC). - */ + * max_ticket_overhead + * session_length */ if (!BUF_MEM_grow(s->init_buf, - SSL_HM_HEADER_LENGTH(s) + 22 + EVP_MAX_IV_LENGTH + - EVP_MAX_BLOCK_LENGTH + EVP_MAX_MD_SIZE + slen)) + SSL_HM_HEADER_LENGTH(s) + 6 + + max_ticket_overhead + session_len)) + { + OPENSSL_free(session); return -1; + } p = ssl_handshake_start(s); EVP_CIPHER_CTX_init(&ctx); HMAC_CTX_init(&hctx); @@ -2598,7 +2604,7 @@ int ssl3_send_new_session_ticket(SSL *s) if (tctx->tlsext_ticket_key_cb(s, key_name, iv, &ctx, &hctx, 1) < 0) { - OPENSSL_free(senc); + OPENSSL_free(session); return -1; } } @@ -2628,7 +2634,7 @@ int ssl3_send_new_session_ticket(SSL *s) memcpy(p, iv, EVP_CIPHER_CTX_iv_length(&ctx)); p += EVP_CIPHER_CTX_iv_length(&ctx); /* Encrypt session data */ - EVP_EncryptUpdate(&ctx, p, &len, senc, slen); + EVP_EncryptUpdate(&ctx, p, &len, session, session_len); p += len; EVP_EncryptFinal_ex(&ctx, p, &len); p += len; @@ -2647,7 +2653,7 @@ int ssl3_send_new_session_ticket(SSL *s) p = ssl_handshake_start(s) + 4; s2n(len - 6, p); s->state=SSL3_ST_SW_SESSION_TICKET_B; - OPENSSL_free(senc); + OPENSSL_free(session); } /* SSL3_ST_SW_SESSION_TICKET_B */ diff --git a/ssl/ssl_asn1.c b/ssl/ssl_asn1.c index 5e86017..ef7ebdc 100644 --- a/ssl/ssl_asn1.c +++ b/ssl/ssl_asn1.c @@ -80,538 +80,530 @@ * OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS OR * OTHERWISE. */ -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> +#include <limits.h> +#include <string.h> -#include <openssl/asn1.h> -#include <openssl/asn1_mac.h> +#include <openssl/bytestring.h> #include <openssl/err.h> -#include <openssl/mem.h> -#include <openssl/obj.h> #include <openssl/x509.h> #include "ssl_locl.h" -OPENSSL_DECLARE_ERROR_REASON(SSL, CIPHER_CODE_WRONG_LENGTH); -OPENSSL_DECLARE_ERROR_REASON(SSL, UNKNOWN_SSL_VERSION); -OPENSSL_DECLARE_ERROR_REASON(SSL, BAD_LENGTH); -OPENSSL_DECLARE_ERROR_FUNCTION(SSL, D2I_SSL_SESSION); - - -typedef struct ssl_session_asn1_st - { - ASN1_INTEGER version; - ASN1_INTEGER ssl_version; - ASN1_OCTET_STRING cipher; - ASN1_OCTET_STRING comp_id; - ASN1_OCTET_STRING master_key; - ASN1_OCTET_STRING session_id; - ASN1_OCTET_STRING session_id_context; - ASN1_INTEGER time; - ASN1_INTEGER timeout; - ASN1_INTEGER verify_result; - ASN1_OCTET_STRING tlsext_hostname; - ASN1_INTEGER tlsext_tick_lifetime; - ASN1_OCTET_STRING tlsext_tick; - ASN1_OCTET_STRING psk_identity_hint; - ASN1_OCTET_STRING psk_identity; - ASN1_OCTET_STRING peer_sha256; - ASN1_OCTET_STRING original_handshake_hash; - ASN1_OCTET_STRING tlsext_signed_cert_timestamp_list; - ASN1_OCTET_STRING ocsp_response; - } SSL_SESSION_ASN1; - -int i2d_SSL_SESSION(SSL_SESSION *in, unsigned char **pp) - { -#define LSIZE2 (sizeof(long)*2) - int v1=0,v2=0,v3=0,v4=0,v5=0,v7=0,v8=0,v13=0,v14=0,v15=0,v16=0; - unsigned char buf[4],ibuf1[LSIZE2],ibuf2[LSIZE2]; - unsigned char ibuf3[LSIZE2],ibuf4[LSIZE2],ibuf5[LSIZE2]; - int v6=0,v9=0,v10=0; - unsigned char ibuf6[LSIZE2]; - long l; - SSL_SESSION_ASN1 a; - M_ASN1_I2D_vars(in); - - if ((in == NULL) || ((in->cipher == NULL) && (in->cipher_id == 0))) - return(0); - - /* Note that I cheat in the following 2 assignments. I know - * that if the ASN1_INTEGER passed to ASN1_INTEGER_set - * is > sizeof(long)+1, the buffer will not be re-OPENSSL_malloc()ed. - * This is a bit evil but makes things simple, no dynamic allocation - * to clean up :-) */ - a.version.length=LSIZE2; - a.version.type=V_ASN1_INTEGER; - a.version.data=ibuf1; - ASN1_INTEGER_set(&(a.version),SSL_SESSION_ASN1_VERSION); - - a.ssl_version.length=LSIZE2; - a.ssl_version.type=V_ASN1_INTEGER; - a.ssl_version.data=ibuf2; - ASN1_INTEGER_set(&(a.ssl_version),in->ssl_version); - - a.cipher.type=V_ASN1_OCTET_STRING; - a.cipher.data=buf; - - if (in->cipher == NULL) - l=in->cipher_id; - else - l=in->cipher->id; - if (in->ssl_version == SSL2_VERSION) - { - a.cipher.length=3; - buf[0]=((unsigned char)(l>>16L))&0xff; - buf[1]=((unsigned char)(l>> 8L))&0xff; - buf[2]=((unsigned char)(l ))&0xff; - } - else - { - a.cipher.length=2; - buf[0]=((unsigned char)(l>>8L))&0xff; - buf[1]=((unsigned char)(l ))&0xff; - } - - - a.master_key.length=in->master_key_length; - a.master_key.type=V_ASN1_OCTET_STRING; - a.master_key.data=in->master_key; - - a.session_id.length=in->session_id_length; - a.session_id.type=V_ASN1_OCTET_STRING; - a.session_id.data=in->session_id; - - a.session_id_context.length=in->sid_ctx_length; - a.session_id_context.type=V_ASN1_OCTET_STRING; - a.session_id_context.data=in->sid_ctx; - - if (in->time != 0L) - { - a.time.length=LSIZE2; - a.time.type=V_ASN1_INTEGER; - a.time.data=ibuf3; - ASN1_INTEGER_set(&(a.time),in->time); - } - - if (in->timeout != 0L) - { - a.timeout.length=LSIZE2; - a.timeout.type=V_ASN1_INTEGER; - a.timeout.data=ibuf4; - ASN1_INTEGER_set(&(a.timeout),in->timeout); - } - - if (in->verify_result != X509_V_OK) - { - a.verify_result.length=LSIZE2; - a.verify_result.type=V_ASN1_INTEGER; - a.verify_result.data=ibuf5; - ASN1_INTEGER_set(&a.verify_result,in->verify_result); - } - - if (in->tlsext_hostname) - { - a.tlsext_hostname.length=strlen(in->tlsext_hostname); - a.tlsext_hostname.type=V_ASN1_OCTET_STRING; - a.tlsext_hostname.data=(unsigned char *)in->tlsext_hostname; - } - if (in->tlsext_tick) - { - a.tlsext_tick.length= in->tlsext_ticklen; - a.tlsext_tick.type=V_ASN1_OCTET_STRING; - a.tlsext_tick.data=(unsigned char *)in->tlsext_tick; - } - if (in->tlsext_tick_lifetime_hint > 0) - { - a.tlsext_tick_lifetime.length=LSIZE2; - a.tlsext_tick_lifetime.type=V_ASN1_INTEGER; - a.tlsext_tick_lifetime.data=ibuf6; - ASN1_INTEGER_set(&a.tlsext_tick_lifetime,in->tlsext_tick_lifetime_hint); - } - if (in->psk_identity_hint) - { - a.psk_identity_hint.length=strlen(in->psk_identity_hint); - a.psk_identity_hint.type=V_ASN1_OCTET_STRING; - a.psk_identity_hint.data=(unsigned char *)(in->psk_identity_hint); - } - if (in->psk_identity) - { - a.psk_identity.length=strlen(in->psk_identity); - a.psk_identity.type=V_ASN1_OCTET_STRING; - a.psk_identity.data=(unsigned char *)(in->psk_identity); - } - - if (in->peer_sha256_valid) - { - a.peer_sha256.length = sizeof(in->peer_sha256); - a.peer_sha256.type = V_ASN1_OCTET_STRING; - a.peer_sha256.data = in->peer_sha256; - } - - if (in->original_handshake_hash_len > 0) - { - a.original_handshake_hash.length = in->original_handshake_hash_len; - a.original_handshake_hash.type = V_ASN1_OCTET_STRING; - a.original_handshake_hash.data = in->original_handshake_hash; - } - - if (in->tlsext_signed_cert_timestamp_list_length > 0) - { - a.tlsext_signed_cert_timestamp_list.length = - in->tlsext_signed_cert_timestamp_list_length; - a.tlsext_signed_cert_timestamp_list.type = V_ASN1_OCTET_STRING; - a.tlsext_signed_cert_timestamp_list.data = - in->tlsext_signed_cert_timestamp_list; - } - - if (in->ocsp_response_length > 0) - { - a.ocsp_response.length = in->ocsp_response_length; - a.ocsp_response.type = V_ASN1_OCTET_STRING; - a.ocsp_response.data = in->ocsp_response; - } - - M_ASN1_I2D_len(&(a.version), i2d_ASN1_INTEGER); - M_ASN1_I2D_len(&(a.ssl_version), i2d_ASN1_INTEGER); - M_ASN1_I2D_len(&(a.cipher), i2d_ASN1_OCTET_STRING); - M_ASN1_I2D_len(&(a.session_id), i2d_ASN1_OCTET_STRING); - M_ASN1_I2D_len(&(a.master_key), i2d_ASN1_OCTET_STRING); - if (in->time != 0L) - M_ASN1_I2D_len_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1); - if (in->timeout != 0L) - M_ASN1_I2D_len_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2); - if (in->peer != NULL && in->peer_sha256_valid == 0) - M_ASN1_I2D_len_EXP_opt(in->peer,i2d_X509,3,v3); - M_ASN1_I2D_len_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4,v4); - if (in->verify_result != X509_V_OK) - M_ASN1_I2D_len_EXP_opt(&(a.verify_result),i2d_ASN1_INTEGER,5,v5); - - if (in->tlsext_tick_lifetime_hint > 0) - M_ASN1_I2D_len_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9); - if (in->tlsext_tick) - M_ASN1_I2D_len_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10); - if (in->tlsext_hostname) - M_ASN1_I2D_len_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6); - if (in->psk_identity_hint) - M_ASN1_I2D_len_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7); - if (in->psk_identity) - M_ASN1_I2D_len_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8); - if (in->peer_sha256_valid) - M_ASN1_I2D_len_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13); - if (in->original_handshake_hash_len > 0) - M_ASN1_I2D_len_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14); - if (in->tlsext_signed_cert_timestamp_list_length > 0) - M_ASN1_I2D_len_EXP_opt(&(a.tlsext_signed_cert_timestamp_list), - i2d_ASN1_OCTET_STRING, 15, v15); - if (in->ocsp_response_length > 0) - M_ASN1_I2D_len_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16); - - M_ASN1_I2D_seq_total(); - - M_ASN1_I2D_put(&(a.version), i2d_ASN1_INTEGER); - M_ASN1_I2D_put(&(a.ssl_version), i2d_ASN1_INTEGER); - M_ASN1_I2D_put(&(a.cipher), i2d_ASN1_OCTET_STRING); - M_ASN1_I2D_put(&(a.session_id), i2d_ASN1_OCTET_STRING); - M_ASN1_I2D_put(&(a.master_key), i2d_ASN1_OCTET_STRING); - if (in->time != 0L) - M_ASN1_I2D_put_EXP_opt(&(a.time),i2d_ASN1_INTEGER,1,v1); - if (in->timeout != 0L) - M_ASN1_I2D_put_EXP_opt(&(a.timeout),i2d_ASN1_INTEGER,2,v2); - if (in->peer != NULL && in->peer_sha256_valid == 0) - M_ASN1_I2D_put_EXP_opt(in->peer,i2d_X509,3,v3); - M_ASN1_I2D_put_EXP_opt(&a.session_id_context,i2d_ASN1_OCTET_STRING,4, - v4); - if (in->verify_result != X509_V_OK) - M_ASN1_I2D_put_EXP_opt(&a.verify_result,i2d_ASN1_INTEGER,5,v5); - if (in->tlsext_hostname) - M_ASN1_I2D_put_EXP_opt(&(a.tlsext_hostname), i2d_ASN1_OCTET_STRING,6,v6); - if (in->psk_identity_hint) - M_ASN1_I2D_put_EXP_opt(&(a.psk_identity_hint), i2d_ASN1_OCTET_STRING,7,v7); - if (in->psk_identity) - M_ASN1_I2D_put_EXP_opt(&(a.psk_identity), i2d_ASN1_OCTET_STRING,8,v8); - if (in->tlsext_tick_lifetime_hint > 0) - M_ASN1_I2D_put_EXP_opt(&a.tlsext_tick_lifetime, i2d_ASN1_INTEGER,9,v9); - if (in->tlsext_tick) - M_ASN1_I2D_put_EXP_opt(&(a.tlsext_tick), i2d_ASN1_OCTET_STRING,10,v10); - if (in->peer_sha256_valid) - M_ASN1_I2D_put_EXP_opt(&(a.peer_sha256),i2d_ASN1_OCTET_STRING,13,v13); - if (in->original_handshake_hash_len > 0) - M_ASN1_I2D_put_EXP_opt(&(a.original_handshake_hash),i2d_ASN1_OCTET_STRING,14,v14); - if (in->tlsext_signed_cert_timestamp_list_length > 0) - M_ASN1_I2D_put_EXP_opt(&(a.tlsext_signed_cert_timestamp_list), - i2d_ASN1_OCTET_STRING, 15, v15); - if (in->ocsp_response > 0) - M_ASN1_I2D_put_EXP_opt(&(a.ocsp_response), i2d_ASN1_OCTET_STRING, 16, v16); - - M_ASN1_I2D_finish(); - } - -SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp, - long length) - { - int ssl_version=0,i; - long id; - ASN1_INTEGER ai,*aip; - ASN1_OCTET_STRING os,*osp; - M_ASN1_D2I_vars(a,SSL_SESSION *,SSL_SESSION_new); - - aip= &ai; - osp= &os; - - M_ASN1_D2I_Init(); - M_ASN1_D2I_start_sequence(); - - ai.data=NULL; ai.length=0; - M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER); - if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; } - - /* we don't care about the version right now :-) */ - M_ASN1_D2I_get_x(ASN1_INTEGER,aip,d2i_ASN1_INTEGER); - ssl_version=(int)ASN1_INTEGER_get(aip); - ret->ssl_version=ssl_version; - if (ai.data != NULL) { OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; } - - os.data=NULL; os.length=0; - M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING); - if (ssl_version == SSL2_VERSION) - { - if (os.length != 3) - { - c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH; - c.line=__LINE__; - goto err; - } - id=0x02000000L| - ((unsigned long)os.data[0]<<16L)| - ((unsigned long)os.data[1]<< 8L)| - (unsigned long)os.data[2]; - } - else if ((ssl_version>>8) >= SSL3_VERSION_MAJOR) - { - if (os.length != 2) - { - c.error=SSL_R_CIPHER_CODE_WRONG_LENGTH; - c.line=__LINE__; - goto err; - } - id=0x03000000L| - ((unsigned long)os.data[0]<<8L)| - (unsigned long)os.data[1]; - } - else - { - c.error=SSL_R_UNKNOWN_SSL_VERSION; - c.line=__LINE__; - goto err; - } - - ret->cipher_id=id; - ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff); - if (ret->cipher == NULL) - { - c.error=SSL_R_UNSUPPORTED_CIPHER; - c.line = __LINE__; - goto err; - } - - M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING); - if ((ssl_version>>8) >= SSL3_VERSION_MAJOR) - i=SSL3_MAX_SSL_SESSION_ID_LENGTH; - else /* if (ssl_version>>8 == SSL2_VERSION_MAJOR) */ - i=SSL2_MAX_SSL_SESSION_ID_LENGTH; - - if (os.length > i) - os.length = i; - if (os.length > (int)sizeof(ret->session_id)) /* can't happen */ - os.length = sizeof(ret->session_id); - - ret->session_id_length=os.length; - assert(os.length <= (int)sizeof(ret->session_id)); - memcpy(ret->session_id,os.data,os.length); - - M_ASN1_D2I_get_x(ASN1_OCTET_STRING,osp,d2i_ASN1_OCTET_STRING); - if (os.length > SSL_MAX_MASTER_KEY_LENGTH) - ret->master_key_length=SSL_MAX_MASTER_KEY_LENGTH; - else - ret->master_key_length=os.length; - memcpy(ret->master_key,os.data,ret->master_key_length); - - os.length=0; - - /* [0] is the tag for key_arg, a no longer used remnant of - * SSLv2. */ - M_ASN1_D2I_get_IMP_opt(osp,d2i_ASN1_OCTET_STRING,0,V_ASN1_OCTET_STRING); - if (os.data != NULL) OPENSSL_free(os.data); - - ai.length=0; - M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,1); - if (ai.data != NULL) - { - ret->time=ASN1_INTEGER_get(aip); - OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; - } - else - ret->time=(unsigned long)time(NULL); - - ai.length=0; - M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,2); - if (ai.data != NULL) - { - ret->timeout=ASN1_INTEGER_get(aip); - OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; - } - else - ret->timeout=3; - - if (ret->peer != NULL) - { - X509_free(ret->peer); - ret->peer=NULL; - } - M_ASN1_D2I_get_EXP_opt(ret->peer,d2i_X509,3); - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,4); - - if(os.data != NULL) - { - if (os.length > SSL_MAX_SID_CTX_LENGTH) - { - c.error=SSL_R_BAD_LENGTH; - c.line=__LINE__; - goto err; - } - else - { - ret->sid_ctx_length=os.length; - memcpy(ret->sid_ctx,os.data,os.length); - } - OPENSSL_free(os.data); os.data=NULL; os.length=0; - } - else - ret->sid_ctx_length=0; - - ai.length=0; - M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,5); - if (ai.data != NULL) - { - ret->verify_result=ASN1_INTEGER_get(aip); - OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; - } - else - ret->verify_result=X509_V_OK; - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,6); - if (os.data) - { - ret->tlsext_hostname = BUF_strndup((char *)os.data, os.length); - OPENSSL_free(os.data); - os.data = NULL; - os.length = 0; - } - else - ret->tlsext_hostname=NULL; - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,7); - if (os.data) - { - ret->psk_identity_hint = BUF_strndup((char *)os.data, os.length); - OPENSSL_free(os.data); - os.data = NULL; - os.length = 0; - } - else - ret->psk_identity_hint=NULL; - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,8); - if (os.data) - { - ret->psk_identity = BUF_strndup((char *)os.data, os.length); - OPENSSL_free(os.data); - os.data = NULL; - os.length = 0; - } - else - ret->psk_identity=NULL; - - ai.length=0; - M_ASN1_D2I_get_EXP_opt(aip,d2i_ASN1_INTEGER,9); - if (ai.data != NULL) - { - ret->tlsext_tick_lifetime_hint=ASN1_INTEGER_get(aip); - OPENSSL_free(ai.data); ai.data=NULL; ai.length=0; - } - else if (ret->tlsext_ticklen && ret->session_id_length) - ret->tlsext_tick_lifetime_hint = -1; - else - ret->tlsext_tick_lifetime_hint=0; - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,10); - if (os.data) - { - ret->tlsext_tick = os.data; - ret->tlsext_ticklen = os.length; - os.data = NULL; - os.length = 0; - } - else - ret->tlsext_tick=NULL; - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,13); - if (os.data && os.length == sizeof(ret->peer_sha256)) - { - memcpy(ret->peer_sha256, os.data, sizeof(ret->peer_sha256)); - ret->peer_sha256_valid = 1; - OPENSSL_free(os.data); - os.data = NULL; - } - - os.length=0; - os.data=NULL; - M_ASN1_D2I_get_EXP_opt(osp,d2i_ASN1_OCTET_STRING,14); - if (os.data && os.length < (int)sizeof(ret->original_handshake_hash)) - { - memcpy(ret->original_handshake_hash, os.data, os.length); - ret->original_handshake_hash_len = os.length; - OPENSSL_free(os.data); - os.data = NULL; - } - - os.length = 0; - os.data = NULL; - M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 15); - if (os.data) - { - if (ret->tlsext_signed_cert_timestamp_list) - OPENSSL_free(ret->tlsext_signed_cert_timestamp_list); - ret->tlsext_signed_cert_timestamp_list = os.data; - ret->tlsext_signed_cert_timestamp_list_length = os.length; - os.data = NULL; - } - - os.length = 0; - os.data = NULL; - M_ASN1_D2I_get_EXP_opt(osp, d2i_ASN1_OCTET_STRING, 16); - if (os.data) - { - if (ret->ocsp_response) - OPENSSL_free(ret->ocsp_response); - ret->ocsp_response = os.data; - ret->ocsp_response_length = os.length; - os.data = NULL; - } - - - M_ASN1_D2I_Finish(a,SSL_SESSION_free,SSL_F_D2I_SSL_SESSION); - } + +/* An SSL_SESSION is serialized as the following ASN.1 structure: + * + * SSLSession ::= SEQUENCE { + * version INTEGER (1), -- ignored + * sslVersion INTEGER, -- protocol version number + * cipher OCTET STRING, -- two bytes long + * sessionID OCTET STRING, + * masterKey OCTET STRING, + * time [1] INTEGER OPTIONAL, -- seconds since UNIX epoch + * timeout [2] INTEGER OPTIONAL, -- in seconds + * peer [3] Certificate OPTIONAL, + * sessionIDContext [4] OCTET STRING OPTIONAL, + * verifyResult [5] INTEGER OPTIONAL, -- one of X509_V_* codes + * hostName [6] OCTET STRING OPTIONAL, + * -- from server_name extension + * pskIdentityHint [7] OCTET STRING OPTIONAL, + * pskIdentity [8] OCTET STRING OPTIONAL, + * ticketLifetimeHint [9] INTEGER OPTIONAL, -- client-only + * ticket [10] OCTET STRING OPTIONAL, -- client-only + * peerSHA256 [13] OCTET STRING OPTIONAL, + * originalHandshakeHash [14] OCTET STRING OPTIONAL, + * signedCertTimestampList [15] OCTET STRING OPTIONAL, + * -- contents of SCT extension + * ocspResponse [16] OCTET STRING OPTIONAL, + * -- stapled OCSP response from the server + * extendedMasterSecret [17] BOOLEAN OPTIONAL, + * } + * + * Note: When the relevant features were #ifdef'd out, support for + * parsing compressionMethod [11] and srpUsername [12] was lost. */ + +static const int kTimeTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 1; +static const int kTimeoutTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 2; +static const int kPeerTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 3; + static const int kSessionIDContextTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 4; +static const int kVerifyResultTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 5; +static const int kHostNameTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 6; +static const int kPSKIdentityHintTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 7; +static const int kPSKIdentityTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 8; +static const int kTicketLifetimeHintTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 9; +static const int kTicketTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 10; +static const int kPeerSHA256Tag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 13; +static const int kOriginalHandshakeHashTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 14; +static const int kSignedCertTimestampListTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15; +static const int kOCSPResponseTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16; +static const int kExtendedMasterSecretTag = + CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17; + +static int SSL_SESSION_to_bytes_full(SSL_SESSION *in, uint8_t **out_data, + size_t *out_len, int for_ticket) { + CBB cbb, session, child, child2; + uint16_t cipher_id; + + if (in == NULL || (in->cipher == NULL && in->cipher_id == 0)) { + return 0; + } + + if (!CBB_init(&cbb, 0)) { + return 0; + } + + if (in->cipher == NULL) { + cipher_id = in->cipher_id & 0xffff; + } else { + cipher_id = in->cipher->id & 0xffff; + } + + if (!CBB_add_asn1(&cbb, &session, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1_uint64(&session, SSL_SESSION_ASN1_VERSION) || + !CBB_add_asn1_uint64(&session, in->ssl_version) || + !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || + !CBB_add_u16(&child, cipher_id) || + !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || + /* The session ID is irrelevant for a session ticket. */ + !CBB_add_bytes(&child, in->session_id, + for_ticket ? 0 : in->session_id_length) || + !CBB_add_asn1(&session, &child, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child, in->master_key, in->master_key_length)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->time != 0) { + if (!CBB_add_asn1(&session, &child, kTimeTag) || + !CBB_add_asn1_uint64(&child, in->time)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->timeout != 0) { + if (!CBB_add_asn1(&session, &child, kTimeoutTag) || + !CBB_add_asn1_uint64(&child, in->timeout)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + /* The peer certificate is only serialized if the SHA-256 isn't + * serialized instead. */ + if (in->peer && !in->peer_sha256_valid) { + uint8_t *buf; + int len = i2d_X509(in->peer, NULL); + if (len < 0) { + goto err; + } + if (!CBB_add_asn1(&session, &child, kPeerTag) || + !CBB_add_space(&child, &buf, len)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + if (buf != NULL && i2d_X509(in->peer, &buf) < 0) { + goto err; + } + } + + /* Although it is OPTIONAL and usually empty, OpenSSL has + * historically always encoded the sid_ctx. */ + if (!CBB_add_asn1(&session, &child, kSessionIDContextTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->sid_ctx, in->sid_ctx_length)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (in->verify_result != X509_V_OK) { + if (!CBB_add_asn1(&session, &child, kVerifyResultTag) || + !CBB_add_asn1_uint64(&child, in->verify_result)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->tlsext_hostname) { + if (!CBB_add_asn1(&session, &child, kHostNameTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, (const uint8_t *)in->tlsext_hostname, + strlen(in->tlsext_hostname))) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->psk_identity_hint) { + if (!CBB_add_asn1(&session, &child, kPSKIdentityHintTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity_hint, + strlen(in->psk_identity_hint))) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->psk_identity) { + if (!CBB_add_asn1(&session, &child, kPSKIdentityTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, (const uint8_t *)in->psk_identity, + strlen(in->psk_identity))) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->tlsext_tick_lifetime_hint > 0) { + if (!CBB_add_asn1(&session, &child, kTicketLifetimeHintTag) || + !CBB_add_asn1_uint64(&child, in->tlsext_tick_lifetime_hint)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->tlsext_tick) { + if (!CBB_add_asn1(&session, &child, kTicketTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->tlsext_tick, in->tlsext_ticklen)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->peer_sha256_valid) { + if (!CBB_add_asn1(&session, &child, kPeerSHA256Tag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->peer_sha256, sizeof(in->peer_sha256))) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->original_handshake_hash_len > 0) { + if (!CBB_add_asn1(&session, &child, kOriginalHandshakeHashTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->original_handshake_hash, + in->original_handshake_hash_len)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->tlsext_signed_cert_timestamp_list_length > 0) { + if (!CBB_add_asn1(&session, &child, kSignedCertTimestampListTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->tlsext_signed_cert_timestamp_list, + in->tlsext_signed_cert_timestamp_list_length)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->ocsp_response_length > 0) { + if (!CBB_add_asn1(&session, &child, kOCSPResponseTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) || + !CBB_add_bytes(&child2, in->ocsp_response, in->ocsp_response_length)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (in->extended_master_secret) { + if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) || + !CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) || + !CBB_add_u8(&child2, 0xff)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + } + + if (!CBB_finish(&cbb, out_data, out_len)) { + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE); + goto err; + } + return 1; + + err: + CBB_cleanup(&cbb); + return 0; +} + +int SSL_SESSION_to_bytes(SSL_SESSION *in, uint8_t **out_data, size_t *out_len) { + return SSL_SESSION_to_bytes_full(in, out_data, out_len, 0); +} + +int SSL_SESSION_to_bytes_for_ticket(SSL_SESSION *in, uint8_t **out_data, + size_t *out_len) { + return SSL_SESSION_to_bytes_full(in, out_data, out_len, 1); +} + +int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) { + uint8_t *out; + size_t len; + + if (!SSL_SESSION_to_bytes(in, &out, &len)) { + return -1; + } + + if (len > INT_MAX) { + OPENSSL_free(out); + OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_OVERFLOW); + return -1; + } + + if (pp) { + memcpy(*pp, out, len); + *pp += len; + } + OPENSSL_free(out); + + return len; +} + +/* d2i_SSL_SESSION_get_string gets an optional ASN.1 OCTET STRING + * explicitly tagged with |tag| from |cbs| and saves it in |*out|. On + * entry, if |*out| is not NULL, it frees the existing contents. If + * the element was not found, it sets |*out| to NULL. It returns one + * on success, whether or not the element was found, and zero on + * decode error. */ +static int d2i_SSL_SESSION_get_string(CBS *cbs, char **out, unsigned tag) { + CBS value; + int present; + if (!CBS_get_optional_asn1_octet_string(cbs, &value, &present, tag)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + return 0; + } + if (present) { + if (CBS_contains_zero_byte(&value)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + return 0; + } + if (!CBS_strdup(&value, out)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE); + return 0; + } + } else if (*out) { + OPENSSL_free(*out); + *out = NULL; + } + return 1; +} + +/* d2i_SSL_SESSION_get_string gets an optional ASN.1 OCTET STRING + * explicitly tagged with |tag| from |cbs| and stows it in |*out_ptr| + * and |*out_len|. If |*out_ptr| is not NULL, it frees the existing + * contents. On entry, if the element was not found, it sets + * |*out_ptr| to NULL. It returns one on success, whether or not the + * element was found, and zero on decode error. */ +static int d2i_SSL_SESSION_get_octet_string(CBS *cbs, uint8_t **out_ptr, + size_t *out_len, unsigned tag) { + CBS value; + if (!CBS_get_optional_asn1_octet_string(cbs, &value, NULL, tag)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + return 0; + } + if (!CBS_stow(&value, out_ptr, out_len)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; +} + +SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) { + SSL_SESSION *ret = NULL; + CBS cbs, session, cipher, session_id, master_key; + CBS peer, sid_ctx, peer_sha256, original_handshake_hash; + int has_peer, has_peer_sha256, extended_master_secret; + uint64_t version, ssl_version; + uint64_t session_time, timeout, verify_result, ticket_lifetime_hint; + + if (a && *a) { + ret = *a; + } else { + ret = SSL_SESSION_new(); + if (ret == NULL) { + goto err; + } + } + + CBS_init(&cbs, *pp, length); + if (!CBS_get_asn1(&cbs, &session, CBS_ASN1_SEQUENCE) || + !CBS_get_asn1_uint64(&session, &version) || + !CBS_get_asn1_uint64(&session, &ssl_version) || + !CBS_get_asn1(&session, &cipher, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&session, &session_id, CBS_ASN1_OCTETSTRING) || + !CBS_get_asn1(&session, &master_key, CBS_ASN1_OCTETSTRING) || + !CBS_get_optional_asn1_uint64(&session, &session_time, kTimeTag, + time(NULL)) || + !CBS_get_optional_asn1_uint64(&session, &timeout, kTimeoutTag, 3) || + !CBS_get_optional_asn1(&session, &peer, &has_peer, kPeerTag) || + !CBS_get_optional_asn1_octet_string(&session, &sid_ctx, NULL, + kSessionIDContextTag) || + !CBS_get_optional_asn1_uint64(&session, &verify_result, kVerifyResultTag, + X509_V_OK)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (!d2i_SSL_SESSION_get_string(&session, &ret->tlsext_hostname, + kHostNameTag) || + !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity_hint, + kPSKIdentityHintTag) || + !d2i_SSL_SESSION_get_string(&session, &ret->psk_identity, + kPSKIdentityTag)) { + goto err; + } + if (!CBS_get_optional_asn1_uint64(&session, &ticket_lifetime_hint, + kTicketLifetimeHintTag, 0)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (!d2i_SSL_SESSION_get_octet_string(&session, &ret->tlsext_tick, + &ret->tlsext_ticklen, kTicketTag)) { + goto err; + } + if (!CBS_get_optional_asn1_octet_string(&session, &peer_sha256, + &has_peer_sha256, kPeerSHA256Tag) || + !CBS_get_optional_asn1_octet_string(&session, &original_handshake_hash, + NULL, kOriginalHandshakeHashTag)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + if (!d2i_SSL_SESSION_get_octet_string( + &session, &ret->tlsext_signed_cert_timestamp_list, + &ret->tlsext_signed_cert_timestamp_list_length, + kSignedCertTimestampListTag) || + !d2i_SSL_SESSION_get_octet_string( + &session, &ret->ocsp_response, &ret->ocsp_response_length, + kOCSPResponseTag)) { + goto err; + } + if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret, + kExtendedMasterSecretTag, + 0 /* default to false */)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + ret->extended_master_secret = extended_master_secret; + + /* Ignore |version|. The structure version number is ignored. */ + + /* Only support SSLv3/TLS and DTLS. */ + if ((ssl_version >> 8) != SSL3_VERSION_MAJOR && + (ssl_version >> 8) != (DTLS1_VERSION >> 8)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNKNOWN_SSL_VERSION); + goto err; + } + ret->ssl_version = ssl_version; + + if (CBS_len(&cipher) != 2) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_CIPHER_CODE_WRONG_LENGTH); + goto err; + } + ret->cipher_id = + 0x03000000L | (CBS_data(&cipher)[0] << 8L) | CBS_data(&cipher)[1]; + ret->cipher = ssl3_get_cipher_by_value(ret->cipher_id & 0xffff); + if (ret->cipher == NULL) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_UNSUPPORTED_CIPHER); + goto err; + } + + if (CBS_len(&session_id) > SSL3_MAX_SSL_SESSION_ID_LENGTH) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->session_id, CBS_data(&session_id), CBS_len(&session_id)); + ret->session_id_length = CBS_len(&session_id); + + if (CBS_len(&master_key) > SSL_MAX_MASTER_KEY_LENGTH) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->master_key, CBS_data(&master_key), CBS_len(&master_key)); + ret->master_key_length = CBS_len(&master_key); + + if (session_time > LONG_MAX || + timeout > LONG_MAX) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + ret->time = session_time; + ret->timeout = timeout; + + if (ret->peer != NULL) { + X509_free(ret->peer); + ret->peer = NULL; + } + if (has_peer) { + const uint8_t *ptr; + ptr = CBS_data(&peer); + ret->peer = d2i_X509(NULL, &ptr, CBS_len(&peer)); + if (ret->peer == NULL) { + goto err; + } + if (ptr != CBS_data(&peer) + CBS_len(&peer)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + } + + if (CBS_len(&sid_ctx) > sizeof(ret->sid_ctx)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->sid_ctx, CBS_data(&sid_ctx), CBS_len(&sid_ctx)); + ret->sid_ctx_length = CBS_len(&sid_ctx); + + if (verify_result > LONG_MAX || + ticket_lifetime_hint > 0xffffffff) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + ret->verify_result = verify_result; + ret->tlsext_tick_lifetime_hint = ticket_lifetime_hint; + + if (has_peer_sha256) { + if (CBS_len(&peer_sha256) != sizeof(ret->peer_sha256)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->peer_sha256, CBS_data(&peer_sha256), sizeof(ret->peer_sha256)); + ret->peer_sha256_valid = 1; + } else { + ret->peer_sha256_valid = 0; + } + + if (CBS_len(&original_handshake_hash) > + sizeof(ret->original_handshake_hash)) { + OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION); + goto err; + } + memcpy(ret->original_handshake_hash, CBS_data(&original_handshake_hash), + CBS_len(&original_handshake_hash)); + ret->original_handshake_hash_len = CBS_len(&original_handshake_hash); + + if (a) { + *a = ret; + } + *pp = CBS_data(&cbs); + return ret; + +err: + if (a && *a != ret) { + SSL_SESSION_free(ret); + } + return NULL; +} diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index 040a2db..97169f2 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -447,12 +447,6 @@ static void ssl_cipher_collect_ciphers(const SSL_METHOD *ssl_method, co_list[co_list_num].active = 0; co_list[co_list_num].in_group = 0; co_list_num++; -#ifdef KSSL_DEBUG - printf("\t%d: %s %lx %lx %lx\n",i,c->name,c->id,c->algorithm_mkey,c->algorithm_auth); -#endif /* KSSL_DEBUG */ - /* - if (!sk_push(ca_list,(char *)c)) goto err; - */ } } @@ -1023,9 +1017,6 @@ STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *ssl_method, * it is used for allocation. */ num_of_ciphers = ssl_method->num_ciphers(); -#ifdef KSSL_DEBUG - printf("ssl_create_cipher_list() for %d ciphers\n", num_of_ciphers); -#endif /* KSSL_DEBUG */ co_list = (CIPHER_ORDER *)OPENSSL_malloc(sizeof(CIPHER_ORDER) * num_of_ciphers); if (co_list == NULL) { @@ -1209,11 +1200,7 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) const char *ver; const char *kx,*au,*enc,*mac; unsigned long alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl; -#ifdef KSSL_DEBUG - static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s AL=%lx/%lx/%lx/%lx/%lx\n"; -#else static const char *format="%-23s %s Kx=%-8s Au=%-4s Enc=%-9s Mac=%-4s\n"; -#endif /* KSSL_DEBUG */ alg_mkey = cipher->algorithm_mkey; alg_auth = cipher->algorithm_auth; @@ -1324,11 +1311,7 @@ const char *SSL_CIPHER_description(const SSL_CIPHER *cipher, char *buf, int len) else if (len < 128) return("Buffer too small"); -#ifdef KSSL_DEBUG - BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac,alg_mkey,alg_auth,alg_enc,alg_mac,alg_ssl); -#else BIO_snprintf(buf,len,format,cipher->name,ver,kx,au,enc,mac); -#endif /* KSSL_DEBUG */ return(buf); } diff --git a/ssl/ssl_error.c b/ssl/ssl_error.c index 0ba125b..b070b5f 100644 --- a/ssl/ssl_error.c +++ b/ssl/ssl_error.c @@ -39,6 +39,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_new, 0), "SSL_SESSION_new"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_print_fp, 0), "SSL_SESSION_print_fp"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_set1_id_context, 0), "SSL_SESSION_set1_id_context"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_SESSION_to_bytes_full, 0), "SSL_SESSION_to_bytes_full"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_dir_cert_subjects_to_stack, 0), "SSL_add_dir_cert_subjects_to_stack"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_add_file_cert_subjects_to_stack, 0), "SSL_add_file_cert_subjects_to_stack"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_check_private_key, 0), "SSL_check_private_key"}, @@ -70,6 +71,9 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_SSL_write, 0), "SSL_write"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_authz_find_data, 0), "authz_find_data"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_check_suiteb_cipher_list, 0), "check_suiteb_cipher_list"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION, 0), "d2i_SSL_SESSION"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_octet_string, 0), "d2i_SSL_SESSION_get_octet_string"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_d2i_SSL_SESSION_get_string, 0), "d2i_SSL_SESSION_get_string"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_do_dtls1_write, 0), "do_dtls1_write"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_do_ssl3_write, 0), "do_ssl3_write"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_accept, 0), "dtls1_accept"}, @@ -87,6 +91,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_dtls1_write_app_data_bytes, 0), "dtls1_write_app_data_bytes"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_fclose, 0), "fclose"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_fprintf, 0), "fprintf"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_i2d_SSL_SESSION, 0), "i2d_SSL_SESSION"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_printf, 0), "printf"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_read_authz, 0), "read_authz"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl23_accept, 0), "ssl23_accept"}, @@ -136,6 +141,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_certificate, 0), "ssl3_send_client_certificate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_hello, 0), "ssl3_send_client_hello"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_client_key_exchange, 0), "ssl3_send_client_key_exchange"}, + {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_new_session_ticket, 0), "ssl3_send_new_session_ticket"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_certificate, 0), "ssl3_send_server_certificate"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_hello, 0), "ssl3_send_server_hello"}, {ERR_PACK(ERR_LIB_SSL, SSL_F_ssl3_send_server_key_exchange, 0), "ssl3_send_server_key_exchange"}, @@ -320,6 +326,7 @@ const ERR_STRING_DATA SSL_error_string_data[] = { {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_PURPOSE), "INVALID_PURPOSE"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA), "INVALID_SERVERINFO_DATA"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME), "INVALID_SRP_USERNAME"}, + {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SSL_SESSION), "INVALID_SSL_SESSION"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE), "INVALID_STATUS_RESPONSE"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH), "INVALID_TICKET_KEYS_LENGTH"}, {ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TRUST), "INVALID_TRUST"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f7818ed..8357ff9 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1495,8 +1495,7 @@ int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p) return(p-q); } -STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, - STACK_OF(SSL_CIPHER) **skp) +STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs) { CBS cipher_suites = *cbs; const SSL_CIPHER *c; @@ -1508,14 +1507,14 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, if (CBS_len(&cipher_suites) % 2 != 0) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); - return(NULL); + return NULL; } - if ((skp == NULL) || (*skp == NULL)) - sk=sk_SSL_CIPHER_new_null(); /* change perhaps later */ - else + + sk = sk_SSL_CIPHER_new_null(); + if (sk == NULL) { - sk= *skp; - sk_SSL_CIPHER_zero(sk); + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); + goto err; } if (!CBS_stow(&cipher_suites, @@ -1535,10 +1534,10 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, goto err; } - /* Check for SCSV */ + /* Check for SCSV. */ if (s->s3 && cipher_suite == (SSL3_CK_SCSV & 0xffff)) { - /* SCSV fatal if renegotiating */ + /* SCSV is fatal if renegotiating. */ if (s->renegotiate) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); @@ -1546,25 +1545,25 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, goto err; } s->s3->send_connection_binding = 1; -#ifdef OPENSSL_RI_DEBUG - fprintf(stderr, "SCSV received by server\n"); -#endif continue; } - /* Check for FALLBACK_SCSV */ - if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff) && - s->version < ssl_get_max_version(s)) + /* Check for FALLBACK_SCSV. */ + if (s->s3 && cipher_suite == (SSL3_CK_FALLBACK_SCSV & 0xffff)) { - OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK); - ssl3_send_alert(s,SSL3_AL_FATAL,SSL3_AD_INAPPROPRIATE_FALLBACK); - goto err; + if (s->version < ssl_get_max_version(s)) + { + OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, SSL_R_INAPPROPRIATE_FALLBACK); + ssl3_send_alert(s, SSL3_AL_FATAL, SSL3_AD_INAPPROPRIATE_FALLBACK); + goto err; + } + continue; } c = ssl3_get_cipher_by_value(cipher_suite); if (c != NULL) { - if (!sk_SSL_CIPHER_push(sk,c)) + if (!sk_SSL_CIPHER_push(sk, c)) { OPENSSL_PUT_ERROR(SSL, ssl_bytes_to_cipher_list, ERR_R_MALLOC_FAILURE); goto err; @@ -1572,13 +1571,12 @@ STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, } } - if (skp != NULL) - *skp=sk; - return(sk); + return sk; + err: - if ((skp == NULL) || (*skp == NULL)) + if (sk != NULL) sk_SSL_CIPHER_free(sk); - return(NULL); + return NULL; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 75c0ba8..c214b91 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -568,6 +568,11 @@ struct tls_sigalgs_st #define FP_ICC (int (*)(const void *,const void *)) +enum should_add_to_finished_hash { + add_to_finished_hash, + dont_add_to_finished_hash, +}; + /* 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 :-) */ @@ -597,7 +602,9 @@ typedef struct ssl3_enc_method /* Set the handshake header */ void (*set_handshake_header)(SSL *s, int type, unsigned long len); /* Write out handshake message */ - int (*do_write)(SSL *s); + int (*do_write)(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash); + /* Add the current handshake message to the finished hash. */ + void (*add_to_finished_hash)(SSL *s); } SSL3_ENC_METHOD; #define SSL_HM_HEADER_LENGTH(s) s->method->ssl3_enc->hhlen @@ -605,7 +612,7 @@ typedef struct ssl3_enc_method (((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen) #define ssl_set_handshake_header(s, htype, len) \ s->method->ssl3_enc->set_handshake_header(s, htype, len) -#define ssl_do_write(s) s->method->ssl3_enc->do_write(s) +#define ssl_do_write(s) s->method->ssl3_enc->do_write(s, add_to_finished_hash) /* Values for enc_flags */ @@ -768,8 +775,7 @@ int ssl_set_peer_cert_type(SESS_CERT *c, int type); int ssl_get_prev_session(SSL *s, const struct ssl_early_callback_ctx *ctx); int ssl_cipher_id_cmp(const void *in_a, const void *in_b); int ssl_cipher_ptr_id_cmp(const SSL_CIPHER **ap, const SSL_CIPHER **bp); -STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs, - STACK_OF(SSL_CIPHER) **skp); +STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, const CBS *cbs); int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *sk, uint8_t *p); STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth, struct ssl_cipher_preference_list_st **pref, @@ -824,7 +830,7 @@ int ssl3_setup_key_block(SSL *s); int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b); int ssl3_change_cipher_state(SSL *s,int which); void ssl3_cleanup_key_block(SSL *s); -int ssl3_do_write(SSL *s,int type); +int ssl3_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash); int ssl3_send_alert(SSL *s,int level, int desc); int ssl3_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len); @@ -866,7 +872,13 @@ int ssl3_setup_read_buffer(SSL *s); int ssl3_setup_write_buffer(SSL *s); int ssl3_release_read_buffer(SSL *s); int ssl3_release_write_buffer(SSL *s); -int ssl3_digest_cached_records(SSL *s); + +enum should_free_handshake_buffer_t { + free_handshake_buffer, + dont_free_handshake_buffer, +}; +int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t); + int ssl3_new(SSL *s); void ssl3_free(SSL *s); int ssl3_accept(SSL *s); @@ -886,13 +898,14 @@ void ssl3_record_sequence_update(unsigned char *seq); int ssl3_do_change_cipher_spec(SSL *ssl); void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len); -int ssl3_handshake_write(SSL *s); +int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash); +void ssl3_add_to_finished_hash(SSL *s); int ssl23_read(SSL *s, void *buf, int len); int ssl23_peek(SSL *s, void *buf, int len); int ssl23_write(SSL *s, const void *buf, int len); -int dtls1_do_write(SSL *s,int type); +int dtls1_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash); int ssl3_read_n(SSL *s, int n, int max, int extend); int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek); int ssl3_write_pending(SSL *s, int type, const unsigned char *buf, diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c index a202273..da9ba4b 100644 --- a/ssl/ssl_test.c +++ b/ssl/ssl_test.c @@ -307,20 +307,6 @@ static const char kOpenSSLSession[] = * filling in missing fields from |kOpenSSLSession|. This includes * providing |peer_sha256|, so |peer| is not serialized. */ static const char kCustomSession[] = - "MIIBggIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" - "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" - "IWoJgAEBoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29t" - "pwcEBWhlbGxvqAcEBXdvcmxkqQUCAwGJwKqBpwSBpBwUQvoeOk0Kg36SYTcLEkXq" - "KwOBfF9vE4KX0NxeLwjcDTpsuh3qXEaZ992r1N38VDcyS6P7I6HBYN9BsNHM362z" - "ZnY27GpTw+Kwd751CLoXFPoaMOe57dbBpXoro6Pd3BTbf/Tzr88K06yEOTDKPNj3" - "+inbMaVigtK4PLyPq+Topyzvx9USFgRvyuoxn0Hgb+R0A3j6SLRuyOdAi4gv7Y5o" - "liynrSIEIAYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGBgYGrgMEAQevAwQB" - "BLADBAEF"; - -/* kCustomSession2 is kCustomSession with the old SSLv2-only key_arg - * field removed. Encoding the decoded version of kCustomSession - * should not preserve key_arg. */ -static const char kCustomSession2[] = "MIIBfwIBAQICAwMEAsAvBCAG5Q1ndq4Yfmbeo1zwLkNRKmCXGdNgWvGT3cskV0yQ" "kAQwJlrlzkAWBOWiLj/jJ76D7l+UXoizP2KI2C7I2FccqMmIfFmmkUy32nIJ0mZH" "IWoJoQYCBFRDO46iBAICASykAwQBAqUDAgEUphAEDnd3dy5nb29nbGUuY29tpwcE" @@ -355,18 +341,16 @@ static int decode_base64(uint8_t **out, size_t *out_len, const char *in) { return 1; } -static int test_ssl_session_asn1(const char *input_b64, - const char *expected_b64) { +static int test_ssl_session_asn1(const char *input_b64) { int ret = 0, len; - size_t input_len, expected_len; - uint8_t *input = NULL, *expected = NULL, *encoded = NULL; + size_t input_len, encoded_len; + uint8_t *input = NULL, *encoded = NULL; const uint8_t *cptr; uint8_t *ptr; SSL_SESSION *session = NULL; /* Decode the input. */ - if (!decode_base64(&input, &input_len, input_b64) || - !decode_base64(&expected, &expected_len, expected_b64)) { + if (!decode_base64(&input, &input_len, input_b64)) { goto done; } @@ -379,28 +363,41 @@ static int test_ssl_session_asn1(const char *input_b64, } /* Verify the SSL_SESSION encoding round-trips. */ + if (!SSL_SESSION_to_bytes(session, &encoded, &encoded_len)) { + fprintf(stderr, "SSL_SESSION_to_bytes failed\n"); + goto done; + } + if (encoded_len != input_len || + memcmp(input, encoded, input_len) != 0) { + fprintf(stderr, "SSL_SESSION_to_bytes did not round-trip\n"); + goto done; + } + OPENSSL_free(encoded); + encoded = NULL; + + /* Verify the SSL_SESSION encoding round-trips via the legacy API. */ len = i2d_SSL_SESSION(session, NULL); - if (len < 0 || (size_t)len != expected_len) { + if (len < 0 || (size_t)len != input_len) { fprintf(stderr, "i2d_SSL_SESSION(NULL) returned invalid length\n"); goto done; } - encoded = OPENSSL_malloc(expected_len); + encoded = OPENSSL_malloc(input_len); if (encoded == NULL) { fprintf(stderr, "malloc failed\n"); goto done; } ptr = encoded; len = i2d_SSL_SESSION(session, &ptr); - if (len < 0 || (size_t)len != expected_len) { + if (len < 0 || (size_t)len != input_len) { fprintf(stderr, "i2d_SSL_SESSION returned invalid length\n"); goto done; } - if (ptr != encoded + expected_len) { + if (ptr != encoded + input_len) { fprintf(stderr, "i2d_SSL_SESSION did not advance ptr correctly\n"); goto done; } - if (memcmp(expected, encoded, expected_len) != 0) { + if (memcmp(input, encoded, input_len) != 0) { fprintf(stderr, "i2d_SSL_SESSION did not round-trip\n"); goto done; } @@ -418,9 +415,6 @@ static int test_ssl_session_asn1(const char *input_b64, if (input) { OPENSSL_free(input); } - if (expected) { - OPENSSL_free(expected); - } if (encoded) { OPENSSL_free(encoded); } @@ -431,9 +425,8 @@ int main(void) { SSL_library_init(); if (!test_cipher_rules() || - !test_ssl_session_asn1(kOpenSSLSession, kOpenSSLSession) || - !test_ssl_session_asn1(kCustomSession, kCustomSession2) || - !test_ssl_session_asn1(kCustomSession2, kCustomSession2)) { + !test_ssl_session_asn1(kOpenSSLSession) || + !test_ssl_session_asn1(kCustomSession)) { return 1; } diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index dd00d0a..6803e9b 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -152,8 +152,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec, const void *seed1, int seed1_len, const void *seed2, int seed2_len, const void *seed3, int seed3_len, - const void *seed4, int seed4_len, - const void *seed5, int seed5_len, unsigned char *out, int olen) { int chunk; @@ -182,10 +180,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec, goto err; if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len)) goto err; - if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len)) - goto err; - if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len)) - goto err; A1_len = EVP_MAX_MD_SIZE; if (!EVP_DigestSignFinal(&ctx,A1,&A1_len)) goto err; @@ -205,10 +199,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec, goto err; if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len)) goto err; - if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len)) - goto err; - if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len)) - goto err; if (olen > chunk) { @@ -246,8 +236,6 @@ static int tls1_PRF(long digest_mask, const void *seed1, int seed1_len, const void *seed2, int seed2_len, const void *seed3, int seed3_len, - const void *seed4, int seed4_len, - const void *seed5, int seed5_len, const unsigned char *sec, int slen, unsigned char *out1, unsigned char *out2, int olen) @@ -275,7 +263,7 @@ static int tls1_PRF(long digest_mask, goto err; } if (!tls1_P_hash(md ,S1,len+(slen&1), - seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len, + seed1,seed1_len,seed2,seed2_len,seed3,seed3_len, out2,olen)) goto err; S1+=len; @@ -298,20 +286,8 @@ static int tls1_generate_key_block(SSL *s, unsigned char *km, TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE, s->s3->server_random,SSL3_RANDOM_SIZE, s->s3->client_random,SSL3_RANDOM_SIZE, - NULL,0,NULL,0, s->session->master_key,s->session->master_key_length, km,tmp,num); -#ifdef KSSL_DEBUG - printf("tls1_generate_key_block() ==> %d byte master_key =\n\t", - s->session->master_key_length); - { - int i; - for (i=0; i < s->session->master_key_length; i++) - { - printf("%02X", s->session->master_key[i]); - } - printf("\n"); } -#endif /* KSSL_DEBUG */ return ret; } @@ -625,9 +601,6 @@ int tls1_setup_key_block(SSL *s) int ret=0; unsigned key_len, iv_len; -#ifdef KSSL_DEBUG - printf ("tls1_setup_key_block()\n"); -#endif /* KSSL_DEBUG */ if (s->s3->tmp.key_block_length != 0) return(1); @@ -926,10 +899,6 @@ int tls1_enc(SSL *s, int send) enc=EVP_CIPHER_CTX_cipher(s->enc_read_ctx); } -#ifdef KSSL_DEBUG - printf("tls1_enc(%d)\n", send); -#endif /* KSSL_DEBUG */ - if ((s->session == NULL) || (ds == NULL) || (enc == NULL)) { memmove(rec->data,rec->input,rec->length); @@ -955,24 +924,6 @@ int tls1_enc(SSL *s, int send) rec->length+=i; } -#ifdef KSSL_DEBUG - { - unsigned long ui; - printf("EVP_Cipher(ds=%p,rec->data=%p,rec->input=%p,l=%ld) ==>\n", - ds,rec->data,rec->input,l); - printf("\tEVP_CIPHER_CTX: %d buf_len, %d key_len [%d %d], %d iv_len\n", - ds->buf_len, ds->cipher->key_len, - DES_KEY_SZ, DES_SCHEDULE_SZ, - ds->cipher->iv_len); - printf("\t\tIV: "); - for (i=0; i<ds->cipher->iv_len; i++) printf("%02X", ds->iv[i]); - printf("\n"); - printf("\trec->input="); - for (ui=0; ui<l; ui++) printf(" %02x", rec->input[ui]); - printf("\n"); - } -#endif /* KSSL_DEBUG */ - if (!send) { if (l == 0 || l%bs != 0) @@ -985,15 +936,6 @@ int tls1_enc(SSL *s, int send) :(i==0)) return -1; /* AEAD can fail to verify MAC */ -#ifdef KSSL_DEBUG - { - unsigned long i; - printf("\trec->data="); - for (i=0; i<l; i++) - printf(" %02x", rec->data[i]); printf("\n"); - } -#endif /* KSSL_DEBUG */ - ret = 1; if (EVP_MD_CTX_md(s->read_hash) != NULL) mac_size = EVP_MD_CTX_size(s->read_hash); @@ -1011,8 +953,8 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out) EVP_MD_CTX ctx, *d=NULL; int i; - if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) + if (s->s3->handshake_buffer) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) return 0; for (i=0;i<SSL_MAX_DIGEST;i++) @@ -1093,7 +1035,7 @@ int tls1_final_finish_mac(SSL *s, int digests_len; if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) return 0; digests_len = tls1_handshake_digest(s, buf, sizeof(buf)); @@ -1104,7 +1046,7 @@ int tls1_final_finish_mac(SSL *s, } if (!tls1_PRF(ssl_get_algorithm2(s), - str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0, + str,slen, buf, digests_len, NULL,0, s->session->master_key,s->session->master_key_length, out,buf2,sizeof buf2)) err = 1; @@ -1212,22 +1154,53 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, int len) { unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH]; - const void *co = NULL, *so = NULL; - int col = 0, sol = 0; - - -#ifdef KSSL_DEBUG - printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len); -#endif /* KSSL_DEBUG */ - - tls1_PRF(ssl_get_algorithm2(s), - TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE, - s->s3->client_random,SSL3_RANDOM_SIZE, - co, col, - s->s3->server_random,SSL3_RANDOM_SIZE, - so, sol, - p,len, - s->session->master_key,buff,sizeof buff); + + if (s->s3->tmp.extended_master_secret) + { + uint8_t digests[2*EVP_MAX_MD_SIZE]; + int digests_len; + + if (s->s3->handshake_buffer) + { + /* The master secret is based on the handshake hash + * just after sending the ClientKeyExchange. However, + * we might have a client certificate to send, in which + * case we might need different hashes for the + * verification and thus still need the handshake + * buffer around. Keeping both a handshake buffer *and* + * running hashes isn't yet supported so, when it comes + * to calculating the Finished hash, we'll have to hash + * the handshake buffer again. */ + if (!ssl3_digest_cached_records(s, dont_free_handshake_buffer)) + return 0; + } + + digests_len = tls1_handshake_digest(s, digests, sizeof(digests)); + + if (digests_len == -1) + { + return 0; + } + + tls1_PRF(ssl_get_algorithm2(s), + TLS_MD_EXTENDED_MASTER_SECRET_CONST, + TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, + digests, digests_len, + NULL, 0, + p, len, + s->session->master_key, + buff, sizeof(buff)); + } + else + { + tls1_PRF(ssl_get_algorithm2(s), + TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE, + s->s3->client_random,SSL3_RANDOM_SIZE, + s->s3->server_random,SSL3_RANDOM_SIZE, + p, len, + s->session->master_key,buff,sizeof buff); + } + #ifdef SSL_DEBUG fprintf(stderr, "Premaster Secret:\n"); BIO_dump_fp(stderr, (char *)p, len); @@ -1257,9 +1230,6 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p, } #endif -#ifdef KSSL_DEBUG - printf ("tls1_generate_master_secret() complete\n"); -#endif /* KSSL_DEBUG */ return(SSL3_MASTER_SECRET_SIZE); } @@ -1272,10 +1242,6 @@ int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, size_t vallen, currentvalpos; int rv; -#ifdef KSSL_DEBUG - printf ("tls1_export_keying_material(%p,%p,%d,%s,%d,%p,%d)\n", s, out, olen, label, llen, p, plen); -#endif /* KSSL_DEBUG */ - buff = OPENSSL_malloc(olen); if (buff == NULL) goto err2; @@ -1330,14 +1296,9 @@ int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen, val, vallen, NULL, 0, NULL, 0, - NULL, 0, - NULL, 0, s->session->master_key,s->session->master_key_length, out,buff,olen); -#ifdef KSSL_DEBUG - printf ("tls1_export_keying_material() complete\n"); -#endif /* KSSL_DEBUG */ goto ret; err1: OPENSSL_PUT_ERROR(SSL, tls1_export_keying_material, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); @@ -1387,10 +1348,6 @@ int tls1_alert_code(int code) case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); case SSL_AD_INAPPROPRIATE_FALLBACK:return(SSL3_AD_INAPPROPRIATE_FALLBACK); -#if 0 /* not appropriate for TLS, not used for DTLS */ - case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return - (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); -#endif default: return(-1); } } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 4b13cfe..0972515 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -140,7 +140,8 @@ SSL3_ENC_METHOD TLSv1_enc_data={ 0, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, - ssl3_handshake_write + ssl3_handshake_write, + ssl3_add_to_finished_hash, }; SSL3_ENC_METHOD TLSv1_1_enc_data={ @@ -159,7 +160,8 @@ SSL3_ENC_METHOD TLSv1_1_enc_data={ SSL_ENC_FLAG_EXPLICIT_IV, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, - ssl3_handshake_write + ssl3_handshake_write, + ssl3_add_to_finished_hash, }; SSL3_ENC_METHOD TLSv1_2_enc_data={ @@ -179,7 +181,8 @@ SSL3_ENC_METHOD TLSv1_2_enc_data={ |SSL_ENC_FLAG_TLS1_2_CIPHERS, SSL3_HM_HEADER_LENGTH, ssl3_set_handshake_header, - ssl3_handshake_write + ssl3_handshake_write, + ssl3_add_to_finished_hash, }; static int compare_uint16_t(const void *p1, const void *p2) @@ -978,6 +981,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c ret += el; } + /* Add extended master secret. */ + if (s->version != SSL3_VERSION) + { + if (limit - ret - 4 < 0) + return NULL; + s2n(TLSEXT_TYPE_extended_master_secret,ret); + s2n(0,ret); + } + if (!(SSL_get_options(s) & SSL_OP_NO_TICKET)) { int ticklen; @@ -1246,6 +1258,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c ret += el; } + if (s->s3->tmp.extended_master_secret) + { + if ((long)(limit - ret - 4) < 0) return NULL; + + s2n(TLSEXT_TYPE_extended_master_secret,ret); + s2n(0,ret); + } + if (using_ecc) { const unsigned char *plist; @@ -1423,6 +1443,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) s->should_ack_sni = 0; s->s3->next_proto_neg_seen = 0; s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; if (s->s3->alpn_selected) { @@ -1782,6 +1803,18 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert) if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert)) return 0; } + + else if (type == TLSEXT_TYPE_extended_master_secret && + s->version != SSL3_VERSION) + { + if (CBS_len(&extension) != 0) + { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + s->s3->tmp.extended_master_secret = 1; + } } ri_check: @@ -1851,6 +1884,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) s->tlsext_ticket_expected = 0; s->s3->tmp.certificate_status_expected = 0; + s->s3->tmp.extended_master_secret = 0; if (s->s3->alpn_selected) { @@ -2086,6 +2120,20 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert) if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert)) return 0; } + + else if (type == TLSEXT_TYPE_extended_master_secret) + { + if (/* It is invalid for the server to select EMS and + SSLv3. */ + s->version == SSL3_VERSION || + CBS_len(&extension) != 0) + { + *out_alert = SSL_AD_DECODE_ERROR; + return 0; + } + + s->s3->tmp.extended_master_secret = 1; + } } if (!s->hit && tlsext_servername == 1) @@ -2779,7 +2827,7 @@ tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s) static const char kClientIDMagic[] = "TLS Channel ID signature"; if (s->s3->handshake_buffer) - if (!ssl3_digest_cached_records(s)) + if (!ssl3_digest_cached_records(s, free_handshake_buffer)) return 0; EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic)); diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index 6b27e26..ce2a3da 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc @@ -25,6 +25,7 @@ #include <sys/types.h> #include <openssl/bio.h> +#include <openssl/buf.h> #include <openssl/bytestring.h> #include <openssl/ssl.h> @@ -180,6 +181,48 @@ static int cookie_verify_callback(SSL *ssl, const uint8_t *cookie, size_t cookie return 1; } +static unsigned psk_client_callback(SSL *ssl, const char *hint, + char *out_identity, + unsigned max_identity_len, + uint8_t *out_psk, unsigned max_psk_len) { + const TestConfig *config = GetConfigPtr(ssl); + + if (strcmp(hint ? hint : "", config->psk_identity.c_str()) != 0) { + fprintf(stderr, "Server PSK hint did not match.\n"); + return 0; + } + + // Account for the trailing '\0' for the identity. + if (config->psk_identity.size() >= max_identity_len || + config->psk.size() > max_psk_len) { + fprintf(stderr, "PSK buffers too small\n"); + return 0; + } + + BUF_strlcpy(out_identity, config->psk_identity.c_str(), + max_identity_len); + memcpy(out_psk, config->psk.data(), config->psk.size()); + return config->psk.size(); +} + +static unsigned psk_server_callback(SSL *ssl, const char *identity, + uint8_t *out_psk, unsigned max_psk_len) { + const TestConfig *config = GetConfigPtr(ssl); + + if (strcmp(identity, config->psk_identity.c_str()) != 0) { + fprintf(stderr, "Client PSK identity did not match.\n"); + return 0; + } + + if (config->psk.size() > max_psk_len) { + fprintf(stderr, "PSK buffers too small\n"); + return 0; + } + + memcpy(out_psk, config->psk.data(), config->psk.size()); + return config->psk.size(); +} + static SSL_CTX *setup_ctx(const TestConfig *config) { SSL_CTX *ssl_ctx = NULL; DH *dh = NULL; @@ -369,6 +412,16 @@ static int do_exchange(SSL_SESSION **out_session, SSL_set_alpn_protos(ssl, (const uint8_t *)config->advertise_alpn.data(), config->advertise_alpn.size()); } + if (!config->psk.empty()) { + SSL_set_psk_client_callback(ssl, psk_client_callback); + SSL_set_psk_server_callback(ssl, psk_server_callback); + } + if (!config->psk_identity.empty()) { + if (!SSL_use_psk_identity_hint(ssl, config->psk_identity.c_str())) { + BIO_print_errors_fp(stdout); + return 1; + } + } BIO *bio = BIO_new_fd(fd, 1 /* take ownership */); if (bio == NULL) { @@ -482,6 +535,37 @@ static int do_exchange(SSL_SESSION **out_session, } } + if (config->expect_extended_master_secret) { + if (!ssl->session->extended_master_secret) { + fprintf(stderr, "No EMS for session when expected"); + return 2; + } + } + + if (config->renegotiate) { + if (config->async) { + fprintf(stderr, "--renegotiate is not supported with --async.\n"); + return 2; + } + + SSL_renegotiate(ssl); + + ret = SSL_do_handshake(ssl); + if (ret != 1) { + SSL_free(ssl); + BIO_print_errors_fp(stdout); + return 2; + } + + SSL_set_state(ssl, SSL_ST_ACCEPT); + ret = SSL_do_handshake(ssl); + if (ret != 1) { + SSL_free(ssl); + BIO_print_errors_fp(stdout); + return 2; + } + } + if (config->write_different_record_sizes) { if (config->is_dtls) { fprintf(stderr, "write_different_record_sizes not supported for DTLS\n"); diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go index 6cd0de9..5a3ac80 100644 --- a/ssl/test/runner/cipher_suites.go +++ b/ssl/test/runner/cipher_suites.go @@ -57,6 +57,9 @@ const ( // suiteNoDTLS indicates that the cipher suite cannot be used // in DTLS. suiteNoDTLS + // suitePSK indicates that the cipher suite authenticates with + // a pre-shared key rather than a server private key. + suitePSK ) // A cipherSuite is a specific combination of key agreement, cipher and MAC @@ -109,6 +112,10 @@ var cipherSuites = []*cipherSuite{ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, {TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, dheRSAKA, 0, cipher3DES, macSHA1, nil}, {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, + {TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdhePSKKA, suiteECDHE | suiteTLS12 | suitePSK, nil, nil, aeadAESGCM}, + {TLS_PSK_WITH_RC4_128_SHA, 16, 20, 0, pskKA, suiteNoDTLS | suitePSK, cipherRC4, macSHA1, nil}, + {TLS_PSK_WITH_AES_128_CBC_SHA, 16, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, + {TLS_PSK_WITH_AES_256_CBC_SHA, 32, 20, 16, pskKA, suitePSK, cipherAES, macSHA1, nil}, } func cipherRC4(key, iv []byte, isRead bool) interface{} { @@ -287,7 +294,7 @@ func rsaKA(version uint16) keyAgreement { func ecdheECDSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureECDSA, version: version, }, @@ -296,7 +303,7 @@ func ecdheECDSAKA(version uint16) keyAgreement { func ecdheRSAKA(version uint16) keyAgreement { return &ecdheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureRSA, version: version, }, @@ -305,13 +312,27 @@ func ecdheRSAKA(version uint16) keyAgreement { func dheRSAKA(version uint16) keyAgreement { return &dheKeyAgreement{ - signedKeyAgreement: signedKeyAgreement{ + auth: &signedKeyAgreement{ sigType: signatureRSA, version: version, }, } } +func pskKA(version uint16) keyAgreement { + return &pskKeyAgreement{ + base: &nilKeyAgreement{}, + } +} + +func ecdhePSKKA(version uint16) keyAgreement { + return &pskKeyAgreement{ + base: &ecdheKeyAgreement{ + auth: &nilKeyAgreementAuthentication{}, + }, + } +} + // mutualCipherSuite returns a cipherSuite given a list of supported // ciphersuites and the id requested by the peer. func mutualCipherSuite(have []uint16, want uint16) *cipherSuite { @@ -343,6 +364,9 @@ const ( TLS_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x003d TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x0067 TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 uint16 = 0x006b + TLS_PSK_WITH_RC4_128_SHA uint16 = 0x008a + TLS_PSK_WITH_AES_128_CBC_SHA uint16 = 0x008c + TLS_PSK_WITH_AES_256_CBC_SHA uint16 = 0x008d TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009e @@ -364,3 +388,8 @@ const ( TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 fallbackSCSV uint16 = 0x5600 ) + +// Additional cipher suite IDs, not IANA-assigned. +const ( + TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256 uint16 = 0xcafe +) diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 8b2c750..6f146af 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -48,6 +48,7 @@ const ( // TLS handshake message types. const ( + typeHelloRequest uint8 = 0 typeClientHello uint8 = 1 typeServerHello uint8 = 2 typeHelloVerifyRequest uint8 = 3 @@ -71,16 +72,17 @@ const ( // TLS extension numbers const ( - extensionServerName uint16 = 0 - extensionStatusRequest uint16 = 5 - extensionSupportedCurves uint16 = 10 - extensionSupportedPoints uint16 = 11 - extensionSignatureAlgorithms uint16 = 13 - extensionALPN uint16 = 16 - extensionSessionTicket uint16 = 35 - extensionNextProtoNeg uint16 = 13172 // not IANA assigned - extensionRenegotiationInfo uint16 = 0xff01 - extensionChannelID uint16 = 30032 // not IANA assigned + extensionServerName uint16 = 0 + extensionStatusRequest uint16 = 5 + extensionSupportedCurves uint16 = 10 + extensionSupportedPoints uint16 = 11 + extensionSignatureAlgorithms uint16 = 13 + extensionALPN uint16 = 16 + extensionExtendedMasterSecret uint16 = 23 + extensionSessionTicket uint16 = 35 + extensionNextProtoNeg uint16 = 13172 // not IANA assigned + extensionRenegotiationInfo uint16 = 0xff01 + extensionChannelID uint16 = 30032 // not IANA assigned ) // TLS signaling cipher suite values @@ -189,12 +191,13 @@ const ( // ClientSessionState contains the state needed by clients to resume TLS // sessions. type ClientSessionState struct { - sessionTicket []uint8 // Encrypted ticket used for session resumption with server - vers uint16 // SSL/TLS version negotiated for the session - cipherSuite uint16 // Ciphersuite negotiated for the session - masterSecret []byte // MasterSecret generated by client on a full handshake - handshakeHash []byte // Handshake hash for Channel ID purposes. - serverCertificates []*x509.Certificate // Certificate chain presented by the server + sessionTicket []uint8 // Encrypted ticket used for session resumption with server + vers uint16 // SSL/TLS version negotiated for the session + cipherSuite uint16 // Ciphersuite negotiated for the session + masterSecret []byte // MasterSecret generated by client on a full handshake + handshakeHash []byte // Handshake hash for Channel ID purposes. + serverCertificates []*x509.Certificate // Certificate chain presented by the server + extendedMasterSecret bool // Whether an extended master secret was used to generate the session } // ClientSessionCache is a cache of ClientSessionState objects that can be used @@ -323,6 +326,14 @@ type Config struct { // returned in the ConnectionState. RequestChannelID bool + // PreSharedKey, if not nil, is the pre-shared key to use with + // the PSK cipher suites. + PreSharedKey []byte + + // PreSharedKeyIdentity, if not empty, is the identity to use + // with the PSK cipher suites. + PreSharedKeyIdentity string + // Bugs specifies optional misbehaviour to be used for testing other // implementations. Bugs ProtocolBugs @@ -472,6 +483,22 @@ type ProtocolBugs struct { // OversizedSessionId causes the session id that is sent with a ticket // resumption attempt to be too large (33 bytes). OversizedSessionId bool + + // RequireExtendedMasterSecret, if true, requires that the peer support + // the extended master secret option. + RequireExtendedMasterSecret bool + + // NoExtendedMasterSecret causes the client and server to behave is if + // they didn't support an extended master secret. + NoExtendedMasterSecret bool + + // EmptyRenegotiationInfo causes the renegotiation extension to be + // empty in a renegotiation handshake. + EmptyRenegotiationInfo bool + + // BadRenegotiationInfo causes the renegotiation extension value in a + // renegotiation handshake to be incorrect. + BadRenegotiationInfo bool } func (c *Config) serverInit() { @@ -727,9 +754,10 @@ func defaultCipherSuites() []uint16 { } func initDefaultCipherSuites() { - varDefaultCipherSuites = make([]uint16, len(cipherSuites)) - for i, suite := range cipherSuites { - varDefaultCipherSuites[i] = suite.id + for _, suite := range cipherSuites { + if suite.flags&suitePSK == 0 { + varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) + } } } diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go index 9f0c328..e76f9d1 100644 --- a/ssl/test/runner/conn.go +++ b/ssl/test/runner/conn.go @@ -29,16 +29,17 @@ type Conn struct { isClient bool // constant after handshake; protected by handshakeMutex - handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex - handshakeErr error // error resulting from handshake - vers uint16 // TLS version - haveVers bool // version has been negotiated - config *Config // configuration passed to constructor - handshakeComplete bool - didResume bool // whether this connection was a session resumption - cipherSuite uint16 - ocspResponse []byte // stapled OCSP response - peerCertificates []*x509.Certificate + handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex + handshakeErr error // error resulting from handshake + vers uint16 // TLS version + haveVers bool // version has been negotiated + config *Config // configuration passed to constructor + handshakeComplete bool + didResume bool // whether this connection was a session resumption + extendedMasterSecret bool // whether this session used an extended master secret + cipherSuite uint16 + ocspResponse []byte // stapled OCSP response + peerCertificates []*x509.Certificate // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. verifiedChains [][]*x509.Certificate @@ -49,6 +50,10 @@ type Conn struct { clientProtocolFallback bool usedALPN bool + // verify_data values for the renegotiation extension. + clientVerify []byte + serverVerify []byte + channelID *ecdsa.PublicKey // input/output @@ -128,9 +133,10 @@ func (hc *halfConn) setErrorLocked(err error) error { } func (hc *halfConn) error() error { - hc.Lock() + // This should be locked, but I've removed it for the renegotiation + // tests since we don't concurrently read and write the same tls.Conn + // in any case during testing. err := hc.err - hc.Unlock() return err } @@ -650,7 +656,7 @@ func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) { func (c *Conn) readRecord(want recordType) error { // Caller must be in sync with connection: // handshake data if handshake not yet completed, - // else application data. (We don't support renegotiation.) + // else application data. switch want { default: c.sendAlert(alertInternalError) @@ -724,7 +730,12 @@ Again: case recordTypeHandshake: // TODO(rsc): Should at least pick off connection close. if typ != want { - return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) + // A client might need to process a HelloRequest from + // the server, thus receiving a handshake message when + // application data is expected is ok. + if !c.isClient { + return c.in.setErrorLocked(c.sendAlert(alertNoRenegotiation)) + } } c.hand.Write(data) } @@ -907,6 +918,8 @@ func (c *Conn) readHandshake() (interface{}, error) { var m handshakeMessage switch data[0] { + case typeHelloRequest: + m = new(helloRequestMsg) case typeClientHello: m = &clientHelloMsg{ isDTLS: c.isDTLS, @@ -999,6 +1012,35 @@ func (c *Conn) Write(b []byte) (int, error) { return n + m, c.out.setErrorLocked(err) } +func (c *Conn) handleRenegotiation() error { + c.handshakeComplete = false + if !c.isClient { + panic("renegotiation should only happen for a client") + } + + msg, err := c.readHandshake() + if err != nil { + return err + } + _, ok := msg.(*helloRequestMsg) + if !ok { + c.sendAlert(alertUnexpectedMessage) + return alertUnexpectedMessage + } + + return c.Handshake() +} + +func (c *Conn) Renegotiate() error { + if !c.isClient { + helloReq := new(helloRequestMsg) + c.writeRecord(recordTypeHandshake, helloReq.marshal()) + } + + c.handshakeComplete = false + return c.Handshake() +} + // Read can be made to time out and return a net.Error with Timeout() == true // after a fixed time limit; see SetDeadline and SetReadDeadline. func (c *Conn) Read(b []byte) (n int, err error) { @@ -1018,6 +1060,14 @@ func (c *Conn) Read(b []byte) (n int, err error) { // Soft error, like EAGAIN return 0, err } + if c.hand.Len() > 0 { + // We received handshake bytes, indicating the + // start of a renegotiation. + if err := c.handleRenegotiation(); err != nil { + return 0, err + } + continue + } } if err := c.in.err; err != nil { return 0, err diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index f4cadc2..0c5192f 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -56,26 +56,40 @@ func (c *Conn) clientHandshake() error { } hello := &clientHelloMsg{ - isDTLS: c.isDTLS, - vers: c.config.maxVersion(), - compressionMethods: []uint8{compressionNone}, - random: make([]byte, 32), - ocspStapling: true, - serverName: c.config.ServerName, - supportedCurves: c.config.curvePreferences(), - supportedPoints: []uint8{pointFormatUncompressed}, - nextProtoNeg: len(c.config.NextProtos) > 0, - secureRenegotiation: true, - alpnProtocols: c.config.NextProtos, - duplicateExtension: c.config.Bugs.DuplicateExtension, - channelIDSupported: c.config.ChannelID != nil, - npnLast: c.config.Bugs.SwapNPNAndALPN, + isDTLS: c.isDTLS, + vers: c.config.maxVersion(), + compressionMethods: []uint8{compressionNone}, + random: make([]byte, 32), + ocspStapling: true, + serverName: c.config.ServerName, + supportedCurves: c.config.curvePreferences(), + supportedPoints: []uint8{pointFormatUncompressed}, + nextProtoNeg: len(c.config.NextProtos) > 0, + secureRenegotiation: []byte{}, + alpnProtocols: c.config.NextProtos, + duplicateExtension: c.config.Bugs.DuplicateExtension, + channelIDSupported: c.config.ChannelID != nil, + npnLast: c.config.Bugs.SwapNPNAndALPN, + extendedMasterSecret: c.config.maxVersion() >= VersionTLS10, } if c.config.Bugs.SendClientVersion != 0 { hello.vers = c.config.Bugs.SendClientVersion } + if c.config.Bugs.NoExtendedMasterSecret { + hello.extendedMasterSecret = false + } + + if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo { + if c.config.Bugs.BadRenegotiationInfo { + hello.secureRenegotiation = append(hello.secureRenegotiation, c.clientVerify...) + hello.secureRenegotiation[0] ^= 0x80 + } else { + hello.secureRenegotiation = c.clientVerify + } + } + possibleCipherSuites := c.config.cipherSuites() hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites)) @@ -235,6 +249,16 @@ NextCipherSuite: return fmt.Errorf("tls: server selected an unsupported cipher suite") } + if len(c.clientVerify) > 0 { + var expectedRenegInfo []byte + expectedRenegInfo = append(expectedRenegInfo, c.clientVerify...) + expectedRenegInfo = append(expectedRenegInfo, c.serverVerify...) + if !bytes.Equal(serverHello.secureRenegotiation, expectedRenegInfo) { + c.sendAlert(alertHandshakeFailure) + return fmt.Errorf("tls: renegotiation mismatch") + } + } + hs := &clientHandshakeState{ c: c, serverHello: serverHello, @@ -303,60 +327,65 @@ NextCipherSuite: func (hs *clientHandshakeState) doFullHandshake() error { c := hs.c - msg, err := c.readHandshake() - if err != nil { - return err - } - certMsg, ok := msg.(*certificateMsg) - if !ok || len(certMsg.certificates) == 0 { - c.sendAlert(alertUnexpectedMessage) - return unexpectedMessageError(certMsg, msg) - } - hs.writeServerHash(certMsg.marshal()) - - certs := make([]*x509.Certificate, len(certMsg.certificates)) - for i, asn1Data := range certMsg.certificates { - cert, err := x509.ParseCertificate(asn1Data) + var leaf *x509.Certificate + if hs.suite.flags&suitePSK == 0 { + msg, err := c.readHandshake() if err != nil { - c.sendAlert(alertBadCertificate) - return errors.New("tls: failed to parse certificate from server: " + err.Error()) + return err } - certs[i] = cert - } - if !c.config.InsecureSkipVerify { - opts := x509.VerifyOptions{ - Roots: c.config.RootCAs, - CurrentTime: c.config.time(), - DNSName: c.config.ServerName, - Intermediates: x509.NewCertPool(), + certMsg, ok := msg.(*certificateMsg) + if !ok || len(certMsg.certificates) == 0 { + c.sendAlert(alertUnexpectedMessage) + return unexpectedMessageError(certMsg, msg) } + hs.writeServerHash(certMsg.marshal()) - for i, cert := range certs { - if i == 0 { - continue + certs := make([]*x509.Certificate, len(certMsg.certificates)) + for i, asn1Data := range certMsg.certificates { + cert, err := x509.ParseCertificate(asn1Data) + if err != nil { + c.sendAlert(alertBadCertificate) + return errors.New("tls: failed to parse certificate from server: " + err.Error()) } - opts.Intermediates.AddCert(cert) + certs[i] = cert } - c.verifiedChains, err = certs[0].Verify(opts) - if err != nil { - c.sendAlert(alertBadCertificate) - return err + leaf = certs[0] + + if !c.config.InsecureSkipVerify { + opts := x509.VerifyOptions{ + Roots: c.config.RootCAs, + CurrentTime: c.config.time(), + DNSName: c.config.ServerName, + Intermediates: x509.NewCertPool(), + } + + for i, cert := range certs { + if i == 0 { + continue + } + opts.Intermediates.AddCert(cert) + } + c.verifiedChains, err = leaf.Verify(opts) + if err != nil { + c.sendAlert(alertBadCertificate) + return err + } } - } - switch certs[0].PublicKey.(type) { - case *rsa.PublicKey, *ecdsa.PublicKey: - break - default: - c.sendAlert(alertUnsupportedCertificate) - return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey) - } + switch leaf.PublicKey.(type) { + case *rsa.PublicKey, *ecdsa.PublicKey: + break + default: + c.sendAlert(alertUnsupportedCertificate) + return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", leaf.PublicKey) + } - c.peerCertificates = certs + c.peerCertificates = certs + } if hs.serverHello.ocspStapling { - msg, err = c.readHandshake() + msg, err := c.readHandshake() if err != nil { return err } @@ -372,7 +401,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { } } - msg, err = c.readHandshake() + msg, err := c.readHandshake() if err != nil { return err } @@ -382,7 +411,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { skx, ok := msg.(*serverKeyExchangeMsg) if ok { hs.writeServerHash(skx.marshal()) - err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, certs[0], skx) + err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, leaf, skx) if err != nil { c.sendAlert(alertUnexpectedMessage) return err @@ -483,7 +512,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { // Certificate message, even if it's empty because we don't have a // certificate to send. if certRequested { - certMsg = new(certificateMsg) + certMsg := new(certificateMsg) if chainToSend != nil { certMsg.certificates = chainToSend.Certificate } @@ -491,7 +520,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.writeRecord(recordTypeHandshake, certMsg.marshal()) } - preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, certs[0]) + preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, leaf) if err != nil { c.sendAlert(alertInternalError) return err @@ -503,7 +532,15 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.writeRecord(recordTypeHandshake, ckx.marshal()) } - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) + if hs.serverHello.extendedMasterSecret && c.vers >= VersionTLS10 { + hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash) + c.extendedMasterSecret = true + } else { + if c.config.Bugs.RequireExtendedMasterSecret { + return errors.New("tls: extended master secret required but not supported by peer") + } + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) + } if chainToSend != nil { var signed []byte @@ -629,6 +666,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { // Restore masterSecret and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates + c.extendedMasterSecret = hs.session.extendedMasterSecret hs.finishedHash.discardHandshakeBuffer() return true, nil } @@ -661,6 +699,7 @@ func (hs *clientHandshakeState) readFinished() error { return errors.New("tls: server's Finished message was incorrect") } } + c.serverVerify = append(c.serverVerify[:0], serverFinished.verifyData...) hs.writeServerHash(serverFinished.marshal()) return nil } @@ -747,6 +786,7 @@ func (hs *clientHandshakeState) sendFinished(isResume bool) error { } else { finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret) } + c.clientVerify = append(c.clientVerify[:0], finished.verifyData...) finishedBytes := finished.marshal() hs.writeHash(finishedBytes, seqno) postCCSBytes = append(postCCSBytes, finishedBytes...) diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go index 136360d..12a9f3d 100644 --- a/ssl/test/runner/handshake_messages.go +++ b/ssl/test/runner/handshake_messages.go @@ -7,27 +7,28 @@ package main import "bytes" type clientHelloMsg struct { - raw []byte - isDTLS bool - vers uint16 - random []byte - sessionId []byte - cookie []byte - cipherSuites []uint16 - compressionMethods []uint8 - nextProtoNeg bool - serverName string - ocspStapling bool - supportedCurves []CurveID - supportedPoints []uint8 - ticketSupported bool - sessionTicket []uint8 - signatureAndHashes []signatureAndHash - secureRenegotiation bool - alpnProtocols []string - duplicateExtension bool - channelIDSupported bool - npnLast bool + raw []byte + isDTLS bool + vers uint16 + random []byte + sessionId []byte + cookie []byte + cipherSuites []uint16 + compressionMethods []uint8 + nextProtoNeg bool + serverName string + ocspStapling bool + supportedCurves []CurveID + supportedPoints []uint8 + ticketSupported bool + sessionTicket []uint8 + signatureAndHashes []signatureAndHash + secureRenegotiation []byte + alpnProtocols []string + duplicateExtension bool + channelIDSupported bool + npnLast bool + extendedMasterSecret bool } func (m *clientHelloMsg) equal(i interface{}) bool { @@ -52,11 +53,13 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.ticketSupported == m1.ticketSupported && bytes.Equal(m.sessionTicket, m1.sessionTicket) && eqSignatureAndHashes(m.signatureAndHashes, m1.signatureAndHashes) && - m.secureRenegotiation == m1.secureRenegotiation && + bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && + (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) && eqStrings(m.alpnProtocols, m1.alpnProtocols) && m.duplicateExtension == m1.duplicateExtension && m.channelIDSupported == m1.channelIDSupported && - m.npnLast == m1.npnLast + m.npnLast == m1.npnLast && + m.extendedMasterSecret == m1.extendedMasterSecret } func (m *clientHelloMsg) marshal() []byte { @@ -97,8 +100,8 @@ func (m *clientHelloMsg) marshal() []byte { extensionsLength += 2 + 2*len(m.signatureAndHashes) numExtensions++ } - if m.secureRenegotiation { - extensionsLength += 1 + if m.secureRenegotiation != nil { + extensionsLength += 1 + len(m.secureRenegotiation) numExtensions++ } if m.duplicateExtension { @@ -118,6 +121,9 @@ func (m *clientHelloMsg) marshal() []byte { } numExtensions++ } + if m.extendedMasterSecret { + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -274,12 +280,15 @@ func (m *clientHelloMsg) marshal() []byte { z = z[2:] } } - if m.secureRenegotiation { + if m.secureRenegotiation != nil { z[0] = byte(extensionRenegotiationInfo >> 8) z[1] = byte(extensionRenegotiationInfo & 0xff) z[2] = 0 - z[3] = 1 + z[3] = byte(1 + len(m.secureRenegotiation)) + z[4] = byte(len(m.secureRenegotiation)) z = z[5:] + copy(z, m.secureRenegotiation) + z = z[len(m.secureRenegotiation):] } if len(m.alpnProtocols) > 0 { z[0] = byte(extensionALPN >> 8) @@ -319,6 +328,12 @@ func (m *clientHelloMsg) marshal() []byte { z[1] = 0xff z = z[4:] } + if m.extendedMasterSecret { + // https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 + z[0] = byte(extensionExtendedMasterSecret >> 8) + z[1] = byte(extensionExtendedMasterSecret & 0xff) + z = z[4:] + } m.raw = x @@ -363,7 +378,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { for i := 0; i < numCipherSuites; i++ { m.cipherSuites[i] = uint16(data[2+2*i])<<8 | uint16(data[3+2*i]) if m.cipherSuites[i] == scsvRenegotiation { - m.secureRenegotiation = true + m.secureRenegotiation = []byte{} } } data = data[2+cipherSuiteLen:] @@ -385,6 +400,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.sessionTicket = nil m.signatureAndHashes = nil m.alpnProtocols = nil + m.extendedMasterSecret = false if len(data) == 0 { // ClientHello is optionally followed by extension data @@ -489,11 +505,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.signatureAndHashes[i].signature = d[1] d = d[2:] } - case extensionRenegotiationInfo + 1: - if length != 1 || data[0] != 0 { + case extensionRenegotiationInfo: + if length < 1 || length != int(data[0])+1 { return false } - m.secureRenegotiation = true + m.secureRenegotiation = data[1:length] case extensionALPN: if length < 2 { return false @@ -517,6 +533,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.channelIDSupported = true + case extensionExtendedMasterSecret: + if length != 0 { + return false + } + m.extendedMasterSecret = true } data = data[length:] } @@ -525,21 +546,22 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } type serverHelloMsg struct { - raw []byte - isDTLS bool - vers uint16 - random []byte - sessionId []byte - cipherSuite uint16 - compressionMethod uint8 - nextProtoNeg bool - nextProtos []string - ocspStapling bool - ticketSupported bool - secureRenegotiation bool - alpnProtocol string - duplicateExtension bool - channelIDRequested bool + raw []byte + isDTLS bool + vers uint16 + random []byte + sessionId []byte + cipherSuite uint16 + compressionMethod uint8 + nextProtoNeg bool + nextProtos []string + ocspStapling bool + ticketSupported bool + secureRenegotiation []byte + alpnProtocol string + duplicateExtension bool + channelIDRequested bool + extendedMasterSecret bool } func (m *serverHelloMsg) equal(i interface{}) bool { @@ -559,10 +581,12 @@ func (m *serverHelloMsg) equal(i interface{}) bool { eqStrings(m.nextProtos, m1.nextProtos) && m.ocspStapling == m1.ocspStapling && m.ticketSupported == m1.ticketSupported && - m.secureRenegotiation == m1.secureRenegotiation && + bytes.Equal(m.secureRenegotiation, m1.secureRenegotiation) && + (m.secureRenegotiation == nil) == (m1.secureRenegotiation == nil) && m.alpnProtocol == m1.alpnProtocol && m.duplicateExtension == m1.duplicateExtension && - m.channelIDRequested == m1.channelIDRequested + m.channelIDRequested == m1.channelIDRequested && + m.extendedMasterSecret == m1.extendedMasterSecret } func (m *serverHelloMsg) marshal() []byte { @@ -589,8 +613,8 @@ func (m *serverHelloMsg) marshal() []byte { if m.ticketSupported { numExtensions++ } - if m.secureRenegotiation { - extensionsLength += 1 + if m.secureRenegotiation != nil { + extensionsLength += 1 + len(m.secureRenegotiation) numExtensions++ } if m.duplicateExtension { @@ -606,6 +630,9 @@ func (m *serverHelloMsg) marshal() []byte { extensionsLength += 2 + 1 + alpnLen numExtensions++ } + if m.extendedMasterSecret { + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions @@ -667,12 +694,15 @@ func (m *serverHelloMsg) marshal() []byte { z[1] = byte(extensionSessionTicket) z = z[4:] } - if m.secureRenegotiation { + if m.secureRenegotiation != nil { z[0] = byte(extensionRenegotiationInfo >> 8) z[1] = byte(extensionRenegotiationInfo & 0xff) z[2] = 0 - z[3] = 1 + z[3] = byte(1 + len(m.secureRenegotiation)) + z[4] = byte(len(m.secureRenegotiation)) z = z[5:] + copy(z, m.secureRenegotiation) + z = z[len(m.secureRenegotiation):] } if alpnLen := len(m.alpnProtocol); alpnLen > 0 { z[0] = byte(extensionALPN >> 8) @@ -699,6 +729,11 @@ func (m *serverHelloMsg) marshal() []byte { z[1] = 0xff z = z[4:] } + if m.extendedMasterSecret { + z[0] = byte(extensionExtendedMasterSecret >> 8) + z[1] = byte(extensionExtendedMasterSecret & 0xff) + z = z[4:] + } m.raw = x @@ -730,6 +765,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.ocspStapling = false m.ticketSupported = false m.alpnProtocol = "" + m.extendedMasterSecret = false if len(data) == 0 { // ServerHello is optionally followed by extension data @@ -780,10 +816,10 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } m.ticketSupported = true case extensionRenegotiationInfo: - if length != 1 || data[0] != 0 { + if length < 1 || length != int(data[0])+1 { return false } - m.secureRenegotiation = true + m.secureRenegotiation = data[1:length] case extensionALPN: d := data[:length] if len(d) < 3 { @@ -805,6 +841,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { return false } m.channelIDRequested = true + case extensionExtendedMasterSecret: + if length != 0 { + return false + } + m.extendedMasterSecret = true } data = data[length:] } @@ -1634,6 +1675,17 @@ func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool { return true } +type helloRequestMsg struct { +} + +func (*helloRequestMsg) marshal() []byte { + return []byte{typeHelloRequest, 0, 0, 0} +} + +func (*helloRequestMsg) unmarshal(data []byte) bool { + return len(data) == 4 +} + func eqUint16s(x, y []uint16) bool { if len(x) != len(y) { return false diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 1eb3f11..41d588a 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -214,7 +214,22 @@ Curves: c.sendAlert(alertInternalError) return false, err } - hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation + + if !bytes.Equal(c.clientVerify, hs.clientHello.secureRenegotiation) { + c.sendAlert(alertHandshakeFailure) + return false, errors.New("tls: renegotiation mismatch") + } + + if len(c.clientVerify) > 0 && !c.config.Bugs.EmptyRenegotiationInfo { + hs.hello.secureRenegotiation = append(hs.hello.secureRenegotiation, c.clientVerify...) + hs.hello.secureRenegotiation = append(hs.hello.secureRenegotiation, c.serverVerify...) + if c.config.Bugs.BadRenegotiationInfo { + hs.hello.secureRenegotiation[0] ^= 0x80 + } + } else { + hs.hello.secureRenegotiation = hs.clientHello.secureRenegotiation + } + hs.hello.compressionMethod = compressionNone hs.hello.duplicateExtension = c.config.Bugs.DuplicateExtension if len(hs.clientHello.serverName) > 0 { @@ -237,6 +252,7 @@ Curves: hs.hello.nextProtos = config.NextProtos } } + hs.hello.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret if len(config.Certificates) == 0 { c.sendAlert(alertInternalError) @@ -373,6 +389,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error { } hs.masterSecret = hs.sessionState.masterSecret + c.extendedMasterSecret = hs.sessionState.extendedMasterSecret return nil } @@ -381,12 +398,14 @@ func (hs *serverHandshakeState) doFullHandshake() error { config := hs.c.config c := hs.c - if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { + isPSK := hs.suite.flags&suitePSK != 0 + if !isPSK && hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 { hs.hello.ocspStapling = true } hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled hs.hello.cipherSuite = hs.suite.id + c.extendedMasterSecret = hs.hello.extendedMasterSecret hs.finishedHash = newFinishedHash(c.vers, hs.suite) hs.writeClientHash(hs.clientHello.marshal()) @@ -394,11 +413,13 @@ func (hs *serverHandshakeState) doFullHandshake() error { c.writeRecord(recordTypeHandshake, hs.hello.marshal()) - certMsg := new(certificateMsg) - certMsg.certificates = hs.cert.Certificate - if !config.Bugs.UnauthenticatedECDH { - hs.writeServerHash(certMsg.marshal()) - c.writeRecord(recordTypeHandshake, certMsg.marshal()) + if !isPSK { + certMsg := new(certificateMsg) + certMsg.certificates = hs.cert.Certificate + if !config.Bugs.UnauthenticatedECDH { + hs.writeServerHash(certMsg.marshal()) + c.writeRecord(recordTypeHandshake, certMsg.marshal()) + } } if hs.hello.ocspStapling { @@ -463,6 +484,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { // If we requested a client certificate, then the client must send a // certificate message, even if it's empty. if config.ClientAuth >= RequestClientCert { + var certMsg *certificateMsg if certMsg, ok = msg.(*certificateMsg); !ok { c.sendAlert(alertUnexpectedMessage) return unexpectedMessageError(certMsg, msg) @@ -502,7 +524,14 @@ func (hs *serverHandshakeState) doFullHandshake() error { c.sendAlert(alertHandshakeFailure) return err } - hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) + if c.extendedMasterSecret { + hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash) + } else { + if c.config.Bugs.RequireExtendedMasterSecret { + return errors.New("tls: extended master secret required but not supported by peer") + } + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) + } // If we received a client cert in response to our certificate request message, // the client will send us a certificateVerifyMsg immediately after the @@ -679,6 +708,7 @@ func (hs *serverHandshakeState) readFinished(isResume bool) error { c.sendAlert(alertHandshakeFailure) return errors.New("tls: client's Finished message is incorrect") } + c.clientVerify = append(c.clientVerify[:0], clientFinished.verifyData...) hs.writeClientHash(clientFinished.marshal()) return nil @@ -716,6 +746,7 @@ func (hs *serverHandshakeState) sendFinished() error { finished := new(finishedMsg) finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) + c.serverVerify = append(c.serverVerify[:0], finished.verifyData...) postCCSBytes := finished.marshal() hs.writeServerHash(postCCSBytes) diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go index f8ba1f8..af54a8f 100644 --- a/ssl/test/runner/key_agreement.go +++ b/ssl/test/runner/key_agreement.go @@ -187,8 +187,29 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) { } -// signedKeyAgreement implements helper functions for key agreement -// methods that involve signed parameters in the ServerKeyExchange. +// keyAgreementAuthentication is a helper interface that specifies how +// to authenticate the ServerKeyExchange parameters. +type keyAgreementAuthentication interface { + signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) + verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error +} + +// nilKeyAgreementAuthentication does not authenticate the key +// agreement parameters. +type nilKeyAgreementAuthentication struct{} + +func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { + skx := new(serverKeyExchangeMsg) + skx.key = params + return skx, nil +} + +func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, params []byte, sig []byte) error { + return nil +} + +// signedKeyAgreement signs the ServerKeyExchange parameters with the +// server's private key. type signedKeyAgreement struct { version uint16 sigType uint8 @@ -328,7 +349,7 @@ func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clie // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { - signedKeyAgreement + auth keyAgreementAuthentication privateKey []byte curve elliptic.Curve x, y *big.Int @@ -394,7 +415,7 @@ NextCandidate: serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - return ka.signParameters(config, cert, clientHello, hello, serverECDHParams) + return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams) } func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { @@ -438,7 +459,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell serverECDHParams := skx.key[:4+publicLen] sig := skx.key[4+publicLen:] - return ka.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig) + return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig) } func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { @@ -468,7 +489,7 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel // an ephemeral Diffie-Hellman public/private key pair and signs it. The // pre-master secret is then calculated using Diffie-Hellman. type dheKeyAgreement struct { - signedKeyAgreement + auth keyAgreementAuthentication p, g *big.Int yTheirs *big.Int xOurs *big.Int @@ -500,7 +521,7 @@ func (ka *dheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi serverDHParams = append(serverDHParams, byte(len(yBytes)>>8), byte(len(yBytes))) serverDHParams = append(serverDHParams, yBytes...) - return ka.signParameters(config, cert, clientHello, hello, serverDHParams) + return ka.auth.signParameters(config, cert, clientHello, hello, serverDHParams) } func (ka *dheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { @@ -562,7 +583,7 @@ func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello sig := k serverDHParams := skx.key[:len(skx.key)-len(sig)] - return ka.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig) + return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverDHParams, sig) } func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { @@ -586,3 +607,164 @@ func (ka *dheKeyAgreement) generateClientKeyExchange(config *Config, clientHello return preMasterSecret, ckx, nil } + +// nilKeyAgreement is a fake key agreement used to implement the plain PSK key +// exchange. +type nilKeyAgreement struct{} + +func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + return nil, nil +} + +func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + if len(ckx.ciphertext) != 0 { + return nil, errClientKeyExchange + } + + // Although in plain PSK, otherSecret is all zeros, the base key + // agreement does not access to the length of the pre-shared + // key. pskKeyAgreement instead interprets nil to mean to use all zeros + // of the appropriate length. + return nil, nil +} + +func (ka *nilKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + if len(skx.key) != 0 { + return errServerKeyExchange + } + return nil +} + +func (ka *nilKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + // Although in plain PSK, otherSecret is all zeros, the base key + // agreement does not access to the length of the pre-shared + // key. pskKeyAgreement instead interprets nil to mean to use all zeros + // of the appropriate length. + return nil, &clientKeyExchangeMsg{}, nil +} + +// makePSKPremaster formats a PSK pre-master secret based on otherSecret from +// the base key exchange and psk. +func makePSKPremaster(otherSecret, psk []byte) []byte { + out := make([]byte, 0, 2+len(otherSecret)+2+len(psk)) + out = append(out, byte(len(otherSecret)>>8), byte(len(otherSecret))) + out = append(out, otherSecret...) + out = append(out, byte(len(psk)>>8), byte(len(psk))) + out = append(out, psk...) + return out +} + +// pskKeyAgreement implements the PSK key agreement. +type pskKeyAgreement struct { + base keyAgreement + identityHint string +} + +func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { + // Assemble the identity hint. + bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) + bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) + bytes[1] = byte(len(config.PreSharedKeyIdentity)) + copy(bytes[2:], []byte(config.PreSharedKeyIdentity)) + + // If there is one, append the base key agreement's + // ServerKeyExchange. + baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello) + if err != nil { + return nil, err + } + + if baseSkx != nil { + bytes = append(bytes, baseSkx.key...) + } else if config.PreSharedKeyIdentity == "" { + // ServerKeyExchange is optional if the identity hint is empty + // and there would otherwise be no ServerKeyExchange. + return nil, nil + } + + skx := new(serverKeyExchangeMsg) + skx.key = bytes + return skx, nil +} + +func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { + // First, process the PSK identity. + if len(ckx.ciphertext) < 2 { + return nil, errClientKeyExchange + } + identityLen := (int(ckx.ciphertext[0]) << 8) | int(ckx.ciphertext[1]) + if 2+identityLen > len(ckx.ciphertext) { + return nil, errClientKeyExchange + } + identity := string(ckx.ciphertext[2 : 2+identityLen]) + + if identity != config.PreSharedKeyIdentity { + return nil, errors.New("tls: unexpected identity") + } + + if config.PreSharedKey == nil { + return nil, errors.New("tls: pre-shared key not configured") + } + + // Process the remainder of the ClientKeyExchange to compute the base + // pre-master secret. + newCkx := new(clientKeyExchangeMsg) + newCkx.ciphertext = ckx.ciphertext[2+identityLen:] + otherSecret, err := ka.base.processClientKeyExchange(config, cert, newCkx, version) + if err != nil { + return nil, err + } + + if otherSecret == nil { + // Special-case for the plain PSK key exchanges. + otherSecret = make([]byte, len(config.PreSharedKey)) + } + return makePSKPremaster(otherSecret, config.PreSharedKey), nil +} + +func (ka *pskKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { + if len(skx.key) < 2 { + return errServerKeyExchange + } + identityLen := (int(skx.key[0]) << 8) | int(skx.key[1]) + if 2+identityLen > len(skx.key) { + return errServerKeyExchange + } + ka.identityHint = string(skx.key[2 : 2+identityLen]) + + // Process the remainder of the ServerKeyExchange. + newSkx := new(serverKeyExchangeMsg) + newSkx.key = skx.key[2+identityLen:] + return ka.base.processServerKeyExchange(config, clientHello, serverHello, cert, newSkx) +} + +func (ka *pskKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + // The server only sends an identity hint but, for purposes of + // test code, the server always sends the hint and it is + // required to match. + if ka.identityHint != config.PreSharedKeyIdentity { + return nil, nil, errors.New("tls: unexpected identity") + } + + // Serialize the identity. + bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) + bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) + bytes[1] = byte(len(config.PreSharedKeyIdentity)) + copy(bytes[2:], []byte(config.PreSharedKeyIdentity)) + + // Append the base key exchange's ClientKeyExchange. + otherSecret, baseCkx, err := ka.base.generateClientKeyExchange(config, clientHello, cert) + if err != nil { + return nil, nil, err + } + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = append(bytes, baseCkx.ciphertext...) + + if config.PreSharedKey == nil { + return nil, nil, errors.New("tls: pre-shared key not configured") + } + if otherSecret == nil { + otherSecret = make([]byte, len(config.PreSharedKey)) + } + return makePSKPremaster(otherSecret, config.PreSharedKey), ckx, nil +} diff --git a/ssl/test/runner/prf.go b/ssl/test/runner/prf.go index 6d0db97..d45c080 100644 --- a/ssl/test/runner/prf.go +++ b/ssl/test/runner/prf.go @@ -117,6 +117,7 @@ const ( ) var masterSecretLabel = []byte("master secret") +var extendedMasterSecretLabel = []byte("extended master secret") var keyExpansionLabel = []byte("key expansion") var clientFinishedLabel = []byte("client finished") var serverFinishedLabel = []byte("server finished") @@ -150,6 +151,15 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr return masterSecret } +// extendedMasterFromPreMasterSecret generates the master secret from the +// pre-master secret when the Triple Handshake fix is in effect. See +// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 +func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte { + masterSecret := make([]byte, masterSecretLength) + prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum()) + return masterSecret +} + // keysFromMasterSecret generates the connection keys from the master // secret, given the lengths of the MAC key, cipher key and IV, as defined in // RFC 2246, section 6.3. @@ -221,6 +231,16 @@ func (h *finishedHash) Write(msg []byte) (n int, err error) { return len(msg), nil } +func (h finishedHash) Sum() []byte { + if h.version >= VersionTLS12 { + return h.client.Sum(nil) + } + + out := make([]byte, 0, md5.Size+sha1.Size) + out = h.clientMD5.Sum(out) + return h.client.Sum(out) +} + // finishedSum30 calculates the contents of the verify_data member of a SSLv3 // Finished message given the MD5 and SHA1 hashes of a set of handshake // messages. @@ -264,15 +284,7 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte { } out := make([]byte, finishedVerifyLength) - if h.version >= VersionTLS12 { - seed := h.client.Sum(nil) - h.prf(out, masterSecret, clientFinishedLabel, seed) - } else { - seed := make([]byte, 0, md5.Size+sha1.Size) - seed = h.clientMD5.Sum(seed) - seed = h.client.Sum(seed) - h.prf(out, masterSecret, clientFinishedLabel, seed) - } + h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) return out } @@ -284,15 +296,7 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte { } out := make([]byte, finishedVerifyLength) - if h.version >= VersionTLS12 { - seed := h.server.Sum(nil) - h.prf(out, masterSecret, serverFinishedLabel, seed) - } else { - seed := make([]byte, 0, md5.Size+sha1.Size) - seed = h.serverMD5.Sum(seed) - seed = h.server.Sum(seed) - h.prf(out, masterSecret, serverFinishedLabel, seed) - } + h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) return out } @@ -334,14 +338,10 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash return digest[:], crypto.SHA256, nil } if signatureAndHash.signature == signatureECDSA { - digest := h.server.Sum(nil) - return digest, crypto.SHA1, nil + return h.server.Sum(nil), crypto.SHA1, nil } - digest := make([]byte, 0, 36) - digest = h.serverMD5.Sum(digest) - digest = h.server.Sum(digest) - return digest, crypto.MD5SHA1, nil + return h.Sum(), crypto.MD5SHA1, nil } // hashForChannelID returns the hash to be signed for TLS Channel diff --git a/ssl/test/runner/recordingconn.go b/ssl/test/runner/recordingconn.go new file mode 100644 index 0000000..a67fa48 --- /dev/null +++ b/ssl/test/runner/recordingconn.go @@ -0,0 +1,130 @@ +package main + +import ( + "bufio" + "encoding/hex" + "errors" + "fmt" + "io" + "net" + "strconv" + "strings" + "sync" +) + +// recordingConn is a net.Conn that records the traffic that passes through it. +// WriteTo can be used to produce output that can be later be loaded with +// ParseTestData. +type recordingConn struct { + net.Conn + sync.Mutex + flows [][]byte + reading bool +} + +func (r *recordingConn) Read(b []byte) (n int, err error) { + if n, err = r.Conn.Read(b); n == 0 { + return + } + b = b[:n] + + r.Lock() + defer r.Unlock() + + if l := len(r.flows); l == 0 || !r.reading { + buf := make([]byte, len(b)) + copy(buf, b) + r.flows = append(r.flows, buf) + } else { + r.flows[l-1] = append(r.flows[l-1], b[:n]...) + } + r.reading = true + return +} + +func (r *recordingConn) Write(b []byte) (n int, err error) { + if n, err = r.Conn.Write(b); n == 0 { + return + } + b = b[:n] + + r.Lock() + defer r.Unlock() + + if l := len(r.flows); l == 0 || r.reading { + buf := make([]byte, len(b)) + copy(buf, b) + r.flows = append(r.flows, buf) + } else { + r.flows[l-1] = append(r.flows[l-1], b[:n]...) + } + r.reading = false + return +} + +// WriteTo writes hex dumps to w that contains the recorded traffic. +func (r *recordingConn) WriteTo(w io.Writer) { + // TLS always starts with a client to server flow. + clientToServer := true + + for i, flow := range r.flows { + source, dest := "client", "server" + if !clientToServer { + source, dest = dest, source + } + fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest) + dumper := hex.Dumper(w) + dumper.Write(flow) + dumper.Close() + clientToServer = !clientToServer + } +} + +func parseTestData(r io.Reader) (flows [][]byte, err error) { + var currentFlow []byte + + scanner := bufio.NewScanner(r) + for scanner.Scan() { + line := scanner.Text() + // If the line starts with ">>> " then it marks the beginning + // of a new flow. + if strings.HasPrefix(line, ">>> ") { + if len(currentFlow) > 0 || len(flows) > 0 { + flows = append(flows, currentFlow) + currentFlow = nil + } + continue + } + + // Otherwise the line is a line of hex dump that looks like: + // 00000170 fc f5 06 bf (...) |.....X{&?......!| + // (Some bytes have been omitted from the middle section.) + + if i := strings.IndexByte(line, ' '); i >= 0 { + line = line[i:] + } else { + return nil, errors.New("invalid test data") + } + + if i := strings.IndexByte(line, '|'); i >= 0 { + line = line[:i] + } else { + return nil, errors.New("invalid test data") + } + + hexBytes := strings.Fields(line) + for _, hexByte := range hexBytes { + val, err := strconv.ParseUint(hexByte, 16, 8) + if err != nil { + return nil, errors.New("invalid hex byte in test data: " + err.Error()) + } + currentFlow = append(currentFlow, byte(val)) + } + } + + if len(currentFlow) > 0 { + flows = append(flows, currentFlow) + } + + return flows, nil +} diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index b4c2e61..4b43481 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -22,6 +22,8 @@ import ( ) var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind") +var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb") +var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection") const ( rsaCertificateFile = "cert.pem" @@ -148,6 +150,12 @@ type testCase struct { // shimWritesFirst controls whether the shim sends an initial "hello" // message before doing a roundtrip with the runner. shimWritesFirst bool + // renegotiate indicates the the connection should be renegotiated + // during the exchange. + renegotiate bool + // renegotiateCiphers is a list of ciphersuite ids that will be + // switched in just before renegotiation. + renegotiateCiphers []uint16 // flags, if not empty, contains a list of command-line flags that will // be passed to the shim program. flags []string @@ -563,6 +571,17 @@ func doExchange(test *testCase, config *Config, conn net.Conn, messageLen int, i } } + if test.renegotiate { + if test.renegotiateCiphers != nil { + config.CipherSuites = test.renegotiateCiphers + } + if err := tlsConn.Renegotiate(); err != nil { + return err + } + } else if test.renegotiateCiphers != nil { + panic("renegotiateCiphers without renegotiate") + } + if messageLen < 0 { if test.protocol == dtls { return fmt.Errorf("messageLen < 0 not supported for DTLS tests") @@ -693,10 +712,11 @@ func runTest(test *testCase, buildDir string) error { var shim *exec.Cmd if *useValgrind { shim = valgrindOf(false, shim_path, flags...) + } else if *useGDB { + shim = gdbOf(shim_path, flags...) } else { shim = exec.Command(shim_path, flags...) } - // shim = gdbOf(shim_path, flags...) shim.ExtraFiles = []*os.File{shimEnd, shimEndResume} shim.Stdin = os.Stdin var stdoutBuf, stderrBuf bytes.Buffer @@ -717,8 +737,19 @@ func runTest(test *testCase, buildDir string) error { } } + var connDebug *recordingConn + if *flagDebug { + connDebug = &recordingConn{Conn: conn} + conn = connDebug + } + err := doExchange(test, &config, conn, test.messageLen, false /* not a resumption */) + + if *flagDebug { + connDebug.WriteTo(os.Stdout) + } + conn.Close() if err == nil && test.resumeSession { var resumeConfig Config @@ -814,6 +845,7 @@ var testCipherSuites = []struct { {"ECDHE-ECDSA-AES256-SHA", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, {"ECDHE-ECDSA-AES256-SHA384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384}, {"ECDHE-ECDSA-RC4-SHA", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA}, + {"ECDHE-PSK-WITH-AES-128-GCM-SHA256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256}, {"ECDHE-RSA-AES128-GCM", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, {"ECDHE-RSA-AES128-SHA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, {"ECDHE-RSA-AES128-SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, @@ -821,6 +853,9 @@ var testCipherSuites = []struct { {"ECDHE-RSA-AES256-SHA", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, {"ECDHE-RSA-AES256-SHA384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384}, {"ECDHE-RSA-RC4-SHA", TLS_ECDHE_RSA_WITH_RC4_128_SHA}, + {"PSK-AES128-CBC-SHA", TLS_PSK_WITH_AES_128_CBC_SHA}, + {"PSK-AES256-CBC-SHA", TLS_PSK_WITH_AES_256_CBC_SHA}, + {"PSK-RC4-SHA", TLS_PSK_WITH_RC4_128_SHA}, {"RC4-MD5", TLS_RSA_WITH_RC4_128_MD5}, {"RC4-SHA", TLS_RSA_WITH_RC4_128_SHA}, } @@ -833,6 +868,9 @@ func isTLS12Only(suiteName string) bool { func addCipherSuiteTests() { for _, suite := range testCipherSuites { + const psk = "12345" + const pskIdentity = "luggage combo" + var cert Certificate var certFile string var keyFile string @@ -846,6 +884,13 @@ func addCipherSuiteTests() { keyFile = rsaKeyFile } + var flags []string + if strings.HasPrefix(suite.name, "PSK-") || strings.Contains(suite.name, "-PSK-") { + flags = append(flags, + "-psk", psk, + "-psk-identity", pskIdentity) + } + for _, ver := range tlsVersions { if ver.version < VersionTLS12 && isTLS12Only(suite.name) { continue @@ -860,11 +905,14 @@ func addCipherSuiteTests() { testType: clientTest, name: ver.name + "-" + suite.name + "-client", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + CipherSuites: []uint16{suite.id}, + Certificates: []Certificate{cert}, + PreSharedKey: []byte(psk), + PreSharedKeyIdentity: pskIdentity, }, + flags: flags, resumeSession: resumeSession, }) @@ -872,13 +920,16 @@ func addCipherSuiteTests() { testType: serverTest, name: ver.name + "-" + suite.name + "-server", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + CipherSuites: []uint16{suite.id}, + Certificates: []Certificate{cert}, + PreSharedKey: []byte(psk), + PreSharedKeyIdentity: pskIdentity, }, certFile: certFile, keyFile: keyFile, + flags: flags, resumeSession: resumeSession, }) @@ -889,11 +940,14 @@ func addCipherSuiteTests() { protocol: dtls, name: "D" + ver.name + "-" + suite.name + "-client", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + CipherSuites: []uint16{suite.id}, + Certificates: []Certificate{cert}, + PreSharedKey: []byte(psk), + PreSharedKeyIdentity: pskIdentity, }, + flags: flags, resumeSession: resumeSession, }) testCases = append(testCases, testCase{ @@ -901,13 +955,16 @@ func addCipherSuiteTests() { protocol: dtls, name: "D" + ver.name + "-" + suite.name + "-server", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + CipherSuites: []uint16{suite.id}, + Certificates: []Certificate{cert}, + PreSharedKey: []byte(psk), + PreSharedKeyIdentity: pskIdentity, }, certFile: certFile, keyFile: keyFile, + flags: flags, resumeSession: resumeSession, }) } @@ -1070,6 +1127,62 @@ func addClientAuthTests() { } } +func addExtendedMasterSecretTests() { + const expectEMSFlag = "-expect-extended-master-secret" + + for _, with := range []bool{false, true} { + prefix := "No" + var flags []string + if with { + prefix = "" + flags = []string{expectEMSFlag} + } + + for _, isClient := range []bool{false, true} { + suffix := "-Server" + testType := serverTest + if isClient { + suffix = "-Client" + testType = clientTest + } + + for _, ver := range tlsVersions { + test := testCase{ + testType: testType, + name: prefix + "ExtendedMasterSecret-" + ver.name + suffix, + config: Config{ + MinVersion: ver.version, + MaxVersion: ver.version, + Bugs: ProtocolBugs{ + NoExtendedMasterSecret: !with, + RequireExtendedMasterSecret: with, + }, + }, + flags: flags, + shouldFail: ver.version == VersionSSL30 && with, + } + if test.shouldFail { + test.expectedLocalError = "extended master secret required but not supported by peer" + } + testCases = append(testCases, test) + } + } + } + + // When a session is resumed, it should still be aware that its master + // secret was generated via EMS and thus it's safe to use tls-unique. + testCases = append(testCases, testCase{ + name: "ExtendedMasterSecret-Resume", + config: Config{ + Bugs: ProtocolBugs{ + RequireExtendedMasterSecret: true, + }, + }, + flags: []string{expectEMSFlag}, + resumeSession: true, + }) +} + // Adds tests that try to cover the range of the handshake state machine, under // various conditions. Some of these are redundant with other tests, but they // only cover the synchronous case. @@ -1178,6 +1291,34 @@ func addStateMachineCoverageTests(async, splitHandshake bool, protocol protocol) flags: flags, }) + // Skip ServerKeyExchange in PSK key exchange if there's no + // identity hint. + testCases = append(testCases, testCase{ + protocol: protocol, + name: "EmptyPSKHint-Client" + suffix, + config: Config{ + CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, + PreSharedKey: []byte("secret"), + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, "-psk", "secret"), + }) + testCases = append(testCases, testCase{ + protocol: protocol, + testType: serverTest, + name: "EmptyPSKHint-Server" + suffix, + config: Config{ + CipherSuites: []uint16{TLS_PSK_WITH_AES_128_CBC_SHA}, + PreSharedKey: []byte("secret"), + Bugs: ProtocolBugs{ + MaxHandshakeRecordLength: maxHandshakeRecordLength, + }, + }, + flags: append(flags, "-psk", "secret"), + }) + if protocol == tls { // NPN on client and server; results in post-handshake message. testCases = append(testCases, testCase{ @@ -1568,7 +1709,7 @@ func addExtensionTests() { }, }, resumeSession: true, - shouldFail: true, + shouldFail: true, expectedError: ":DECODE_ERROR:", }) } @@ -1635,6 +1776,84 @@ func addResumptionVersionTests() { } } +func addRenegotiationTests() { + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Renegotiate-Server", + flags: []string{"-renegotiate"}, + shimWritesFirst: true, + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Renegotiate-Server-EmptyExt", + config: Config{ + Bugs: ProtocolBugs{ + EmptyRenegotiationInfo: true, + }, + }, + flags: []string{"-renegotiate"}, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", + }) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "Renegotiate-Server-BadExt", + config: Config{ + Bugs: ProtocolBugs{ + BadRenegotiationInfo: true, + }, + }, + flags: []string{"-renegotiate"}, + shimWritesFirst: true, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", + }) + // TODO(agl): test the renegotiation info SCSV. + testCases = append(testCases, testCase{ + name: "Renegotiate-Client", + renegotiate: true, + }) + testCases = append(testCases, testCase{ + name: "Renegotiate-Client-EmptyExt", + renegotiate: true, + config: Config{ + Bugs: ProtocolBugs{ + EmptyRenegotiationInfo: true, + }, + }, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", + }) + testCases = append(testCases, testCase{ + name: "Renegotiate-Client-BadExt", + renegotiate: true, + config: Config{ + Bugs: ProtocolBugs{ + BadRenegotiationInfo: true, + }, + }, + shouldFail: true, + expectedError: ":RENEGOTIATION_MISMATCH:", + }) + testCases = append(testCases, testCase{ + name: "Renegotiate-Client-SwitchCiphers", + renegotiate: true, + config: Config{ + CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + }, + renegotiateCiphers: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + }) + testCases = append(testCases, testCase{ + name: "Renegotiate-Client-SwitchCiphers2", + renegotiate: true, + config: Config{ + CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, + }, + renegotiateCiphers: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + }) +} + func worker(statusChan chan statusMsg, c chan *testCase, buildDir string, wg *sync.WaitGroup) { defer wg.Done() @@ -1690,6 +1909,8 @@ func main() { addD5BugTests() addExtensionTests() addResumptionVersionTests() + addExtendedMasterSecretTests() + addRenegotiationTests() for _, async := range []bool{false, true} { for _, splitHandshake := range []bool{false, true} { for _, protocol := range []protocol{tls, dtls} { diff --git a/ssl/test/runner/ticket.go b/ssl/test/runner/ticket.go index 74791d6..8355822 100644 --- a/ssl/test/runner/ticket.go +++ b/ssl/test/runner/ticket.go @@ -18,11 +18,12 @@ import ( // sessionState contains the information that is serialized into a session // ticket in order to later resume a connection. type sessionState struct { - vers uint16 - cipherSuite uint16 - masterSecret []byte - handshakeHash []byte - certificates [][]byte + vers uint16 + cipherSuite uint16 + masterSecret []byte + handshakeHash []byte + certificates [][]byte + extendedMasterSecret bool } func (s *sessionState) equal(i interface{}) bool { @@ -34,7 +35,8 @@ func (s *sessionState) equal(i interface{}) bool { if s.vers != s1.vers || s.cipherSuite != s1.cipherSuite || !bytes.Equal(s.masterSecret, s1.masterSecret) || - !bytes.Equal(s.handshakeHash, s1.handshakeHash) { + !bytes.Equal(s.handshakeHash, s1.handshakeHash) || + s.extendedMasterSecret != s1.extendedMasterSecret { return false } @@ -56,6 +58,7 @@ func (s *sessionState) marshal() []byte { for _, cert := range s.certificates { length += 4 + len(cert) } + length++ ret := make([]byte, length) x := ret @@ -88,6 +91,11 @@ func (s *sessionState) marshal() []byte { x = x[4+len(cert):] } + if s.extendedMasterSecret { + x[0] = 1 + } + x = x[1:] + return ret } @@ -144,6 +152,16 @@ func (s *sessionState) unmarshal(data []byte) bool { data = data[certLen:] } + if len(data) < 1 { + return false + } + + s.extendedMasterSecret = false + if data[0] == 1 { + s.extendedMasterSecret = true + } + data = data[1:] + if len(data) > 0 { return false } diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 270fbfb..b717bd3 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -57,6 +57,9 @@ const BoolFlag kBoolFlags[] = { { "-shim-writes-first", &TestConfig::shim_writes_first }, { "-tls-d5-bug", &TestConfig::tls_d5_bug }, { "-expect-session-miss", &TestConfig::expect_session_miss }, + { "-expect-extended-master-secret", + &TestConfig::expect_extended_master_secret }, + { "-renegotiate", &TestConfig::renegotiate }, }; const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]); @@ -74,6 +77,8 @@ const StringFlag kStringFlags[] = { { "-expect-alpn", &TestConfig::expected_alpn }, { "-expect-advertised-alpn", &TestConfig::expected_advertised_alpn }, { "-select-alpn", &TestConfig::select_alpn }, + { "-psk", &TestConfig::psk }, + { "-psk-identity", &TestConfig::psk_identity }, }; const size_t kNumStringFlags = sizeof(kStringFlags) / sizeof(kStringFlags[0]); @@ -105,7 +110,9 @@ TestConfig::TestConfig() cookie_exchange(false), shim_writes_first(false), tls_d5_bug(false), - expect_session_miss(false) { + expect_session_miss(false), + expect_extended_master_secret(false), + renegotiate(false) { } bool ParseConfig(int argc, char **argv, TestConfig *out_config) { diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index acce504..2dc4dc1 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -53,6 +53,10 @@ struct TestConfig { std::string expected_advertised_alpn; std::string select_alpn; bool expect_session_miss; + bool expect_extended_master_secret; + std::string psk; + std::string psk_identity; + bool renegotiate; }; bool ParseConfig(int argc, char **argv, TestConfig *out_config); diff --git a/tool/CMakeLists.txt b/tool/CMakeLists.txt index e513c8b..e504838 100644 --- a/tool/CMakeLists.txt +++ b/tool/CMakeLists.txt @@ -11,7 +11,7 @@ add_executable( tool.cc ) -if (APPLE) +if (APPLE OR WIN32) target_link_libraries(bssl ssl crypto) else() target_link_libraries(bssl ssl crypto -lrt) diff --git a/tool/client.cc b/tool/client.cc index d7d9e22..21ea8ba 100644 --- a/tool/client.cc +++ b/tool/client.cc @@ -14,6 +14,9 @@ #include <openssl/base.h> +// TODO(davidben): bssl client does not work on Windows. +#if !defined(OPENSSL_WINDOWS) + #include <string> #include <vector> @@ -47,6 +50,10 @@ static const struct argument kArguments[] = { "The hostname and port of the server to connect to, e.g. foo.com:443", }, { + "-cipher", false, + "An OpenSSL-style cipher suite string that configures the offered ciphers", + }, + { "", false, "", }, }; @@ -265,6 +272,10 @@ bool Client(const std::vector<std::string> &args) { SSL_CTX_set_keylog_bio(ctx, keylog_bio); } + if (args_map.count("-cipher") != 0) { + SSL_CTX_set_cipher_list(ctx, args_map["-cipher"].c_str()); + } + int sock = -1; if (!Connect(&sock, args_map["-connect"])) { return false; @@ -291,3 +302,5 @@ bool Client(const std::vector<std::string> &args) { SSL_CTX_free(ctx); return ok; } + +#endif // !OPENSSL_WINDOWS
\ No newline at end of file diff --git a/tool/pkcs12.cc b/tool/pkcs12.cc index d35ba0b..fca8bb2 100644 --- a/tool/pkcs12.cc +++ b/tool/pkcs12.cc @@ -12,6 +12,8 @@ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include <openssl/base.h> + #include <memory> #include <string> #include <vector> @@ -21,7 +23,11 @@ #include <stdint.h> #include <sys/stat.h> #include <sys/types.h> +#if defined(OPENSSL_WINDOWS) +#include <io.h> +#else #include <unistd.h> +#endif #include <openssl/bytestring.h> #include <openssl/pem.h> @@ -31,6 +37,12 @@ #include "internal.h" +#if defined(OPENSSL_WINDOWS) +typedef int read_result_t; +#else +typedef ssize_t read_result_t; +#endif + static const struct argument kArguments[] = { { "-dump", false, "Dump the key and contents of the given file to stdout", @@ -64,7 +76,7 @@ bool DoPKCS12(const std::vector<std::string> &args) { const size_t size = st.st_size; std::unique_ptr<uint8_t[]> contents(new uint8_t[size]); - ssize_t n; + read_result_t n; size_t off = 0; do { n = read(fd, &contents[off], size - off); diff --git a/tool/tool.cc b/tool/tool.cc index a0866d7..f35cc7c 100644 --- a/tool/tool.cc +++ b/tool/tool.cc @@ -19,7 +19,9 @@ #include <openssl/ssl.h> +#if !defined(OPENSSL_WINDOWS) bool Client(const std::vector<std::string> &args); +#endif bool DoPKCS12(const std::vector<std::string> &args); bool Speed(const std::vector<std::string> &args); @@ -42,8 +44,10 @@ int main(int argc, char **argv) { if (tool == "speed") { return !Speed(args); +#if !defined(OPENSSL_WINDOWS) } else if (tool == "s_client" || tool == "client") { return !Client(args); +#endif } else if (tool == "pkcs12") { return !DoPKCS12(args); } else { diff --git a/util/all_tests.sh b/util/all_tests.sh index de6800f..f6188d1 100644 --- a/util/all_tests.sh +++ b/util/all_tests.sh @@ -36,7 +36,7 @@ TESTS=" ./crypto/ec/example_mul ./crypto/ecdsa/ecdsa_test ./crypto/err/err_test -./crypto/evp/example_sign +./crypto/evp/evp_test ./crypto/hmac/hmac_test ./crypto/lhash/lhash_test ./crypto/md5/md5_test |