From f78925a4b7dbff90991e8dedb56acd50523f6123 Mon Sep 17 00:00:00 2001 From: Hakase Date: Fri, 10 Aug 2018 09:36:18 +0900 Subject: [PATCH] Latest update - pre9 --- CHANGES | 10 ++ Configurations/windows-makefile.tmpl | 4 +- Configure | 5 +- INSTALL | 10 +- NOTES.ANDROID | 4 +- crypto/asn1/ameth_lib.c | 12 ++ crypto/asn1/asn_mime.c | 4 - crypto/asn1/tasn_utl.c | 35 ++-- crypto/ec/curve448/eddsa.c | 9 +- crypto/engine/eng_lib.c | 6 +- crypto/evp/build.info | 1 + crypto/evp/evp_pbe.c | 5 +- crypto/evp/m_sha3.c | 238 +++++++++++++++++++++++++- crypto/include/internal/x509_int.h | 1 + crypto/lhash/lhash.c | 14 +- crypto/lhash/lhash_lcl.h | 12 +- crypto/mem.c | 18 +- crypto/objects/obj_xref.c | 5 +- crypto/objects/objects.txt | 2 +- crypto/s390x_arch.h | 4 + crypto/s390xcpuid.pl | 42 +++++ crypto/x509/by_dir.c | 10 +- crypto/x509/x509_lu.c | 11 +- crypto/x509/x509_trs.c | 7 +- crypto/x509/x509_vpm.c | 9 +- crypto/x509/x509name.c | 8 +- crypto/x509/x_crl.c | 10 +- crypto/x509v3/pcy_cache.c | 10 +- crypto/x509v3/pcy_node.c | 3 - crypto/x509v3/pcy_tree.c | 2 +- crypto/x509v3/v3_lib.c | 2 - crypto/x509v3/v3_purp.c | 18 +- doc/man3/OPENSSL_LH_COMPFUNC.pod | 25 +-- fuzz/client.c | 4 +- fuzz/server.c | 4 +- include/internal/tsan_assist.h | 84 +++++++++ include/openssl/ssl3.h | 10 +- include/openssl/tls1.h | 8 +- ssl/record/rec_layer_s3.c | 17 +- ssl/record/ssl3_record.c | 9 +- ssl/record/ssl3_record_tls13.c | 8 +- ssl/s3_enc.c | 4 +- ssl/ssl_ciph.c | 5 +- ssl/ssl_init.c | 2 +- ssl/ssl_lib.c | 41 ++--- ssl/ssl_locl.h | 33 ++-- ssl/ssl_sess.c | 20 +-- ssl/statem/extensions.c | 8 +- ssl/statem/statem.c | 3 +- ssl/statem/statem.h | 19 +- ssl/statem/statem_clnt.c | 18 +- ssl/statem/statem_lib.c | 32 ++-- ssl/statem/statem_srvr.c | 42 +++-- ssl/t1_enc.c | 4 +- ssl/tls13_enc.c | 11 +- test/asn1_internal_test.c | 18 +- test/recipes/70-test_tls13alerts.t | 56 ++++++ test/recipes/70-test_tls13downgrade.t | 42 +++-- test/sanitytest.c | 6 + test/test_test.c | 6 - util/perl/TLSProxy/Alert.pm | 51 ++++++ util/perl/TLSProxy/Message.pm | 17 ++ util/perl/TLSProxy/Record.pm | 4 +- 63 files changed, 863 insertions(+), 279 deletions(-) create mode 100644 include/internal/tsan_assist.h create mode 100644 test/recipes/70-test_tls13alerts.t create mode 100644 util/perl/TLSProxy/Alert.pm diff --git a/CHANGES b/CHANGES index 78059129..8c67dab6 100644 --- a/CHANGES +++ b/CHANGES @@ -9,6 +9,16 @@ Changes between 1.1.0h and 1.1.1 [xx XXX xxxx] + *) s390x assembly pack: add (improved) hardware-support for the following + cryptographic primitives: sha3, shake, aes-gcm, aes-ccm, aes-ctr, aes-ofb, + aes-cfb/cfb8, aes-ecb. + [Patrick Steuer] + + *) Make EVP_PKEY_asn1_new() a bit stricter about its input. A NULL pem_str + parameter is no longer accepted, as it leads to a corrupt table. NULL + pem_str is reserved for alias entries only. + [Richard Levitte] + *) Use the new ec_scalar_mul_ladder scaffold to implement a specialized ladder step for prime curves. The new implementation is based on formulae from differential addition-and-doubling in homogeneous projective coordinates diff --git a/Configurations/windows-makefile.tmpl b/Configurations/windows-makefile.tmpl index 76efa410..f7d8e273 100644 --- a/Configurations/windows-makefile.tmpl +++ b/Configurations/windows-makefile.tmpl @@ -93,8 +93,8 @@ GENERATED={- # common0.tmpl provides @generated @generated) -} INSTALL_LIBS={- join(" ", map { quotify1(lib($_)) } @{$unified_info{install}->{libraries}}) -} -INSTALL_SHLIBS={- join(" ", map { quotify1(shlib($_)) } @{$unified_info{install}->{libraries}}) -} -INSTALL_SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; quotify1(shlib($_)) } @{$unified_info{install}->{libraries}}) -} +INSTALL_SHLIBS={- join(" ", map { quotify_l(shlib($_)) } @{$unified_info{install}->{libraries}}) -} +INSTALL_SHLIBPDBS={- join(" ", map { local $shlibext = ".pdb"; quotify_l(shlib($_)) } @{$unified_info{install}->{libraries}}) -} INSTALL_ENGINES={- join(" ", map { quotify1(dso($_)) } @{$unified_info{install}->{engines}}) -} INSTALL_ENGINEPDBS={- join(" ", map { local $dsoext = ".pdb"; quotify1(dso($_)) } @{$unified_info{install}->{engines}}) -} INSTALL_PROGRAMS={- join(" ", map { quotify1($_.$exeext) } grep { !m|^test\\| } @{$unified_info{install}->{programs}}) -} diff --git a/Configure b/Configure index 9f728b92..05927127 100755 --- a/Configure +++ b/Configure @@ -1034,11 +1034,12 @@ if ($d) { $target = $t; } } + +&usage if !$table{$target} || $table{$target}->{template}; + $config{target} = $target; my %target = resolve_config($target); -&usage if (!%target || $target{template}); - foreach (keys %target_attr_translate) { $target{$target_attr_translate{$_}} = $target{$_} if $target{$_}; diff --git a/INSTALL b/INSTALL index 98c34d6a..34023dcd 100644 --- a/INSTALL +++ b/INSTALL @@ -145,8 +145,8 @@ put together one-size-fits-all instructions. You might have to pass more flags or set up environment variables to actually make it work. Android and iOS cases are - discussed in corresponding Configurations/10-main.cf - sections. But there are cases when this option alone is + discussed in corresponding Configurations/15-*.conf + files. But there are cases when this option alone is sufficient. For example to build the mingw64 target on Linux "--cross-compile-prefix=x86_64-w64-mingw32-" works. Naturally provided that mingw packages are @@ -157,10 +157,12 @@ "--cross-compile-prefix=mipsel-linux-gnu-" suffices in such case. Needless to mention that you have to invoke ./Configure, not ./config, and pass your target - name explicitly. + name explicitly. Also, note that --openssldir refers + to target's file system, not one you are building on. --debug - Build OpenSSL with debugging symbols. + Build OpenSSL with debugging symbols and zero optimization + level. --libdir=DIR The name of the directory under the top of the installation diff --git a/NOTES.ANDROID b/NOTES.ANDROID index 103ed87f..d13f47d6 100644 --- a/NOTES.ANDROID +++ b/NOTES.ANDROID @@ -46,8 +46,8 @@ One can engage clang by adjusting PATH to cover NDK's clang. Just keep in mind that if you miss it, Configure will try to use gcc... Also, PATH would need even further adjustment to cover unprefixed, yet - target-specific, ar and ranlib (or not, if you use binutils-multiarch - on your Linux). + target-specific, ar and ranlib. It's possible that you don't need to + bother, if binutils-multiarch is installed on your Linux system. Running tests (on Linux) ------------------------ diff --git a/crypto/asn1/ameth_lib.c b/crypto/asn1/ameth_lib.c index 9b3274bc..9a164414 100644 --- a/crypto/asn1/ameth_lib.c +++ b/crypto/asn1/ameth_lib.c @@ -216,6 +216,18 @@ EVP_PKEY_ASN1_METHOD *EVP_PKEY_asn1_new(int id, int flags, goto err; } + /* + * One of the following must be true: + * + * pem_str == NULL AND ASN1_PKEY_ALIAS is set + * pem_str != NULL AND ASN1_PKEY_ALIAS is clear + * + * Anything else is an error and may lead to a corrupt ASN1 method table + */ + if (!((pem_str == NULL && (flags & ASN1_PKEY_ALIAS) != 0) + || (pem_str != NULL && (flags & ASN1_PKEY_ALIAS) == 0))) + goto err; + if (pem_str) { ameth->pem_str = OPENSSL_strdup(pem_str); if (!ameth->pem_str) diff --git a/crypto/asn1/asn_mime.c b/crypto/asn1/asn_mime.c index aa92a8e1..dfd5be63 100644 --- a/crypto/asn1/asn_mime.c +++ b/crypto/asn1/asn_mime.c @@ -883,8 +883,6 @@ static MIME_HEADER *mime_hdr_find(STACK_OF(MIME_HEADER) *hdrs, const char *name) htmp.params = NULL; idx = sk_MIME_HEADER_find(hdrs, &htmp); - if (idx < 0) - return NULL; return sk_MIME_HEADER_value(hdrs, idx); } @@ -896,8 +894,6 @@ static MIME_PARAM *mime_param_find(MIME_HEADER *hdr, const char *name) param.param_name = (char *)name; param.param_value = NULL; idx = sk_MIME_PARAM_find(hdr->params, ¶m); - if (idx < 0) - return NULL; return sk_MIME_PARAM_value(hdr->params, idx); } diff --git a/crypto/asn1/tasn_utl.c b/crypto/asn1/tasn_utl.c index a93fd871..7ceecffc 100644 --- a/crypto/asn1/tasn_utl.c +++ b/crypto/asn1/tasn_utl.c @@ -58,8 +58,10 @@ int asn1_set_choice_selector(ASN1_VALUE **pval, int value, int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it) { const ASN1_AUX *aux; - int *lck, ret; + CRYPTO_REF_COUNT *lck; CRYPTO_RWLOCK **lock; + int ret = -1; + if ((it->itype != ASN1_ITYPE_SEQUENCE) && (it->itype != ASN1_ITYPE_NDEF_SEQUENCE)) return 0; @@ -68,25 +70,34 @@ int asn1_do_lock(ASN1_VALUE **pval, int op, const ASN1_ITEM *it) return 0; lck = offset2ptr(*pval, aux->ref_offset); lock = offset2ptr(*pval, aux->ref_lock); - if (op == 0) { - *lck = 1; + + switch (op) { + case 0: + *lck = ret = 1; *lock = CRYPTO_THREAD_lock_new(); if (*lock == NULL) { ASN1err(ASN1_F_ASN1_DO_LOCK, ERR_R_MALLOC_FAILURE); return -1; } - return 1; - } - if (CRYPTO_atomic_add(lck, op, &ret, *lock) < 0) - return -1; /* failed */ + break; + case 1: + if (!CRYPTO_UP_REF(lck, &ret, *lock)) + return -1; + break; + case -1: + if (!CRYPTO_DOWN_REF(lck, &ret, *lock)) + return -1; /* failed */ #ifdef REF_PRINT - fprintf(stderr, "%p:%4d:%s\n", it, *lck, it->sname); + fprintf(stderr, "%p:%4d:%s\n", it, ret, it->sname); #endif - REF_ASSERT_ISNT(ret < 0); - if (ret == 0) { - CRYPTO_THREAD_lock_free(*lock); - *lock = NULL; + REF_ASSERT_ISNT(ret < 0); + if (ret == 0) { + CRYPTO_THREAD_lock_free(*lock); + *lock = NULL; + } + break; } + return ret; } diff --git a/crypto/ec/curve448/eddsa.c b/crypto/ec/curve448/eddsa.c index 85565a8d..909413a5 100644 --- a/crypto/ec/curve448/eddsa.c +++ b/crypto/ec/curve448/eddsa.c @@ -63,8 +63,7 @@ static c448_error_t hash_init_with_dom(EVP_MD_CTX *hashctx, uint8_t prehashed, if (!EVP_DigestInit_ex(hashctx, EVP_shake256(), NULL) || !EVP_DigestUpdate(hashctx, dom_s, strlen(dom_s)) || !EVP_DigestUpdate(hashctx, dom, sizeof(dom)) - || (context_len > 0 - && !EVP_DigestUpdate(hashctx, context, context_len))) + || !EVP_DigestUpdate(hashctx, context, context_len)) return C448_FAILURE; return C448_SUCCESS; @@ -161,8 +160,7 @@ c448_error_t c448_ed448_sign( || !EVP_DigestUpdate(hashctx, expanded + EDDSA_448_PRIVATE_BYTES, EDDSA_448_PRIVATE_BYTES) - || (message_len > 0 - && !EVP_DigestUpdate(hashctx, message, message_len))) { + || !EVP_DigestUpdate(hashctx, message, message_len)) { OPENSSL_cleanse(expanded, sizeof(expanded)); goto err; } @@ -202,8 +200,7 @@ c448_error_t c448_ed448_sign( if (!hash_init_with_dom(hashctx, prehashed, 0, context, context_len) || !EVP_DigestUpdate(hashctx, nonce_point, sizeof(nonce_point)) || !EVP_DigestUpdate(hashctx, pubkey, EDDSA_448_PUBLIC_BYTES) - || (message_len > 0 - && !EVP_DigestUpdate(hashctx, message, message_len)) + || !EVP_DigestUpdate(hashctx, message, message_len) || !EVP_DigestFinalXOF(hashctx, challenge, sizeof(challenge))) goto err; diff --git a/crypto/engine/eng_lib.c b/crypto/engine/eng_lib.c index 90283197..3ef3aae2 100644 --- a/crypto/engine/eng_lib.c +++ b/crypto/engine/eng_lib.c @@ -75,14 +75,10 @@ int engine_free_util(ENGINE *e, int not_locked) if (e == NULL) return 1; -#ifdef HAVE_ATOMICS - CRYPTO_DOWN_REF(&e->struct_ref, &i, global_engine_lock); -#else if (not_locked) - CRYPTO_atomic_add(&e->struct_ref, -1, &i, global_engine_lock); + CRYPTO_DOWN_REF(&e->struct_ref, &i, global_engine_lock); else i = --e->struct_ref; -#endif engine_ref_debug(e, 0, -1); if (i > 0) return 1; diff --git a/crypto/evp/build.info b/crypto/evp/build.info index 03057380..cc33ac3c 100644 --- a/crypto/evp/build.info +++ b/crypto/evp/build.info @@ -22,3 +22,4 @@ INCLUDE[e_camellia.o]=.. ../modes INCLUDE[e_sm4.o]=.. ../modes INCLUDE[e_des.o]=.. INCLUDE[e_des3.o]=.. +INCLUDE[m_sha3.o]=.. diff --git a/crypto/evp/evp_pbe.c b/crypto/evp/evp_pbe.c index 0cebd2df..f80fc064 100644 --- a/crypto/evp/evp_pbe.c +++ b/crypto/evp/evp_pbe.c @@ -217,10 +217,9 @@ int EVP_PBE_find(int type, int pbe_nid, pbelu.pbe_type = type; pbelu.pbe_nid = pbe_nid; - if (pbe_algs) { + if (pbe_algs != NULL) { i = sk_EVP_PBE_CTL_find(pbe_algs, &pbelu); - if (i != -1) - pbetmp = sk_EVP_PBE_CTL_value(pbe_algs, i); + pbetmp = sk_EVP_PBE_CTL_value(pbe_algs, i); } if (pbetmp == NULL) { pbetmp = OBJ_bsearch_pbe2(&pbelu, builtin_pbe, OSSL_NELEM(builtin_pbe)); diff --git a/crypto/evp/m_sha3.c b/crypto/evp/m_sha3.c index cf902e74..729622b8 100644 --- a/crypto/evp/m_sha3.c +++ b/crypto/evp/m_sha3.c @@ -66,6 +66,9 @@ static int sha3_update(EVP_MD_CTX *evp_ctx, const void *_inp, size_t len) size_t bsz = ctx->block_size; size_t num, rem; + if (len == 0) + return 1; + if ((num = ctx->num) != 0) { /* process intermediate buffer? */ rem = bsz - num; @@ -134,7 +137,227 @@ static int shake_ctrl(EVP_MD_CTX *evp_ctx, int cmd, int p1, void *p2) } } -#define EVP_MD_SHA3(bitlen) \ +#if defined(OPENSSL_CPUID_OBJ) && defined(__s390__) && defined(KECCAK1600_ASM) +/* + * IBM S390X support + */ +# include "s390x_arch.h" + +# define S390X_SHA3_FC(ctx) ((ctx)->pad) + +# define S390X_sha3_224_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHA3_224)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHA3_224))) +# define S390X_sha3_256_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHA3_256)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHA3_256))) +# define S390X_sha3_384_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHA3_384)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHA3_384))) +# define S390X_sha3_512_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHA3_512)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHA3_512))) +# define S390X_shake128_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHAKE_128)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHAKE_128))) +# define S390X_shake256_CAPABLE ((OPENSSL_s390xcap_P.kimd[0] & \ + S390X_CAPBIT(S390X_SHAKE_256)) && \ + (OPENSSL_s390xcap_P.klmd[0] & \ + S390X_CAPBIT(S390X_SHAKE_256))) + +/* Convert md-size to block-size. */ +# define S390X_KECCAK1600_BSZ(n) ((KECCAK1600_WIDTH - ((n) << 1)) >> 3) + +static int s390x_sha3_init(EVP_MD_CTX *evp_ctx) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + const size_t bsz = evp_ctx->digest->block_size; + + /*- + * KECCAK1600_CTX structure's pad field is used to store the KIMD/KLMD + * function code. + */ + switch (bsz) { + case S390X_KECCAK1600_BSZ(224): + ctx->pad = S390X_SHA3_224; + break; + case S390X_KECCAK1600_BSZ(256): + ctx->pad = S390X_SHA3_256; + break; + case S390X_KECCAK1600_BSZ(384): + ctx->pad = S390X_SHA3_384; + break; + case S390X_KECCAK1600_BSZ(512): + ctx->pad = S390X_SHA3_512; + break; + default: + return 0; + } + + memset(ctx->A, 0, sizeof(ctx->A)); + ctx->num = 0; + ctx->block_size = bsz; + ctx->md_size = evp_ctx->digest->md_size; + return 1; +} + +static int s390x_shake_init(EVP_MD_CTX *evp_ctx) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + const size_t bsz = evp_ctx->digest->block_size; + + /*- + * KECCAK1600_CTX structure's pad field is used to store the KIMD/KLMD + * function code. + */ + switch (bsz) { + case S390X_KECCAK1600_BSZ(128): + ctx->pad = S390X_SHAKE_128; + break; + case S390X_KECCAK1600_BSZ(256): + ctx->pad = S390X_SHAKE_256; + break; + default: + return 0; + } + + memset(ctx->A, 0, sizeof(ctx->A)); + ctx->num = 0; + ctx->block_size = bsz; + ctx->md_size = evp_ctx->digest->md_size; + return 1; +} + +static int s390x_sha3_update(EVP_MD_CTX *evp_ctx, const void *_inp, size_t len) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + const unsigned char *inp = _inp; + const size_t bsz = ctx->block_size; + size_t num, rem; + + if (len == 0) + return 1; + + if ((num = ctx->num) != 0) { + rem = bsz - num; + + if (len < rem) { + memcpy(ctx->buf + num, inp, len); + ctx->num += len; + return 1; + } + memcpy(ctx->buf + num, inp, rem); + inp += rem; + len -= rem; + s390x_kimd(ctx->buf, bsz, ctx->pad, ctx->A); + ctx->num = 0; + } + rem = len % bsz; + + s390x_kimd(inp, len - rem, ctx->pad, ctx->A); + + if (rem) { + memcpy(ctx->buf, inp + len - rem, rem); + ctx->num = rem; + } + return 1; +} + +static int s390x_sha3_final(EVP_MD_CTX *evp_ctx, unsigned char *md) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + + s390x_klmd(ctx->buf, ctx->num, NULL, 0, ctx->pad, ctx->A); + memcpy(md, ctx->A, ctx->md_size); + return 1; +} + +static int s390x_shake_final(EVP_MD_CTX *evp_ctx, unsigned char *md) +{ + KECCAK1600_CTX *ctx = evp_ctx->md_data; + + s390x_klmd(ctx->buf, ctx->num, md, ctx->md_size, ctx->pad, ctx->A); + return 1; +} + +# define EVP_MD_SHA3(bitlen) \ +const EVP_MD *EVP_sha3_##bitlen(void) \ +{ \ + static const EVP_MD s390x_sha3_##bitlen##_md = { \ + NID_sha3_##bitlen, \ + NID_RSA_SHA3_##bitlen, \ + bitlen / 8, \ + EVP_MD_FLAG_DIGALGID_ABSENT, \ + s390x_sha3_init, \ + s390x_sha3_update, \ + s390x_sha3_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + }; \ + static const EVP_MD sha3_##bitlen##_md = { \ + NID_sha3_##bitlen, \ + NID_RSA_SHA3_##bitlen, \ + bitlen / 8, \ + EVP_MD_FLAG_DIGALGID_ABSENT, \ + sha3_init, \ + sha3_update, \ + sha3_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + }; \ + return S390X_sha3_##bitlen##_CAPABLE ? \ + &s390x_sha3_##bitlen##_md : \ + &sha3_##bitlen##_md; \ +} + +# define EVP_MD_SHAKE(bitlen) \ +const EVP_MD *EVP_shake##bitlen(void) \ +{ \ + static const EVP_MD s390x_shake##bitlen##_md = { \ + NID_shake##bitlen, \ + 0, \ + bitlen / 8, \ + EVP_MD_FLAG_XOF, \ + s390x_shake_init, \ + s390x_sha3_update, \ + s390x_shake_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + shake_ctrl \ + }; \ + static const EVP_MD shake##bitlen##_md = { \ + NID_shake##bitlen, \ + 0, \ + bitlen / 8, \ + EVP_MD_FLAG_XOF, \ + shake_init, \ + sha3_update, \ + sha3_final, \ + NULL, \ + NULL, \ + (KECCAK1600_WIDTH - bitlen * 2) / 8, \ + sizeof(KECCAK1600_CTX), \ + shake_ctrl \ + }; \ + return S390X_shake##bitlen##_CAPABLE ? \ + &s390x_shake##bitlen##_md : \ + &shake##bitlen##_md; \ +} + +#else + +# define EVP_MD_SHA3(bitlen) \ const EVP_MD *EVP_sha3_##bitlen(void) \ { \ static const EVP_MD sha3_##bitlen##_md = { \ @@ -153,12 +376,7 @@ const EVP_MD *EVP_sha3_##bitlen(void) \ return &sha3_##bitlen##_md; \ } -EVP_MD_SHA3(224) -EVP_MD_SHA3(256) -EVP_MD_SHA3(384) -EVP_MD_SHA3(512) - -#define EVP_MD_SHAKE(bitlen) \ +# define EVP_MD_SHAKE(bitlen) \ const EVP_MD *EVP_shake##bitlen(void) \ { \ static const EVP_MD shake##bitlen##_md = { \ @@ -177,6 +395,12 @@ const EVP_MD *EVP_shake##bitlen(void) \ }; \ return &shake##bitlen##_md; \ } +#endif + +EVP_MD_SHA3(224) +EVP_MD_SHA3(256) +EVP_MD_SHA3(384) +EVP_MD_SHA3(512) EVP_MD_SHAKE(128) EVP_MD_SHAKE(256) diff --git a/crypto/include/internal/x509_int.h b/crypto/include/internal/x509_int.h index 124cc533..1638de4c 100644 --- a/crypto/include/internal/x509_int.h +++ b/crypto/include/internal/x509_int.h @@ -182,6 +182,7 @@ struct x509_st { unsigned char sha1_hash[SHA_DIGEST_LENGTH]; X509_CERT_AUX *aux; CRYPTO_RWLOCK *lock; + volatile int ex_cached; } /* X509 */ ; /* diff --git a/crypto/lhash/lhash.c b/crypto/lhash/lhash.c index dca50072..f7ac9d02 100644 --- a/crypto/lhash/lhash.c +++ b/crypto/lhash/lhash.c @@ -157,16 +157,18 @@ void *OPENSSL_LH_retrieve(OPENSSL_LHASH *lh, const void *data) OPENSSL_LH_NODE **rn; void *ret; - lh->error = 0; + tsan_store((TSAN_QUALIFIER int *)&lh->error, 0); + rn = getrn(lh, data, &hash); if (*rn == NULL) { - lh->num_retrieve_miss++; + tsan_counter(&lh->num_retrieve_miss); return NULL; } else { ret = (*rn)->data; - lh->num_retrieve++; + tsan_counter(&lh->num_retrieve); } + return ret; } @@ -296,7 +298,7 @@ static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh, OPENSSL_LH_COMPFUNC cf; hash = (*(lh->hash)) (data); - lh->num_hash_calls++; + tsan_counter(&lh->num_hash_calls); *rhash = hash; nn = hash % lh->pmax; @@ -306,12 +308,12 @@ static OPENSSL_LH_NODE **getrn(OPENSSL_LHASH *lh, cf = lh->comp; ret = &(lh->b[(int)nn]); for (n1 = *ret; n1 != NULL; n1 = n1->next) { - lh->num_hash_comps++; + tsan_counter(&lh->num_hash_comps); if (n1->hash != hash) { ret = &(n1->next); continue; } - lh->num_comp_calls++; + tsan_counter(&lh->num_comp_calls); if (cf(n1->data, data) == 0) break; ret = &(n1->next); diff --git a/crypto/lhash/lhash_lcl.h b/crypto/lhash/lhash_lcl.h index 78691eb6..8f792329 100644 --- a/crypto/lhash/lhash_lcl.h +++ b/crypto/lhash/lhash_lcl.h @@ -8,6 +8,8 @@ */ #include +#include "internal/tsan_assist.h" + struct lhash_node_st { void *data; struct lhash_node_st *next; @@ -29,14 +31,14 @@ struct lhash_st { unsigned long num_expand_reallocs; unsigned long num_contracts; unsigned long num_contract_reallocs; - unsigned long num_hash_calls; - unsigned long num_comp_calls; + TSAN_QUALIFIER unsigned long num_hash_calls; + TSAN_QUALIFIER unsigned long num_comp_calls; unsigned long num_insert; unsigned long num_replace; unsigned long num_delete; unsigned long num_no_delete; - unsigned long num_retrieve; - unsigned long num_retrieve_miss; - unsigned long num_hash_comps; + TSAN_QUALIFIER unsigned long num_retrieve; + TSAN_QUALIFIER unsigned long num_retrieve_miss; + TSAN_QUALIFIER unsigned long num_hash_comps; int error; }; diff --git a/crypto/mem.c b/crypto/mem.c index 33644678..780053ff 100644 --- a/crypto/mem.c +++ b/crypto/mem.c @@ -31,13 +31,13 @@ static void (*free_impl)(void *, const char *, int) = CRYPTO_free; #ifndef OPENSSL_NO_CRYPTO_MDEBUG -static int malloc_count; -static int realloc_count; -static int free_count; -static int dummy; +# include "internal/tsan_assist.h" -# define INCREMENT(x) CRYPTO_atomic_add(&x, 1, &dummy, memdbg_lock) -# define GET(ret, val) CRYPTO_atomic_read(&val, ret, memdbg_lock) +static TSAN_QUALIFIER int malloc_count; +static TSAN_QUALIFIER int realloc_count; +static TSAN_QUALIFIER int free_count; + +# define INCREMENT(x) tsan_counter(&(x)) static char *md_failstring; static long md_count; @@ -98,11 +98,11 @@ void CRYPTO_get_mem_functions( void CRYPTO_get_alloc_counts(int *mcount, int *rcount, int *fcount) { if (mcount != NULL) - GET(mcount, malloc_count); + *mcount = tsan_load(&malloc_count); if (rcount != NULL) - GET(rcount, realloc_count); + *rcount = tsan_load(&realloc_count); if (fcount != NULL) - GET(fcount, free_count); + *fcount = tsan_load(&free_count); } /* diff --git a/crypto/objects/obj_xref.c b/crypto/objects/obj_xref.c index 42d204ca..faf59eb2 100644 --- a/crypto/objects/obj_xref.c +++ b/crypto/objects/obj_xref.c @@ -46,10 +46,9 @@ int OBJ_find_sigid_algs(int signid, int *pdig_nid, int *ppkey_nid) const nid_triple *rv = NULL; tmp.sign_id = signid; - if (sig_app) { + if (sig_app != NULL) { int idx = sk_nid_triple_find(sig_app, &tmp); - if (idx >= 0) - rv = sk_nid_triple_value(sig_app, idx); + rv = sk_nid_triple_value(sig_app, idx); } #ifndef OBJ_XREF_TEST2 if (rv == NULL) { diff --git a/crypto/objects/objects.txt b/crypto/objects/objects.txt index f6b5f33d..6dbc41ce 100644 --- a/crypto/objects/objects.txt +++ b/crypto/objects/objects.txt @@ -1605,7 +1605,7 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme id-pkinit 4 : pkInitClientAuth : PKINIT Client Auth id-pkinit 5 : pkInitKDC : Signing KDC Response -# New algorithms from draft-ietf-curdle-pkix-04 +# From RFC8410 1 3 101 110 : X25519 1 3 101 111 : X448 1 3 101 112 : ED25519 diff --git a/crypto/s390x_arch.h b/crypto/s390x_arch.h index 50421544..4a775a92 100644 --- a/crypto/s390x_arch.h +++ b/crypto/s390x_arch.h @@ -12,6 +12,10 @@ # ifndef __ASSEMBLER__ +void s390x_kimd(const unsigned char *in, size_t len, unsigned int fc, + void *param); +void s390x_klmd(const unsigned char *in, size_t inlen, unsigned char *out, + size_t outlen, unsigned int fc, void *param); void s390x_km(const unsigned char *in, size_t len, unsigned char *out, unsigned int fc, void *param); void s390x_kmac(const unsigned char *in, size_t len, unsigned int fc, diff --git a/crypto/s390xcpuid.pl b/crypto/s390xcpuid.pl index e7afb8dc..ec700a47 100755 --- a/crypto/s390xcpuid.pl +++ b/crypto/s390xcpuid.pl @@ -262,6 +262,48 @@ OPENSSL_vx_probe: .size OPENSSL_vx_probe,.-OPENSSL_vx_probe ___ +{ +################ +# void s390x_kimd(const unsigned char *in, size_t len, unsigned int fc, +# void *param) +my ($in,$len,$fc,$param) = map("%r$_",(2..5)); +$code.=<<___; +.globl s390x_kimd +.type s390x_kimd,\@function +.align 16 +s390x_kimd: + llgfr %r0,$fc + lgr %r1,$param + + .long 0xb93e0002 # kimd %r0,%r2 + brc 1,.-4 # pay attention to "partial completion" + + br $ra +.size s390x_kimd,.-s390x_kimd +___ +} + +{ +################ +# void s390x_klmd(const unsigned char *in, size_t inlen, unsigned char *out, +# size_t outlen, unsigned int fc, void *param) +my ($in,$inlen,$out,$outlen,$fc) = map("%r$_",(2..6)); +$code.=<<___; +.globl s390x_klmd +.type s390x_klmd,\@function +.align 32 +s390x_klmd: + llgfr %r0,$fc + l${g} %r1,$stdframe($sp) + + .long 0xb93f0042 # klmd %r4,%r2 + brc 1,.-4 # pay attention to "partial completion" + + br $ra +.size s390x_klmd,.-s390x_klmd +___ +} + ################ # void s390x_km(const unsigned char *in, size_t len, unsigned char *out, # unsigned int fc, void *param) diff --git a/crypto/x509/by_dir.c b/crypto/x509/by_dir.c index 9d5a571c..11ac52ce 100644 --- a/crypto/x509/by_dir.c +++ b/crypto/x509/by_dir.c @@ -329,10 +329,7 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, */ CRYPTO_THREAD_write_lock(ctx->lock); j = sk_X509_OBJECT_find(xl->store_ctx->objs, &stmp); - if (j != -1) - tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); - else - tmp = NULL; + tmp = sk_X509_OBJECT_value(xl->store_ctx->objs, j); CRYPTO_THREAD_unlock(ctx->lock); /* If a CRL, update the last file suffix added for this */ @@ -343,11 +340,10 @@ static int get_cert_by_subject(X509_LOOKUP *xl, X509_LOOKUP_TYPE type, * Look for entry again in case another thread added an entry * first. */ - if (!hent) { + if (hent == NULL) { htmp.hash = h; idx = sk_BY_DIR_HASH_find(ent->hashes, &htmp); - if (idx >= 0) - hent = sk_BY_DIR_HASH_value(ent->hashes, idx); + hent = sk_BY_DIR_HASH_value(ent->hashes, idx); } if (hent == NULL) { hent = OPENSSL_malloc(sizeof(*hent)); diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index e7b1b852..be39015b 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -619,17 +619,18 @@ STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *ctx, X509_NAME *nm) X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, X509_OBJECT *x) { - int idx, i; + int idx, i, num; X509_OBJECT *obj; + idx = sk_X509_OBJECT_find(h, x); - if (idx == -1) + if (idx < 0) return NULL; if ((x->type != X509_LU_X509) && (x->type != X509_LU_CRL)) return sk_X509_OBJECT_value(h, idx); - for (i = idx; i < sk_X509_OBJECT_num(h); i++) { + for (i = idx, num = sk_X509_OBJECT_num(h); i < num; i++) { obj = sk_X509_OBJECT_value(h, i); - if (x509_object_cmp - ((const X509_OBJECT **)&obj, (const X509_OBJECT **)&x)) + if (x509_object_cmp((const X509_OBJECT **)&obj, + (const X509_OBJECT **)&x)) return NULL; if (x->type == X509_LU_X509) { if (!X509_cmp(obj->data.x509, x->data.x509)) diff --git a/crypto/x509/x509_trs.c b/crypto/x509/x509_trs.c index a9bb88d1..d2b0a8af 100644 --- a/crypto/x509/x509_trs.c +++ b/crypto/x509/x509_trs.c @@ -98,13 +98,14 @@ int X509_TRUST_get_by_id(int id) { X509_TRUST tmp; int idx; + if ((id >= X509_TRUST_MIN) && (id <= X509_TRUST_MAX)) return id - X509_TRUST_MIN; - tmp.trust = id; - if (!trtable) + if (trtable == NULL) return -1; + tmp.trust = id; idx = sk_X509_TRUST_find(trtable, &tmp); - if (idx == -1) + if (idx < 0) return -1; return idx + X509_TRUST_COUNT; } diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c index 16d27f91..aea18629 100644 --- a/crypto/x509/x509_vpm.c +++ b/crypto/x509/x509_vpm.c @@ -555,10 +555,9 @@ int X509_VERIFY_PARAM_add0_table(X509_VERIFY_PARAM *param) return 0; } else { idx = sk_X509_VERIFY_PARAM_find(param_table, param); - if (idx != -1) { - ptmp = sk_X509_VERIFY_PARAM_value(param_table, idx); + if (idx >= 0) { + ptmp = sk_X509_VERIFY_PARAM_delete(param_table, idx); X509_VERIFY_PARAM_free(ptmp); - (void)sk_X509_VERIFY_PARAM_delete(param_table, idx); } } if (!sk_X509_VERIFY_PARAM_push(param_table, param)) @@ -588,9 +587,9 @@ const X509_VERIFY_PARAM *X509_VERIFY_PARAM_lookup(const char *name) X509_VERIFY_PARAM pm; pm.name = (char *)name; - if (param_table) { + if (param_table != NULL) { idx = sk_X509_VERIFY_PARAM_find(param_table, &pm); - if (idx != -1) + if (idx >= 0) return sk_X509_VERIFY_PARAM_value(param_table, idx); } return OBJ_bsearch_table(&pm, default_table, OSSL_NELEM(default_table)); diff --git a/crypto/x509/x509name.c b/crypto/x509/x509name.c index 46668244..64a73e79 100644 --- a/crypto/x509/x509name.c +++ b/crypto/x509/x509name.c @@ -26,8 +26,8 @@ int X509_NAME_get_text_by_NID(X509_NAME *name, int nid, char *buf, int len) return X509_NAME_get_text_by_OBJ(name, obj, buf, len); } -int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf, - int len) +int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, + char *buf, int len) { int i; const ASN1_STRING *data; @@ -36,9 +36,11 @@ int X509_NAME_get_text_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, char *buf if (i < 0) return -1; data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i)); - i = (data->length > (len - 1)) ? (len - 1) : data->length; if (buf == NULL) return data->length; + if (len <= 0) + return 0; + i = (data->length > (len - 1)) ? (len - 1) : data->length; memcpy(buf, data->data, i); buf[i] = '\0'; return i; diff --git a/crypto/x509/x_crl.c b/crypto/x509/x_crl.c index c0099e0f..10733b58 100644 --- a/crypto/x509/x_crl.c +++ b/crypto/x509/x_crl.c @@ -383,8 +383,11 @@ static int def_crl_lookup(X509_CRL *crl, X509_NAME *issuer) { X509_REVOKED rtmp, *rev; - int idx; - rtmp.serialNumber = *serial; + int idx, num; + + if (crl->crl.revoked == NULL) + return 0; + /* * Sort revoked into serial number order if not already sorted. Do this * under a lock to avoid race condition. @@ -394,11 +397,12 @@ static int def_crl_lookup(X509_CRL *crl, sk_X509_REVOKED_sort(crl->crl.revoked); CRYPTO_THREAD_unlock(crl->lock); } + rtmp.serialNumber = *serial; idx = sk_X509_REVOKED_find(crl->crl.revoked, &rtmp); if (idx < 0) return 0; /* Need to look for matching name */ - for (; idx < sk_X509_REVOKED_num(crl->crl.revoked); idx++) { + for (num = sk_X509_REVOKED_num(crl->crl.revoked); idx < num; idx++) { rev = sk_X509_REVOKED_value(crl->crl.revoked, idx); if (ASN1_INTEGER_cmp(&rev->serialNumber, serial)) return 0; diff --git a/crypto/x509v3/pcy_cache.c b/crypto/x509v3/pcy_cache.c index 7873a424..623870b1 100644 --- a/crypto/x509v3/pcy_cache.c +++ b/crypto/x509v3/pcy_cache.c @@ -26,19 +26,19 @@ static int policy_cache_set_int(long *out, ASN1_INTEGER *value); static int policy_cache_create(X509 *x, CERTIFICATEPOLICIES *policies, int crit) { - int i, ret = 0; + int i, num, ret = 0; X509_POLICY_CACHE *cache = x->policy_cache; X509_POLICY_DATA *data = NULL; POLICYINFO *policy; - if (sk_POLICYINFO_num(policies) == 0) + if ((num = sk_POLICYINFO_num(policies)) <= 0) goto bad_policy; cache->data = sk_X509_POLICY_DATA_new(policy_data_cmp); if (cache->data == NULL) { X509V3err(X509V3_F_POLICY_CACHE_CREATE, ERR_R_MALLOC_FAILURE); goto just_cleanup; } - for (i = 0; i < sk_POLICYINFO_num(policies); i++) { + for (i = 0; i < num; i++) { policy = sk_POLICYINFO_value(policies, i); data = policy_data_new(policy, NULL, crit); if (data == NULL) { @@ -54,7 +54,7 @@ static int policy_cache_create(X509 *x, goto bad_policy; } cache->anyPolicy = data; - } else if (sk_X509_POLICY_DATA_find(cache->data, data) != -1) { + } else if (sk_X509_POLICY_DATA_find(cache->data, data) >=0 ) { ret = -1; goto bad_policy; } else if (!sk_X509_POLICY_DATA_push(cache->data, data)) { @@ -204,8 +204,6 @@ X509_POLICY_DATA *policy_cache_find_data(const X509_POLICY_CACHE *cache, X509_POLICY_DATA tmp; tmp.valid_policy = (ASN1_OBJECT *)id; idx = sk_X509_POLICY_DATA_find(cache->data, &tmp); - if (idx == -1) - return NULL; return sk_X509_POLICY_DATA_value(cache->data, idx); } diff --git a/crypto/x509v3/pcy_node.c b/crypto/x509v3/pcy_node.c index db4d71f8..1ffe9849 100644 --- a/crypto/x509v3/pcy_node.c +++ b/crypto/x509v3/pcy_node.c @@ -36,9 +36,6 @@ X509_POLICY_NODE *tree_find_sk(STACK_OF(X509_POLICY_NODE) *nodes, l.data = &n; idx = sk_X509_POLICY_NODE_find(nodes, &l); - if (idx == -1) - return NULL; - return sk_X509_POLICY_NODE_value(nodes, idx); } diff --git a/crypto/x509v3/pcy_tree.c b/crypto/x509v3/pcy_tree.c index 9a1e2088..87f51d00 100644 --- a/crypto/x509v3/pcy_tree.c +++ b/crypto/x509v3/pcy_tree.c @@ -442,7 +442,7 @@ static int tree_add_auth_node(STACK_OF(X509_POLICY_NODE) **pnodes, if (*pnodes == NULL && (*pnodes = policy_node_cmp_new()) == NULL) return 0; - if (sk_X509_POLICY_NODE_find(*pnodes, pcy) != -1) + if (sk_X509_POLICY_NODE_find(*pnodes, pcy) >= 0) return 1; return sk_X509_POLICY_NODE_push(*pnodes, pcy) != 0; } diff --git a/crypto/x509v3/v3_lib.c b/crypto/x509v3/v3_lib.c index f51aa962..e11e51b6 100644 --- a/crypto/x509v3/v3_lib.c +++ b/crypto/x509v3/v3_lib.c @@ -64,8 +64,6 @@ const X509V3_EXT_METHOD *X509V3_EXT_get_nid(int nid) if (!ext_list) return NULL; idx = sk_X509V3_EXT_METHOD_find(ext_list, &tmp); - if (idx == -1) - return NULL; return sk_X509V3_EXT_METHOD_value(ext_list, idx); } diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 1ba1ce83..5a535e2a 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -13,6 +13,7 @@ #include #include #include "internal/x509_int.h" +#include "internal/tsan_assist.h" static void x509v3_cache_extensions(X509 *x); @@ -133,13 +134,14 @@ int X509_PURPOSE_get_by_id(int purpose) { X509_PURPOSE tmp; int idx; + if ((purpose >= X509_PURPOSE_MIN) && (purpose <= X509_PURPOSE_MAX)) return purpose - X509_PURPOSE_MIN; - tmp.purpose = purpose; - if (!xptable) + if (xptable == NULL) return -1; + tmp.purpose = purpose; idx = sk_X509_PURPOSE_find(xptable, &tmp); - if (idx == -1) + if (idx < 0) return -1; return idx + X509_PURPOSE_COUNT; } @@ -350,10 +352,10 @@ static void x509v3_cache_extensions(X509 *x) ASN1_BIT_STRING *ns; EXTENDED_KEY_USAGE *extusage; X509_EXTENSION *ex; - int i; - if (x->ex_flags & EXFLAG_SET) + /* fast lock-free check, see end of the function for details. */ + if (tsan_load((TSAN_QUALIFIER int *)&x->ex_cached)) return; CRYPTO_THREAD_write_lock(x->lock); @@ -497,6 +499,12 @@ static void x509v3_cache_extensions(X509 *x) x509_init_sig_info(x); x->ex_flags |= EXFLAG_SET; CRYPTO_THREAD_unlock(x->lock); + /* + * It has to be placed after memory barrier, which is implied by unlock. + * Worst thing that can happen is that another thread proceeds to lock + * and checks x->ex_flags & EXFLAGS_SET. See beginning of the function. + */ + tsan_store((TSAN_QUALIFIER int *)&x->ex_cached, 1); } /*- diff --git a/doc/man3/OPENSSL_LH_COMPFUNC.pod b/doc/man3/OPENSSL_LH_COMPFUNC.pod index ec21c79c..a312ef73 100644 --- a/doc/man3/OPENSSL_LH_COMPFUNC.pod +++ b/doc/man3/OPENSSL_LH_COMPFUNC.pod @@ -18,7 +18,7 @@ lh_TYPE_doall, lh_TYPE_doall_arg, lh_TYPE_error - dynamic hash table DECLARE_LHASH_OF(TYPE); - LHASH *lh_TYPE_new(); + LHASH *lh_TYPE_new(OPENSSL_LH_HASHFUNC hash, OPENSSL_LH_COMPFUNC compare); void lh_TYPE_free(LHASH_OF(TYPE) *table); TYPE *lh_TYPE_insert(LHASH_OF(TYPE) *table, TYPE *data); @@ -27,7 +27,7 @@ lh_TYPE_doall, lh_TYPE_doall_arg, lh_TYPE_error - dynamic hash table void lh_TYPE_doall(LHASH_OF(TYPE) *table, OPENSSL_LH_DOALL_FUNC func); void lh_TYPE_doall_arg(LHASH_OF(TYPE) *table, OPENSSL_LH_DOALL_FUNCARG func, - TYPE, TYPE *arg); + TYPE *arg); int lh_TYPE_error(LHASH_OF(TYPE) *table); @@ -171,25 +171,18 @@ lh_TYPE_retrieve() returns the hash table entry if it has been found, B otherwise. lh_TYPE_error() returns 1 if an error occurred in the last operation, 0 -otherwise. +otherwise. It's meaningful only after non-retrieve operations. lh_TYPE_free(), lh_TYPE_doall() and lh_TYPE_doall_arg() return no values. =head1 NOTE -The various LHASH macros and callback types exist to make it possible -to write type-checked code without resorting to function-prototype -casting - an evil that makes application code much harder to -audit/verify and also opens the window of opportunity for stack -corruption and other hard-to-find bugs. It also, apparently, violates -ANSI-C. - -The LHASH code is not thread safe. All updating operations must be -performed under a write lock. All retrieve operations should be performed -under a read lock, I accurate usage statistics are desired. -In which case, a write lock should be used for retrieve operations -as well. For output of the usage statistics, using the functions from -L, a read lock suffices. +The LHASH code is not thread safe. All updating operations, as well as +lh_TYPE_error call must be performed under a write lock. All retrieve +operations should be performed under a read lock, I accurate +usage statistics are desired. In which case, a write lock should be used +for retrieve operations as well. For output of the usage statistics, +using the functions from L, a read lock suffices. The LHASH code regards table entries as constant data. As such, it internally represents lh_insert()'d items with a "const void *" diff --git a/fuzz/client.c b/fuzz/client.c index bc01f622..a262209c 100644 --- a/fuzz/client.c +++ b/fuzz/client.c @@ -49,8 +49,8 @@ int FuzzerInitialize(int *argc, char ***argv) idx = SSL_get_ex_data_X509_STORE_CTX_idx(); FuzzerSetRand(); comp_methods = SSL_COMP_get_compression_methods(); - sk_SSL_COMP_sort(comp_methods); - + if (comp_methods != NULL) + sk_SSL_COMP_sort(comp_methods); return 1; } diff --git a/fuzz/server.c b/fuzz/server.c index 7f9f9fa0..db8c8b99 100644 --- a/fuzz/server.c +++ b/fuzz/server.c @@ -496,8 +496,8 @@ int FuzzerInitialize(int *argc, char ***argv) idx = SSL_get_ex_data_X509_STORE_CTX_idx(); FuzzerSetRand(); comp_methods = SSL_COMP_get_compression_methods(); - sk_SSL_COMP_sort(comp_methods); - + if (comp_methods != NULL) + sk_SSL_COMP_sort(comp_methods); return 1; } diff --git a/include/internal/tsan_assist.h b/include/internal/tsan_assist.h new file mode 100644 index 00000000..f6870a2d --- /dev/null +++ b/include/internal/tsan_assist.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Goal here is to facilitate writing "thread-opportunistic" code that + * withstands Thread Sanitizer's scrutiny. "Thread-opportunistic" is when + * exact result is not required, e.g. some statistics, or execution flow + * doesn't have to be unambiguous. Simplest example is lazy "constant" + * initialization when one can synchronize on variable itself, e.g. + * + * if (var == NOT_YET_INITIALIZED) + * var = function_returning_same_value(); + * + * This does work provided that loads and stores are single-instuction + * operations (and integer ones are on *all* supported platforms), but + * it upsets Thread Sanitizer. Suggested solution is + * + * if (tsan_load(&var) == NOT_YET_INITIALIZED) + * tsan_store(&var, function_returning_same_value()); + * + * Production machine code would be the same, so one can wonder why + * bother. Having Thread Sanitizer accept "thread-opportunistic" code + * allows to move on trouble-shooting real bugs. + * + * We utilize the fact that compilers that implement Thread Sanitizer + * implement even atomic operations. Then it's assumed that + * ATOMIC_{LONG|INT}_LOCK_FREE are assigned same value as + * ATOMIC_POINTER_LOCK_FREE. And check for >= 2 ensures that correspodning + * code is inlined. It should be noted that statistics counters become + * accurate in such case. + */ + +#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L \ + && !defined(__STDC_NO_ATOMICS__) +# include + +# if defined(ATOMIC_POINTER_LOCK_FREE) \ + && ATOMIC_POINTER_LOCK_FREE >= 2 +# define TSAN_QUALIFIER _Atomic +# define tsan_load(ptr) atomic_load_explicit((ptr), memory_order_relaxed) +# define tsan_store(ptr, val) atomic_store_explicit((ptr), (val), memory_order_relaxed) +# define tsan_counter(ptr) atomic_fetch_add_explicit((ptr), 1, memory_order_relaxed) +# endif + +#elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) + +# if defined(__GCC_ATOMIC_POINTER_LOCK_FREE) \ + && __GCC_ATOMIC_POINTER_LOCK_FREE >= 2 +# define TSAN_QUALIFIER volatile +# define tsan_load(ptr) __atomic_load_n((ptr), __ATOMIC_RELAXED) +# define tsan_store(ptr, val) __atomic_store_n((ptr), (val), __ATOMIC_RELAXED) +# define tsan_counter(ptr) __atomic_fetch_add((ptr), 1, __ATOMIC_RELAXED) +# endif + +#elif defined(_MSC_VER) && _MSC_VER>=1200 + +# define TSAN_QUALIFIER volatile +# define tsan_load(ptr) (*(ptr)) +# define tsan_store(ptr, val) (*(ptr) = (val)) +# pragma intrinsic(_InterlockedExchangeAdd) +# ifdef _WIN64 +# pragma intrinsic(_InterlockedExchangeAdd64) +# define tsan_counter(ptr) (sizeof(*ptr) == 8 ? _InterlockedExchangeAdd64((ptr), 1) \ + : _InterlockedExchangeAdd((ptr), 1)) +# else +# define tsan_counter(ptr) _InterlockedExchangeAdd((ptr), 1) +# endif + +#endif + +#ifndef TSAN_QUALIFIER + +# define TSAN_QUALIFIER volatile +# define tsan_load(ptr) (*(ptr)) +# define tsan_store(ptr, val) (*(ptr) = (val)) +# define tsan_counter(ptr) ((*(ptr))++) + +#endif diff --git a/include/openssl/ssl3.h b/include/openssl/ssl3.h index 6d0ed11b..8d01fcc4 100644 --- a/include/openssl/ssl3.h +++ b/include/openssl/ssl3.h @@ -263,9 +263,15 @@ extern "C" { # define SSL3_CT_FORTEZZA_DMS 20 /* * SSL3_CT_NUMBER is used to size arrays and it must be large enough to - * contain all of the cert types defined either for SSLv3 and TLSv1. + * contain all of the cert types defined for *either* SSLv3 and TLSv1. */ -# define SSL3_CT_NUMBER 9 +# define SSL3_CT_NUMBER 10 + +# if defined(TLS_CT_NUMBER) +# if TLS_CT_NUMBER != SSL3_CT_NUMBER +# error "SSL/TLS CT_NUMBER values do not match" +# endif +# endif /* No longer used as of OpenSSL 1.1.1 */ # define SSL3_FLAGS_NO_RENEGOTIATE_CIPHERS 0x0001 diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h index 9090449b..0accc837 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -1151,7 +1151,13 @@ __owur int SSL_check_chain(SSL *s, X509 *x, EVP_PKEY *pk, STACK_OF(X509) *chain) * when correcting this number, correct also SSL3_CT_NUMBER in ssl3.h (see * comment there) */ -# define TLS_CT_NUMBER 9 +# define TLS_CT_NUMBER 10 + +# if defined(SSL3_CT_NUMBER) +# if TLS_CT_NUMBER != SSL3_CT_NUMBER +# error "SSL/TLS CT_NUMBER values do not match" +# endif +# endif # define TLS1_FINISH_MAC_LENGTH 12 diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 1628ac8f..d208695b 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -816,8 +816,8 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, /* Clear our SSL3_RECORD structures */ memset(wr, 0, sizeof(wr)); for (j = 0; j < numpipes; j++) { - unsigned int version = SSL_TREAT_AS_TLS13(s) ? TLS1_2_VERSION - : s->version; + unsigned int version = (s->version == TLS1_3_VERSION) ? TLS1_2_VERSION + : s->version; unsigned char *compressdata = NULL; size_t maxcomplen; unsigned int rectype; @@ -829,7 +829,10 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, * In TLSv1.3, once encrypting, we always use application data for the * record type */ - if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) + if (SSL_TREAT_AS_TLS13(s) + && s->enc_write_ctx != NULL + && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS + || type != SSL3_RT_ALERT)) rectype = SSL3_RT_APPLICATION_DATA; else rectype = type; @@ -892,7 +895,10 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, SSL3_RECORD_reset_input(&wr[j]); } - if (SSL_TREAT_AS_TLS13(s) && s->enc_write_ctx != NULL) { + if (SSL_TREAT_AS_TLS13(s) + && s->enc_write_ctx != NULL + && (s->statem.enc_write_state != ENC_WRITE_STATE_WRITE_PLAIN_ALERTS + || type != SSL3_RT_ALERT)) { size_t rlen, max_send_fragment; if (!WPACKET_put_bytes_u8(thispkt, type)) { @@ -981,8 +987,7 @@ int do_ssl3_write(SSL *s, int type, const unsigned char *buf, SSL3_RECORD_set_length(thiswr, len); } - if (s->early_data_state == SSL_EARLY_DATA_WRITING - || s->early_data_state == SSL_EARLY_DATA_WRITE_RETRY) { + if (s->statem.enc_write_state == ENC_WRITE_STATE_WRITE_PLAIN_ALERTS) { /* * We haven't actually negotiated the version yet, but we're trying to * send early data - so we need to use the tls13enc function. diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c index ad478bf3..a616bf04 100644 --- a/ssl/record/ssl3_record.c +++ b/ssl/record/ssl3_record.c @@ -342,7 +342,10 @@ int ssl3_get_record(SSL *s) if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL) { if (thisrr->type != SSL3_RT_APPLICATION_DATA && (thisrr->type != SSL3_RT_CHANGE_CIPHER_SPEC - || !SSL_IS_FIRST_HANDSHAKE(s))) { + || !SSL_IS_FIRST_HANDSHAKE(s)) + && (thisrr->type != SSL3_RT_ALERT + || s->statem.enc_read_state + != ENC_READ_STATE_ALLOW_PLAIN_ALERTS)) { SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE, SSL_F_SSL3_GET_RECORD, SSL_R_BAD_RECORD_TYPE); return -1; @@ -692,7 +695,9 @@ int ssl3_get_record(SSL *s) } } - if (SSL_IS_TLS13(s) && s->enc_read_ctx != NULL) { + if (SSL_IS_TLS13(s) + && s->enc_read_ctx != NULL + && thisrr->type != SSL3_RT_ALERT) { size_t end; if (thisrr->length == 0 diff --git a/ssl/record/ssl3_record_tls13.c b/ssl/record/ssl3_record_tls13.c index 63ecafe3..4fd583dd 100644 --- a/ssl/record/ssl3_record_tls13.c +++ b/ssl/record/ssl3_record_tls13.c @@ -52,7 +52,13 @@ int tls13_enc(SSL *s, SSL3_RECORD *recs, size_t n_recs, int sending) seq = RECORD_LAYER_get_read_sequence(&s->rlayer); } - if (ctx == NULL) { + /* + * If we're sending an alert and ctx != NULL then we must be forcing + * plaintext alerts. If we're reading and ctx != NULL then we allow + * plaintext alerts at certain points in the handshake. If we've got this + * far then we have already validated that a plaintext alert is ok here. + */ + if (ctx == NULL || rec->type == SSL3_RT_ALERT) { memmove(rec->data, rec->input, rec->length); rec->input = rec->data; return 1; diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 6d78aa1a..5f403817 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -155,7 +155,7 @@ int ssl3_change_cipher_state(SSL *s, int which) RECORD_LAYER_reset_read_sequence(&s->rlayer); mac_secret = &(s->s3->read_mac_secret[0]); } else { - s->statem.invalid_enc_write_ctx = 1; + s->statem.enc_write_state = ENC_WRITE_STATE_INVALID; if (s->enc_write_ctx != NULL) { reuse_dd = 1; } else if ((s->enc_write_ctx = EVP_CIPHER_CTX_new()) == NULL) { @@ -238,7 +238,7 @@ int ssl3_change_cipher_state(SSL *s, int which) goto err; } - s->statem.invalid_enc_write_ctx = 0; + s->statem.enc_write_state = ENC_WRITE_STATE_VALID; OPENSSL_cleanse(exp_key, sizeof(exp_key)); OPENSSL_cleanse(exp_iv, sizeof(exp_iv)); return 1; diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c index e89d1482..205f868a 100644 --- a/ssl/ssl_ciph.c +++ b/ssl/ssl_ciph.c @@ -507,10 +507,7 @@ int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, ctmp.id = s->compress_meth; if (ssl_comp_methods != NULL) { i = sk_SSL_COMP_find(ssl_comp_methods, &ctmp); - if (i >= 0) - *comp = sk_SSL_COMP_value(ssl_comp_methods, i); - else - *comp = NULL; + *comp = sk_SSL_COMP_value(ssl_comp_methods, i); } /* If were only interested in comp then return success */ if ((enc == NULL) && (md == NULL)) diff --git a/ssl/ssl_init.c b/ssl/ssl_init.c index ed2bf845..c0ccb930 100644 --- a/ssl/ssl_init.c +++ b/ssl/ssl_init.c @@ -129,8 +129,8 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_load_ssl_strings) "ERR_load_SSL_strings()\n"); # endif ERR_load_SSL_strings(); -#endif ssl_strings_inited = 1; +#endif return 1; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 7d7e67e8..d753825a 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -2330,7 +2330,6 @@ LHASH_OF(SSL_SESSION) *SSL_CTX_sessions(SSL_CTX *ctx) long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) { long l; - int i; /* For some cases with ctx == NULL perform syntax checks */ if (ctx == NULL) { switch (cmd) { @@ -2385,40 +2384,27 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, void *parg) case SSL_CTRL_SESS_NUMBER: return lh_SSL_SESSION_num_items(ctx->sessions); case SSL_CTRL_SESS_CONNECT: - return CRYPTO_atomic_read(&ctx->stats.sess_connect, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_connect); case SSL_CTRL_SESS_CONNECT_GOOD: - return CRYPTO_atomic_read(&ctx->stats.sess_connect_good, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_connect_good); case SSL_CTRL_SESS_CONNECT_RENEGOTIATE: - return CRYPTO_atomic_read(&ctx->stats.sess_connect_renegotiate, &i, - ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_connect_renegotiate); case SSL_CTRL_SESS_ACCEPT: - return CRYPTO_atomic_read(&ctx->stats.sess_accept, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_accept); case SSL_CTRL_SESS_ACCEPT_GOOD: - return CRYPTO_atomic_read(&ctx->stats.sess_accept_good, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_accept_good); case SSL_CTRL_SESS_ACCEPT_RENEGOTIATE: - return CRYPTO_atomic_read(&ctx->stats.sess_accept_renegotiate, &i, - ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_accept_renegotiate); case SSL_CTRL_SESS_HIT: - return CRYPTO_atomic_read(&ctx->stats.sess_hit, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_hit); case SSL_CTRL_SESS_CB_HIT: - return CRYPTO_atomic_read(&ctx->stats.sess_cb_hit, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_cb_hit); case SSL_CTRL_SESS_MISSES: - return CRYPTO_atomic_read(&ctx->stats.sess_miss, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_miss); case SSL_CTRL_SESS_TIMEOUTS: - return CRYPTO_atomic_read(&ctx->stats.sess_timeout, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_timeout); case SSL_CTRL_SESS_CACHE_FULL: - return CRYPTO_atomic_read(&ctx->stats.sess_cache_full, &i, ctx->lock) - ? i : 0; + return tsan_load(&ctx->stats.sess_cache_full); case SSL_CTRL_MODE: return (ctx->mode |= larg); case SSL_CTRL_CLEAR_MODE: @@ -3492,13 +3478,12 @@ void ssl_update_cache(SSL *s, int mode) /* auto flush every 255 connections */ if ((!(i & SSL_SESS_CACHE_NO_AUTO_CLEAR)) && ((i & mode) == mode)) { - int *stat, val; + TSAN_QUALIFIER int *stat; if (mode & SSL_SESS_CACHE_CLIENT) stat = &s->session_ctx->stats.sess_connect_good; else stat = &s->session_ctx->stats.sess_accept_good; - if (CRYPTO_atomic_read(stat, &val, s->session_ctx->lock) - && (val & 0xff) == 0xff) + if ((tsan_load(stat) & 0xff) == 0xff) SSL_CTX_flush_sessions(s->session_ctx, (unsigned long)time(NULL)); } } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index ab08f9cb..38e95528 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -33,6 +33,7 @@ # include "packet_locl.h" # include "internal/dane.h" # include "internal/refcount.h" +# include "internal/tsan_assist.h" # ifdef OPENSSL_BUILD_SHLIBSSL # undef OPENSSL_EXTERN @@ -816,21 +817,23 @@ struct ssl_ctx_st { const unsigned char *data, int len, int *copy); struct { - int sess_connect; /* SSL new conn - started */ - int sess_connect_renegotiate; /* SSL reneg - requested */ - int sess_connect_good; /* SSL new conne/reneg - finished */ - int sess_accept; /* SSL new accept - started */ - int sess_accept_renegotiate; /* SSL reneg - requested */ - int sess_accept_good; /* SSL accept/reneg - finished */ - int sess_miss; /* session lookup misses */ - int sess_timeout; /* reuse attempt on timeouted session */ - int sess_cache_full; /* session removed due to full cache */ - int sess_hit; /* session reuse actually done */ - int sess_cb_hit; /* session-id that was not in the cache was - * passed back via the callback. This - * indicates that the application is supplying - * session-id's from other processes - spooky - * :-) */ + TSAN_QUALIFIER int sess_connect; /* SSL new conn - started */ + TSAN_QUALIFIER int sess_connect_renegotiate; /* SSL reneg - requested */ + TSAN_QUALIFIER int sess_connect_good; /* SSL new conne/reneg - finished */ + TSAN_QUALIFIER int sess_accept; /* SSL new accept - started */ + TSAN_QUALIFIER int sess_accept_renegotiate; /* SSL reneg - requested */ + TSAN_QUALIFIER int sess_accept_good; /* SSL accept/reneg - finished */ + TSAN_QUALIFIER int sess_miss; /* session lookup misses */ + TSAN_QUALIFIER int sess_timeout; /* reuse attempt on timeouted session */ + TSAN_QUALIFIER int sess_cache_full; /* session removed due to full cache */ + TSAN_QUALIFIER int sess_hit; /* session reuse actually done */ + TSAN_QUALIFIER int sess_cb_hit; /* session-id that was not in + * the cache was passed back via + * the callback. This indicates + * that the application is + * supplying session-id's from + * other processes - spooky + * :-) */ } stats; CRYPTO_REF_COUNT references; diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index d4a4808f..5ad2792a 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -448,7 +448,6 @@ SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id, size_t sess_id_len) { SSL_SESSION *ret = NULL; - int discard; if ((s->session_ctx->session_cache_mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP) == 0) { @@ -469,8 +468,7 @@ SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id, } CRYPTO_THREAD_unlock(s->session_ctx->lock); if (ret == NULL) - CRYPTO_atomic_add(&s->session_ctx->stats.sess_miss, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_miss); } if (ret == NULL && s->session_ctx->get_session_cb != NULL) { @@ -479,8 +477,7 @@ SSL_SESSION *lookup_sess_in_cache(SSL *s, const unsigned char *sess_id, ret = s->session_ctx->get_session_cb(s, sess_id, sess_id_len, ©); if (ret != NULL) { - CRYPTO_atomic_add(&s->session_ctx->stats.sess_cb_hit, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_cb_hit); /* * Increment reference count now if the session callback asks us @@ -533,7 +530,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) /* This is used only by servers. */ SSL_SESSION *ret = NULL; - int fatal = 0, discard; + int fatal = 0; int try_session_cache = 0; SSL_TICKET_STATUS r; @@ -612,8 +609,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) } if (ret->timeout < (long)(time(NULL) - ret->time)) { /* timeout */ - CRYPTO_atomic_add(&s->session_ctx->stats.sess_timeout, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_timeout); if (try_session_cache) { /* session was from the cache, so remove it */ SSL_CTX_remove_session(s->session_ctx, ret); @@ -641,8 +637,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) s->session = ret; } - CRYPTO_atomic_add(&s->session_ctx->stats.sess_hit, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_hit); s->verify_result = s->session->verify_result; return 1; @@ -669,7 +664,7 @@ int ssl_get_prev_session(SSL *s, CLIENTHELLO_MSG *hello) int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) { - int ret = 0, discard; + int ret = 0; SSL_SESSION *s; /* @@ -736,8 +731,7 @@ int SSL_CTX_add_session(SSL_CTX *ctx, SSL_SESSION *c) if (!remove_session_lock(ctx, ctx->session_cache_tail, 0)) break; else - CRYPTO_atomic_add(&ctx->stats.sess_cache_full, 1, &discard, - ctx->lock); + tsan_counter(&ctx->stats.sess_cache_full); } } } diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 85945acc..12c712e8 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -912,7 +912,7 @@ static int init_server_name(SSL *s, unsigned int context) static int final_server_name(SSL *s, unsigned int context, int sent) { - int ret = SSL_TLSEXT_ERR_NOACK, discard; + int ret = SSL_TLSEXT_ERR_NOACK; int altmp = SSL_AD_UNRECOGNIZED_NAME; int was_ticket = (SSL_get_options(s) & SSL_OP_NO_TICKET) == 0; @@ -960,10 +960,8 @@ static int final_server_name(SSL *s, unsigned int context, int sent) * exceed sess_accept (zero) for the new context. */ if (SSL_IS_FIRST_HANDSHAKE(s) && s->ctx != s->session_ctx) { - CRYPTO_atomic_add(&s->ctx->stats.sess_accept, 1, &discard, - s->ctx->lock); - CRYPTO_atomic_add(&s->session_ctx->stats.sess_accept, -1, &discard, - s->session_ctx->lock); + tsan_counter(&s->ctx->stats.sess_accept); + tsan_counter(&s->session_ctx->stats.sess_accept); } /* diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c index 7f1017d8..d75f9ea0 100644 --- a/ssl/statem/statem.c +++ b/ssl/statem/statem.c @@ -123,7 +123,8 @@ void ossl_statem_fatal(SSL *s, int al, int func, int reason, const char *file, s->statem.in_init = 1; s->statem.state = MSG_FLOW_ERROR; ERR_put_error(ERR_LIB_SSL, func, reason, file, line); - if (al != SSL_AD_NO_ALERT && !s->statem.invalid_enc_write_ctx) + if (al != SSL_AD_NO_ALERT + && s->statem.enc_write_state != ENC_WRITE_STATE_INVALID) ssl3_send_alert(s, SSL3_AL_FATAL, al); } diff --git a/ssl/statem/statem.h b/ssl/statem/statem.h index 95dd8812..144d930f 100644 --- a/ssl/statem/statem.h +++ b/ssl/statem/statem.h @@ -71,6 +71,22 @@ typedef enum { WRITE_STATE_POST_WORK } WRITE_STATE; +typedef enum { + /* The enc_write_ctx can be used normally */ + ENC_WRITE_STATE_VALID, + /* The enc_write_ctx cannot be used */ + ENC_WRITE_STATE_INVALID, + /* Write alerts in plaintext, but otherwise use the enc_write_ctx */ + ENC_WRITE_STATE_WRITE_PLAIN_ALERTS +} ENC_WRITE_STATES; + +typedef enum { + /* The enc_read_ctx can be used normally */ + ENC_READ_STATE_VALID, + /* We may receive encrypted or plaintext alerts */ + ENC_READ_STATE_ALLOW_PLAIN_ALERTS +} ENC_READ_STATES; + /***************************************************************************** * * * This structure should be considered "opaque" to anything outside of the * @@ -100,7 +116,8 @@ struct ossl_statem_st { /* Should we skip the CertificateVerify message? */ unsigned int no_cert_verify; int use_timer; - int invalid_enc_write_ctx; + ENC_WRITE_STATES enc_write_state; + ENC_READ_STATES enc_read_state; }; typedef struct ossl_statem_st OSSL_STATEM; diff --git a/ssl/statem/statem_clnt.c b/ssl/statem/statem_clnt.c index ad79fef8..3dc29cc7 100644 --- a/ssl/statem/statem_clnt.c +++ b/ssl/statem/statem_clnt.c @@ -1409,7 +1409,6 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) unsigned int compression; unsigned int sversion; unsigned int context; - int discard; RAW_EXTENSION *extensions = NULL; #ifndef OPENSSL_NO_COMP SSL_COMP *comp; @@ -1616,8 +1615,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt) || (SSL_IS_TLS13(s) && s->session->ext.tick_identity != TLSEXT_PSK_BAD_IDENTITY)) { - CRYPTO_atomic_add(&s->session_ctx->stats.sess_miss, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_miss); if (!ssl_get_new_session(s, 0)) { /* SSLfatal() already called */ goto err; @@ -2647,10 +2645,16 @@ MSG_PROCESS_RETURN tls_process_new_session_ticket(SSL *s, PACKET *pkt) PACKET extpkt; if (!PACKET_as_length_prefixed_2(pkt, &extpkt) - || PACKET_remaining(pkt) != 0 - || !tls_collect_extensions(s, &extpkt, - SSL_EXT_TLS1_3_NEW_SESSION_TICKET, - &exts, NULL, 1) + || PACKET_remaining(pkt) != 0) { + SSLfatal(s, SSL_AD_DECODE_ERROR, + SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, + SSL_R_LENGTH_MISMATCH); + goto err; + } + + if (!tls_collect_extensions(s, &extpkt, + SSL_EXT_TLS1_3_NEW_SESSION_TICKET, &exts, + NULL, 1) || !tls_parse_all_extensions(s, SSL_EXT_TLS1_3_NEW_SESSION_TICKET, exts, NULL, 0, 1)) { diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index f8d34bb7..88258215 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -132,23 +132,18 @@ int tls_setup_handshake(SSL *s) } if (SSL_IS_FIRST_HANDSHAKE(s)) { /* N.B. s->session_ctx == s->ctx here */ - CRYPTO_atomic_add(&s->session_ctx->stats.sess_accept, 1, &i, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_accept); } else { /* N.B. s->ctx may not equal s->session_ctx */ - CRYPTO_atomic_add(&s->ctx->stats.sess_accept_renegotiate, 1, &i, - s->ctx->lock); + tsan_counter(&s->ctx->stats.sess_accept_renegotiate); s->s3->tmp.cert_request = 0; } } else { - int discard; if (SSL_IS_FIRST_HANDSHAKE(s)) - CRYPTO_atomic_add(&s->session_ctx->stats.sess_connect, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_connect); else - CRYPTO_atomic_add(&s->session_ctx->stats.sess_connect_renegotiate, - 1, &discard, s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_connect_renegotiate); /* mark client_random uninitialized */ memset(s->s3->client_random, 0, sizeof(s->s3->client_random)); @@ -752,6 +747,12 @@ MSG_PROCESS_RETURN tls_process_finished(SSL *s, PACKET *pkt) /* This is a real handshake so make sure we clean it up at the end */ if (s->server) { + /* + * To get this far we must have read encrypted data from the client. We + * no longer tolerate unencrypted alerts. This value is ignored if less + * than TLSv1.3 + */ + s->statem.enc_read_state = ENC_READ_STATE_VALID; if (s->post_handshake_auth != SSL_PHA_REQUESTED) s->statem.cleanuphand = 1; if (SSL_IS_TLS13(s) && !tls13_save_handshake_digest_for_pha(s)) { @@ -1009,7 +1010,6 @@ unsigned long ssl3_output_cert_chain(SSL *s, WPACKET *pkt, CERT_PKEY *cpk) */ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop) { - int discard; void (*cb) (const SSL *ssl, int type, int val) = NULL; if (clearbufs) { @@ -1055,8 +1055,7 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop) ssl_update_cache(s, SSL_SESS_CACHE_SERVER); /* N.B. s->ctx may not equal s->session_ctx */ - CRYPTO_atomic_add(&s->ctx->stats.sess_accept_good, 1, &discard, - s->ctx->lock); + tsan_counter(&s->ctx->stats.sess_accept_good); s->handshake_func = ossl_statem_accept; if (SSL_IS_DTLS(s) && !s->hit) { @@ -1084,12 +1083,10 @@ WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop) ssl_update_cache(s, SSL_SESS_CACHE_CLIENT); } if (s->hit) - CRYPTO_atomic_add(&s->session_ctx->stats.sess_hit, 1, &discard, - s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_hit); s->handshake_func = ossl_statem_connect; - CRYPTO_atomic_add(&s->session_ctx->stats.sess_connect_good, 1, - &discard, s->session_ctx->lock); + tsan_counter(&s->session_ctx->stats.sess_connect_good); if (SSL_IS_DTLS(s) && s->hit) { /* @@ -1917,6 +1914,9 @@ int ssl_choose_client_version(SSL *s, int version, RAW_EXTENSION *extensions) if (highver != 0 && s->version != vent->version) continue; + if (highver == 0 && (s->mode & SSL_MODE_SEND_FALLBACK_SCSV) != 0) + highver = vent->version; + method = vent->cmeth(); err = ssl_method_error(s, method); if (err != 0) { diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 3e824311..d2912756 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -848,12 +848,7 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) return WORK_MORE_A; break; } - /* - * TODO(TLS1.3): This actually causes a problem. We don't yet know - * whether the next record we are going to receive is an unencrypted - * alert, or an encrypted handshake message. We're going to need - * something clever in the record layer for this. - */ + if (SSL_IS_TLS13(s)) { if (!s->method->ssl3_enc->setup_key_block(s) || !s->method->ssl3_enc->change_cipher_state(s, @@ -868,6 +863,12 @@ WORK_STATE ossl_statem_server_post_work(SSL *s, WORK_STATE wst) /* SSLfatal() already called */ return WORK_ERROR; } + /* + * We don't yet know whether the next record we are going to receive + * is an unencrypted alert, an encrypted alert, or an encrypted + * handshake message. We temporarily tolerate unencrypted alerts. + */ + s->statem.enc_read_state = ENC_READ_STATE_ALLOW_PLAIN_ALERTS; break; } @@ -2371,15 +2372,19 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) if (!WPACKET_sub_memcpy_u8(pkt, session_id, sl) || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len) - || !WPACKET_put_bytes_u8(pkt, compm) - || !tls_construct_extensions(s, pkt, - s->hello_retry_request - == SSL_HRR_PENDING - ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST - : (SSL_IS_TLS13(s) - ? SSL_EXT_TLS1_3_SERVER_HELLO - : SSL_EXT_TLS1_2_SERVER_HELLO), - NULL, 0)) { + || !WPACKET_put_bytes_u8(pkt, compm)) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_SERVER_HELLO, + ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!tls_construct_extensions(s, pkt, + s->hello_retry_request == SSL_HRR_PENDING + ? SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST + : (SSL_IS_TLS13(s) + ? SSL_EXT_TLS1_3_SERVER_HELLO + : SSL_EXT_TLS1_2_SERVER_HELLO), + NULL, 0)) { /* SSLfatal() already called */ return 0; } @@ -3520,6 +3525,13 @@ MSG_PROCESS_RETURN tls_process_client_certificate(SSL *s, PACKET *pkt) size_t chainidx; SSL_SESSION *new_sess = NULL; + /* + * To get this far we must have read encrypted data from the client. We no + * longer tolerate unencrypted alerts. This value is ignored if less than + * TLSv1.3 + */ + s->statem.enc_read_state = ENC_READ_STATE_VALID; + if ((sk = sk_X509_new_null()) == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PROCESS_CLIENT_CERTIFICATE, ERR_R_MALLOC_FAILURE); diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 23d3efb0..2db913fb 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -154,7 +154,7 @@ int tls1_change_cipher_state(SSL *s, int which) mac_secret = &(s->s3->read_mac_secret[0]); mac_secret_size = &(s->s3->read_mac_secret_size); } else { - s->statem.invalid_enc_write_ctx = 1; + s->statem.enc_write_state = ENC_WRITE_STATE_INVALID; if (s->ext.use_etm) s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC_WRITE; else @@ -316,7 +316,7 @@ int tls1_change_cipher_state(SSL *s, int which) ERR_R_INTERNAL_ERROR); goto err; } - s->statem.invalid_enc_write_ctx = 0; + s->statem.enc_write_state = ENC_WRITE_STATE_VALID; #ifdef SSL_DEBUG printf("which = %04X\nkey=", which); diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c index 48990fd6..22db2f82 100644 --- a/ssl/tls13_enc.c +++ b/ssl/tls13_enc.c @@ -425,7 +425,7 @@ int tls13_change_cipher_state(SSL *s, int which) RECORD_LAYER_reset_read_sequence(&s->rlayer); } else { - s->statem.invalid_enc_write_ctx = 1; + s->statem.enc_write_state = ENC_WRITE_STATE_INVALID; if (s->enc_write_ctx != NULL) { EVP_CIPHER_CTX_reset(s->enc_write_ctx); } else { @@ -648,7 +648,10 @@ int tls13_change_cipher_state(SSL *s, int which) goto err; } - s->statem.invalid_enc_write_ctx = 0; + if (!s->server && label == client_early_traffic) + s->statem.enc_write_state = ENC_WRITE_STATE_WRITE_PLAIN_ALERTS; + else + s->statem.enc_write_state = ENC_WRITE_STATE_VALID; ret = 1; err: OPENSSL_cleanse(secret, sizeof(secret)); @@ -671,7 +674,7 @@ int tls13_update_key(SSL *s, int sending) insecret = s->client_app_traffic_secret; if (sending) { - s->statem.invalid_enc_write_ctx = 1; + s->statem.enc_write_state = ENC_WRITE_STATE_INVALID; iv = s->write_iv; ciph_ctx = s->enc_write_ctx; RECORD_LAYER_reset_write_sequence(&s->rlayer); @@ -692,7 +695,7 @@ int tls13_update_key(SSL *s, int sending) memcpy(insecret, secret, hashlen); - s->statem.invalid_enc_write_ctx = 0; + s->statem.enc_write_state = ENC_WRITE_STATE_VALID; ret = 1; err: OPENSSL_cleanse(secret, sizeof(secret)); diff --git a/test/asn1_internal_test.c b/test/asn1_internal_test.c index ab4dc353..38313d58 100644 --- a/test/asn1_internal_test.c +++ b/test/asn1_internal_test.c @@ -67,6 +67,7 @@ static int test_standard_methods(void) const EVP_PKEY_ASN1_METHOD **tmp; int last_pkey_id = -1; size_t i; + int ok = 1; for (tmp = standard_methods, i = 0; i < OSSL_NELEM(standard_methods); i++, tmp++) { @@ -75,11 +76,26 @@ static int test_standard_methods(void) break; } last_pkey_id = (*tmp)->pkey_id; + + /* + * One of the following must be true: + * + * pem_str == NULL AND ASN1_PKEY_ALIAS is set + * pem_str != NULL AND ASN1_PKEY_ALIAS is clear + * + * Anything else is an error and may lead to a corrupt ASN1 method table + */ + if (!TEST_true(((*tmp)->pem_str == NULL && ((*tmp)->pkey_flags & ASN1_PKEY_ALIAS) != 0) + || ((*tmp)->pem_str != NULL && ((*tmp)->pkey_flags & ASN1_PKEY_ALIAS) == 0))) { + TEST_note("asn1 standard methods: Index %zu, pkey ID %d, Name=%s", + i, (*tmp)->pkey_id, OBJ_nid2sn((*tmp)->pkey_id)); + ok = 0; + } } if (TEST_int_ne(last_pkey_id, 0)) { TEST_info("asn1 standard methods: Table order OK"); - return 1; + return ok; } TEST_note("asn1 standard methods: out of order"); diff --git a/test/recipes/70-test_tls13alerts.t b/test/recipes/70-test_tls13alerts.t new file mode 100644 index 00000000..7111d404 --- /dev/null +++ b/test/recipes/70-test_tls13alerts.t @@ -0,0 +1,56 @@ +#! /usr/bin/env perl +# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use OpenSSL::Test qw/:DEFAULT cmdstr srctop_file bldtop_dir/; +use OpenSSL::Test::Utils; +use TLSProxy::Proxy; + +my $test_name = "test_tls13alerts"; +setup($test_name); + +plan skip_all => "TLSProxy isn't usable on $^O" + if $^O =~ /^(VMS)$/; + +plan skip_all => "$test_name needs the dynamic engine feature enabled" + if disabled("engine") || disabled("dynamic-engine"); + +plan skip_all => "$test_name needs the sock feature enabled" + if disabled("sock"); + +plan skip_all => "$test_name needs TLS1.3 enabled" + if disabled("tls1_3"); + +$ENV{OPENSSL_ia32cap} = '~0x200000200000000'; + +my $proxy = TLSProxy::Proxy->new( + undef, + cmdstr(app(["openssl"]), display => 1), + srctop_file("apps", "server.pem"), + (!$ENV{HARNESS_ACTIVE} || $ENV{HARNESS_VERBOSE}) +); + +#Test 1: We test that a server can handle an unencrypted alert when normally the +# next message is encrypted +$proxy->filter(\&alert_filter); +$proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; +plan tests => 1; +my $alert = TLSProxy::Message->alert(); +ok(TLSProxy::Message->fail() && !$alert->server() && !$alert->encrypted(), "Client sends an unecrypted alert"); + +sub alert_filter +{ + my $proxy = shift; + + if ($proxy->flight != 1) { + return; + } + + ${$proxy->message_list}[1]->session_id_len(1); + ${$proxy->message_list}[1]->repack(); +} diff --git a/test/recipes/70-test_tls13downgrade.t b/test/recipes/70-test_tls13downgrade.t index dbf011cb..cc5fb16d 100644 --- a/test/recipes/70-test_tls13downgrade.t +++ b/test/recipes/70-test_tls13downgrade.t @@ -41,14 +41,15 @@ my $proxy = TLSProxy::Proxy->new( use constant { DOWNGRADE_TO_TLS_1_2 => 0, - DOWNGRADE_TO_TLS_1_1 => 1 + DOWNGRADE_TO_TLS_1_1 => 1, + FALLBACK_FROM_TLS_1_3 => 2, }; #Test 1: Downgrade from TLSv1.3 to TLSv1.2 $proxy->filter(\&downgrade_filter); my $testtype = DOWNGRADE_TO_TLS_1_2; $proxy->start() or plan skip_all => "Unable to start up Proxy for tests"; -plan tests => 3; +plan tests => 4; ok(TLSProxy::Message->fail(), "Downgrade TLSv1.3 to TLSv1.2"); #Test 2: Downgrade from TLSv1.3 to TLSv1.1 @@ -64,6 +65,18 @@ $proxy->serverflags("-no_tls1_3"); $proxy->start(); ok(TLSProxy::Message->fail(), "Downgrade TLSv1.2 to TLSv1.1"); +#Test 4: Client falls back from TLSv1.3 (server does not support the fallback +# SCSV) +$proxy->clear(); +$testtype = FALLBACK_FROM_TLS_1_3; +$proxy->clientflags("-fallback_scsv -no_tls1_3"); +$proxy->start(); +my $alert = TLSProxy::Message->alert(); +ok(TLSProxy::Message->fail() + && !$alert->server() + && $alert->description() == TLSProxy::Message::AL_DESC_ILLEGAL_PARAMETER, + "Fallback from TLSv1.3"); + sub downgrade_filter { my $proxy = shift; @@ -76,17 +89,24 @@ sub downgrade_filter my $message = ${$proxy->message_list}[0]; my $ext; - if ($testtype == DOWNGRADE_TO_TLS_1_2) { - $ext = pack "C3", - 0x02, # Length - 0x03, 0x03; #TLSv1.2 + if ($testtype == FALLBACK_FROM_TLS_1_3) { + #The default ciphersuite we use for TLSv1.2 without any SCSV + my @ciphersuites = (TLSProxy::Message::CIPHER_RSA_WITH_AES_128_CBC_SHA); + $message->ciphersuite_len(2 * scalar @ciphersuites); + $message->ciphersuites(\@ciphersuites); } else { - $ext = pack "C3", - 0x02, # Length - 0x03, 0x02; #TLSv1.1 - } + if ($testtype == DOWNGRADE_TO_TLS_1_2) { + $ext = pack "C3", + 0x02, # Length + 0x03, 0x03; #TLSv1.2 + } else { + $ext = pack "C3", + 0x02, # Length + 0x03, 0x02; #TLSv1.1 + } - $message->set_extension(TLSProxy::Message::EXT_SUPPORTED_VERSIONS, $ext); + $message->set_extension(TLSProxy::Message::EXT_SUPPORTED_VERSIONS, $ext); + } $message->repack(); } diff --git a/test/sanitytest.c b/test/sanitytest.c index da74e7ec..0aaf3f45 100644 --- a/test/sanitytest.c +++ b/test/sanitytest.c @@ -84,6 +84,11 @@ static int test_sanity_range(void) return 1; } +static int test_sanity_memcmp(void) +{ + return CRYPTO_memcmp("ab","cd",2); +} + int setup_tests(void) { ADD_TEST(test_sanity_null_zero); @@ -92,6 +97,7 @@ int setup_tests(void) ADD_TEST(test_sanity_sign); ADD_TEST(test_sanity_unsigned_conversion); ADD_TEST(test_sanity_range); + ADD_TEST(test_sanity_memcmp); return 1; } diff --git a/test/test_test.c b/test/test_test.c index 18b61c6d..0af2eaeb 100644 --- a/test/test_test.c +++ b/test/test_test.c @@ -531,11 +531,6 @@ static int test_bn_output(int n) return 1; } -static int test_memcmp(void) -{ - return CRYPTO_memcmp("ab","cd",2); -} - int setup_tests(void) { ADD_TEST(test_int); @@ -557,7 +552,6 @@ int setup_tests(void) ADD_TEST(test_messages); ADD_TEST(test_single_eval); ADD_TEST(test_output); - ADD_TEST(test_memcmp); ADD_ALL_TESTS(test_bn_output, OSSL_NELEM(bn_output_tests)); return 1; } diff --git a/util/perl/TLSProxy/Alert.pm b/util/perl/TLSProxy/Alert.pm new file mode 100644 index 00000000..e66883d4 --- /dev/null +++ b/util/perl/TLSProxy/Alert.pm @@ -0,0 +1,51 @@ +# Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; + +package TLSProxy::Alert; + +sub new +{ + my $class = shift; + my ($server, + $encrypted, + $level, + $description) = @_; + + my $self = { + server => $server, + encrypted => $encrypted, + level => $level, + description => $description + }; + + return bless $self, $class; +} + +#Read only accessors +sub server +{ + my $self = shift; + return $self->{server}; +} +sub encrypted +{ + my $self = shift; + return $self->{encrypted}; +} +sub level +{ + my $self = shift; + return $self->{level}; +} +sub description +{ + my $self = shift; + return $self->{description}; +} +1; diff --git a/util/perl/TLSProxy/Message.pm b/util/perl/TLSProxy/Message.pm index 56570f9b..dae6daa6 100644 --- a/util/perl/TLSProxy/Message.pm +++ b/util/perl/TLSProxy/Message.pm @@ -9,6 +9,8 @@ use strict; package TLSProxy::Message; +use TLSProxy::Alert; + use constant TLS_MESSAGE_HEADER_LENGTH => 4; #Message types @@ -39,6 +41,7 @@ use constant { use constant { AL_DESC_CLOSE_NOTIFY => 0, AL_DESC_UNEXPECTED_MESSAGE => 10, + AL_DESC_ILLEGAL_PARAMETER => 47, AL_DESC_NO_RENEGOTIATION => 100 }; @@ -123,6 +126,7 @@ use constant { }; use constant { + CIPHER_RSA_WITH_AES_128_CBC_SHA => 0x002f, CIPHER_DHE_RSA_AES_128_SHA => 0x0033, CIPHER_ADH_AES_128_SHA => 0x0034, CIPHER_TLS13_AES_128_GCM_SHA256 => 0x1301, @@ -140,6 +144,7 @@ my @message_rec_list = (); my @message_frag_lens = (); my $ciphersuite = 0; my $successondata = 0; +my $alert; sub clear { @@ -152,6 +157,7 @@ sub clear $successondata = 0; @message_rec_list = (); @message_frag_lens = (); + $alert = undef; } #Class method to extract messages from a record @@ -281,6 +287,11 @@ sub get_messages if ($alertlev == AL_LEVEL_FATAL || $alertdesc == AL_DESC_CLOSE_NOTIFY) { $end = 1; } + $alert = TLSProxy::Alert->new( + $server, + $record->encrypted, + $alertlev, + $alertdesc); } return @messages; @@ -388,6 +399,12 @@ sub fail my $class = shift; return !$success && $end; } + +sub alert +{ + return $alert; +} + sub new { my $class = shift; diff --git a/util/perl/TLSProxy/Record.pm b/util/perl/TLSProxy/Record.pm index 9de51b37..8db50d0b 100644 --- a/util/perl/TLSProxy/Record.pm +++ b/util/perl/TLSProxy/Record.pm @@ -97,7 +97,9 @@ sub get_records $data # decrypt_data ); - if ($content_type != RT_CCS) { + if ($content_type != RT_CCS + && (!TLSProxy::Proxy->is_tls13() + || $content_type != RT_ALERT)) { if (($server && $server_encrypting) || (!$server && $client_encrypting)) { if (!TLSProxy::Proxy->is_tls13() && $etm) {