diff options
author | Robert Sloan <varomodt@google.com> | 2017-10-30 14:10:28 -0700 |
---|---|---|
committer | Robert Sloan <varomodt@google.com> | 2017-10-30 14:10:51 -0700 |
commit | 29c1d2cf8620ad14e06d8e7ff91db8f4de04d481 (patch) | |
tree | 40c62dc13cf10cc29eab8e9caf1f6cf7a86ffee4 | |
parent | a7dc4759b5f834b50a9be8dd3ec1abb7ff3e5bc5 (diff) | |
download | boringssl-29c1d2cf8620ad14e06d8e7ff91db8f4de04d481.tar.gz |
external/boringssl: Sync to ba94746eb2b4b59a0eb72047e4ca2d2d54454c87.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/7f8c553d7f4db0a6ce727f2986d41bf8fe8ec4bf..ba94746eb2b4b59a0eb72047e4ca2d2d54454c87
Test: BoringSSL CTS Presubmits
Change-Id: I5283ca8ec80f4abbc2543fece2ecf2b33240c6e4
84 files changed, 1368 insertions, 1152 deletions
diff --git a/BORINGSSL_REVISION b/BORINGSSL_REVISION index cab4f0be..36163e6c 100644 --- a/BORINGSSL_REVISION +++ b/BORINGSSL_REVISION @@ -1 +1 @@ -7f8c553d7f4db0a6ce727f2986d41bf8fe8ec4bf +ba94746eb2b4b59a0eb72047e4ca2d2d54454c87 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1814b13d..1f2f6ba0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,6 +72,9 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CLANG) if(NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + if(APPLE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + endif() if(NOT BORINGSSL_ALLOW_CXX_RUNTIME) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions -fno-rtti") endif() @@ -307,7 +310,7 @@ if (ANDROID AND ${ARCH} STREQUAL "arm") set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -march=${CMAKE_SYSTEM_PROCESSOR}") endif() -if (${ARCH} STREQUAL "x86" AND APPLE) +if (${ARCH} STREQUAL "x86" AND APPLE AND ${CMAKE_VERSION} VERSION_LESS "3.0") # With CMake 2.8.x, ${CMAKE_SYSTEM_PROCESSOR} evalutes to i386 on OS X, # but clang defaults to 64-bit builds on OS X unless otherwise told. # Set ARCH to x86_64 so clang and CMake agree. This is fixed in CMake 3. diff --git a/src/crypto/asn1/a_enum.c b/src/crypto/asn1/a_enum.c index cc469055..4a779718 100644 --- a/src/crypto/asn1/a_enum.c +++ b/src/crypto/asn1/a_enum.c @@ -56,6 +56,7 @@ #include <openssl/asn1.h> +#include <limits.h> #include <string.h> #include <openssl/err.h> @@ -110,7 +111,6 @@ int ASN1_ENUMERATED_set(ASN1_ENUMERATED *a, long v) long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a) { int neg = 0, i; - long r = 0; if (a == NULL) return (0L); @@ -120,20 +120,31 @@ long ASN1_ENUMERATED_get(ASN1_ENUMERATED *a) else if (i != V_ASN1_ENUMERATED) return -1; - if (a->length > (int)sizeof(long)) { + OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long), + long_larger_than_uint64_t); + + if (a->length > (int)sizeof(uint64_t)) { /* hmm... a bit ugly */ - return (0xffffffffL); + return -1; } - if (a->data == NULL) - return 0; - for (i = 0; i < a->length; i++) { - r <<= 8; - r |= (unsigned char)a->data[i]; + uint64_t r64 = 0; + if (a->data != NULL) { + for (i = 0; i < a->length; i++) { + r64 <<= 8; + r64 |= (unsigned char)a->data[i]; + } + + if (r64 > LONG_MAX) { + return -1; + } } + + long r = (long) r64; if (neg) r = -r; - return (r); + + return r; } ASN1_ENUMERATED *BN_to_ASN1_ENUMERATED(BIGNUM *bn, ASN1_ENUMERATED *ai) diff --git a/src/crypto/asn1/a_int.c b/src/crypto/asn1/a_int.c index 617ba962..8a4edd69 100644 --- a/src/crypto/asn1/a_int.c +++ b/src/crypto/asn1/a_int.c @@ -57,6 +57,7 @@ #include <openssl/asn1.h> #include <string.h> +#include <limits.h> #include <openssl/err.h> #include <openssl/mem.h> @@ -385,7 +386,6 @@ int ASN1_INTEGER_set(ASN1_INTEGER *a, long v) long ASN1_INTEGER_get(const ASN1_INTEGER *a) { int neg = 0, i; - long r = 0; if (a == NULL) return (0L); @@ -395,20 +395,31 @@ long ASN1_INTEGER_get(const ASN1_INTEGER *a) else if (i != V_ASN1_INTEGER) return -1; - if (a->length > (int)sizeof(long)) { + OPENSSL_COMPILE_ASSERT(sizeof(uint64_t) >= sizeof(long), + long_larger_than_uint64_t); + + if (a->length > (int)sizeof(uint64_t)) { /* hmm... a bit ugly, return all ones */ return -1; } - if (a->data == NULL) - return 0; - for (i = 0; i < a->length; i++) { - r <<= 8; - r |= (unsigned char)a->data[i]; + uint64_t r64 = 0; + if (a->data != NULL) { + for (i = 0; i < a->length; i++) { + r64 <<= 8; + r64 |= (unsigned char)a->data[i]; + } + + if (r64 > LONG_MAX) { + return -1; + } } + + long r = (long) r64; if (neg) r = -r; - return (r); + + return r; } ASN1_INTEGER *BN_to_ASN1_INTEGER(const BIGNUM *bn, ASN1_INTEGER *ai) diff --git a/src/crypto/asn1/asn1_locl.h b/src/crypto/asn1/asn1_locl.h index fef00acf..10a832cd 100644 --- a/src/crypto/asn1/asn1_locl.h +++ b/src/crypto/asn1/asn1_locl.h @@ -90,6 +90,9 @@ int OPENSSL_gmtime_diff(int *out_days, int *out_secs, const struct tm *from, int asn1_utctime_to_tm(struct tm *tm, const ASN1_UTCTIME *d); int asn1_generalizedtime_to_tm(struct tm *tm, const ASN1_GENERALIZEDTIME *d); +void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, + int combine); + #if defined(__cplusplus) } /* extern C */ diff --git a/src/crypto/asn1/tasn_fre.c b/src/crypto/asn1/tasn_fre.c index 609cb9f9..eabc0fb5 100644 --- a/src/crypto/asn1/tasn_fre.c +++ b/src/crypto/asn1/tasn_fre.c @@ -59,8 +59,7 @@ #include <openssl/asn1t.h> #include <openssl/mem.h> -static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, - int combine); +#include "asn1_locl.h" /* Free up an ASN1 structure */ @@ -74,8 +73,7 @@ void ASN1_item_ex_free(ASN1_VALUE **pval, const ASN1_ITEM *it) asn1_item_combine_free(pval, it, 0); } -static void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, - int combine) +void asn1_item_combine_free(ASN1_VALUE **pval, const ASN1_ITEM *it, int combine) { const ASN1_TEMPLATE *tt = NULL, *seqtt; const ASN1_EXTERN_FUNCS *ef; diff --git a/src/crypto/asn1/tasn_new.c b/src/crypto/asn1/tasn_new.c index 10cf954f..5db38bef 100644 --- a/src/crypto/asn1/tasn_new.c +++ b/src/crypto/asn1/tasn_new.c @@ -63,6 +63,7 @@ #include <openssl/mem.h> #include <openssl/obj.h> +#include "asn1_locl.h" #include "../internal.h" @@ -201,7 +202,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, return 1; memerr2: - ASN1_item_ex_free(pval, it); + asn1_item_combine_free(pval, it, combine); memerr: OPENSSL_PUT_ERROR(ASN1, ERR_R_MALLOC_FAILURE); #ifdef CRYPTO_MDEBUG @@ -211,7 +212,7 @@ static int asn1_item_ex_combine_new(ASN1_VALUE **pval, const ASN1_ITEM *it, return 0; auxerr2: - ASN1_item_ex_free(pval, it); + asn1_item_combine_free(pval, it, combine); auxerr: OPENSSL_PUT_ERROR(ASN1, ASN1_R_AUX_ERROR); #ifdef CRYPTO_MDEBUG diff --git a/src/crypto/bn_extra/bn_asn1.c b/src/crypto/bn_extra/bn_asn1.c index 8b939da5..0d96573a 100644 --- a/src/crypto/bn_extra/bn_asn1.c +++ b/src/crypto/bn_extra/bn_asn1.c @@ -42,22 +42,6 @@ int BN_parse_asn1_unsigned(CBS *cbs, BIGNUM *ret) { return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; } -int BN_parse_asn1_unsigned_buggy(CBS *cbs, BIGNUM *ret) { - CBS child; - if (!CBS_get_asn1(cbs, &child, CBS_ASN1_INTEGER) || - CBS_len(&child) == 0) { - OPENSSL_PUT_ERROR(BN, BN_R_BAD_ENCODING); - return 0; - } - - // This function intentionally does not reject negative numbers or non-minimal - // encodings. Estonian IDs issued between September 2014 to September 2015 are - // broken. See https://crbug.com/532048 and https://crbug.com/534766. - // - // TODO(davidben): Remove this code and callers in March 2016. - return BN_bin2bn(CBS_data(&child), CBS_len(&child), ret) != NULL; -} - int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn) { // Negative numbers are unsupported. if (BN_is_negative(bn)) { diff --git a/src/crypto/cpu-intel.c b/src/crypto/cpu-intel.c index 127fa57a..1ac280c8 100644 --- a/src/crypto/cpu-intel.c +++ b/src/crypto/cpu-intel.c @@ -164,7 +164,7 @@ void OPENSSL_cpuid_setup(void) { uint32_t num_extended_ids = eax; if (num_extended_ids >= 0x80000001) { OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 0x80000001); - if (ecx & (1 << 11)) { + if (ecx & (1u << 11)) { has_amd_xop = 1; } } @@ -193,68 +193,68 @@ void OPENSSL_cpuid_setup(void) { OPENSSL_cpuid(&eax, &ebx, &ecx, &edx, 1); // Adjust the hyper-threading bit. - if (edx & (1 << 28)) { + if (edx & (1u << 28)) { uint32_t num_logical_cores = (ebx >> 16) & 0xff; if (cores_per_cache == 1 || num_logical_cores <= 1) { - edx &= ~(1 << 28); + edx &= ~(1u << 28); } } // Reserved bit #20 was historically repurposed to control the in-memory // representation of RC4 state. Always set it to zero. - edx &= ~(1 << 20); + edx &= ~(1u << 20); // Reserved bit #30 is repurposed to signal an Intel CPU. if (is_intel) { - edx |= (1 << 30); + edx |= (1u << 30); // Clear the XSAVE bit on Knights Landing to mimic Silvermont. This enables // some Silvermont-specific codepaths which perform better. See OpenSSL // commit 64d92d74985ebb3d0be58a9718f9e080a14a8e7f. if ((eax & 0x0fff0ff0) == 0x00050670 /* Knights Landing */ || (eax & 0x0fff0ff0) == 0x00080650 /* Knights Mill (per SDE) */) { - ecx &= ~(1 << 26); + ecx &= ~(1u << 26); } } else { - edx &= ~(1 << 30); + edx &= ~(1u << 30); } // The SDBG bit is repurposed to denote AMD XOP support. if (has_amd_xop) { - ecx |= (1 << 11); + ecx |= (1u << 11); } else { - ecx &= ~(1 << 11); + ecx &= ~(1u << 11); } uint64_t xcr0 = 0; - if (ecx & (1 << 27)) { + if (ecx & (1u << 27)) { // XCR0 may only be queried if the OSXSAVE bit is set. xcr0 = OPENSSL_xgetbv(0); } // See Intel manual, volume 1, section 14.3. if ((xcr0 & 6) != 6) { // YMM registers cannot be used. - ecx &= ~(1 << 28); // AVX - ecx &= ~(1 << 12); // FMA - ecx &= ~(1 << 11); // AMD XOP + ecx &= ~(1u << 28); // AVX + ecx &= ~(1u << 12); // FMA + ecx &= ~(1u << 11); // AMD XOP // Clear AVX2 and AVX512* bits. // // TODO(davidben): Should bits 17 and 26-28 also be cleared? Upstream // doesn't clear those. extended_features &= - ~((1 << 5) | (1 << 16) | (1 << 21) | (1 << 30) | (1 << 31)); + ~((1u << 5) | (1u << 16) | (1u << 21) | (1u << 30) | (1u << 31)); } // See Intel manual, volume 1, section 15.2. if ((xcr0 & 0xe6) != 0xe6) { // Clear AVX512F. Note we don't touch other AVX512 extensions because they // can be used with YMM. - extended_features &= ~(1 << 16); + extended_features &= ~(1u << 16); } // Disable ADX instructions on Knights Landing. See OpenSSL commit // 64d92d74985ebb3d0be58a9718f9e080a14a8e7f. - if ((ecx & (1 << 26)) == 0) { - extended_features &= ~(1 << 19); + if ((ecx & (1u << 26)) == 0) { + extended_features &= ~(1u << 19); } OPENSSL_ia32cap_P[0] = edx; diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c index 390cd8bb..9f4639f2 100644 --- a/src/crypto/crypto.c +++ b/src/crypto/crypto.c @@ -40,6 +40,18 @@ OPENSSL_ARM || OPENSSL_AARCH64) */ +// Our assembly does not use the GOT to reference symbols, which means +// references to visible symbols will often require a TEXTREL. This is +// undesirable, so all assembly-referenced symbols should be hidden. CPU +// capabilities are the only such symbols defined in C. Explicitly hide them, +// rather than rely on being built with -fvisibility=hidden. +#if defined(OPENSSL_WINDOWS) +#define HIDDEN +#else +#define HIDDEN __attribute__((visibility("hidden"))) +#endif + + // The capability variables are defined in this file in order to work around a // linker bug. When linking with a .a, if no symbols in a .o are referenced // then the .o is discarded, even if it has constructor functions. @@ -57,11 +69,11 @@ // archive, linking on OS X will fail to resolve common symbols. By // initialising it to zero, it becomes a "data symbol", which isn't so // affected. -uint32_t OPENSSL_ia32cap_P[4] = {0}; +HIDDEN uint32_t OPENSSL_ia32cap_P[4] = {0}; #elif defined(OPENSSL_PPC64LE) -unsigned long OPENSSL_ppc64le_hwcap2 = 0; +HIDDEN unsigned long OPENSSL_ppc64le_hwcap2 = 0; #elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64) @@ -69,7 +81,7 @@ unsigned long OPENSSL_ppc64le_hwcap2 = 0; #if defined(OPENSSL_STATIC_ARMCAP) -uint32_t OPENSSL_armcap_P = +HIDDEN uint32_t OPENSSL_armcap_P = #if defined(OPENSSL_STATIC_ARMCAP_NEON) || defined(__ARM_NEON__) ARMV7_NEON | #endif @@ -88,7 +100,7 @@ uint32_t OPENSSL_armcap_P = 0; #else -uint32_t OPENSSL_armcap_P = 0; +HIDDEN uint32_t OPENSSL_armcap_P = 0; #endif #endif diff --git a/src/crypto/ecdh/ecdh_test.cc b/src/crypto/ecdh/ecdh_test.cc index b3114453..6d48408b 100644 --- a/src/crypto/ecdh/ecdh_test.cc +++ b/src/crypto/ecdh/ecdh_test.cc @@ -14,6 +14,7 @@ #include <stdio.h> +#include <utility> #include <vector> #include <gtest/gtest.h> @@ -23,6 +24,7 @@ #include <openssl/ec.h> #include <openssl/ec_key.h> #include <openssl/ecdh.h> +#include <openssl/err.h> #include <openssl/nid.h> #include "../test/file_test.h" @@ -112,3 +114,98 @@ TEST(ECDHTest, TestVectors) { Bytes(actual_z.data(), static_cast<size_t>(ret))); }); } + +// MakeCustomGroup returns an |EC_GROUP| containing a non-standard group. (P-256 +// with the wrong generator.) +static bssl::UniquePtr<EC_GROUP> MakeCustomGroup() { + static const uint8_t kP[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + }; + static const uint8_t kA[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + }; + static const uint8_t kB[] = { + 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, + 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, + 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, + }; + static const uint8_t kX[] = { + 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, + }; + static const uint8_t kY[] = { + 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 const uint8_t kOrder[] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, + 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, + }; + bssl::UniquePtr<BN_CTX> ctx(BN_CTX_new()); + bssl::UniquePtr<BIGNUM> p(BN_bin2bn(kP, sizeof(kP), nullptr)); + bssl::UniquePtr<BIGNUM> a(BN_bin2bn(kA, sizeof(kA), nullptr)); + bssl::UniquePtr<BIGNUM> b(BN_bin2bn(kB, sizeof(kB), nullptr)); + bssl::UniquePtr<BIGNUM> x(BN_bin2bn(kX, sizeof(kX), nullptr)); + bssl::UniquePtr<BIGNUM> y(BN_bin2bn(kY, sizeof(kY), nullptr)); + bssl::UniquePtr<BIGNUM> order(BN_bin2bn(kOrder, sizeof(kOrder), nullptr)); + if (!ctx || !p || !a || !b || !x || !y || !order) { + return nullptr; + } + bssl::UniquePtr<EC_GROUP> group( + EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get())); + if (!group) { + return nullptr; + } + bssl::UniquePtr<EC_POINT> generator(EC_POINT_new(group.get())); + if (!generator || + !EC_POINT_set_affine_coordinates_GFp(group.get(), generator.get(), + x.get(), y.get(), ctx.get()) || + !EC_GROUP_set_generator(group.get(), generator.get(), order.get(), + BN_value_one())) { + return nullptr; + } + return group; +} + +TEST(ECDHTest, GroupMismatch) { + const size_t num_curves = EC_get_builtin_curves(nullptr, 0); + std::vector<EC_builtin_curve> curves(num_curves); + EC_get_builtin_curves(curves.data(), num_curves); + + // Instantiate all the built-in curves. + std::vector<bssl::UniquePtr<EC_GROUP>> groups; + for (const auto &curve : curves) { + groups.emplace_back(EC_GROUP_new_by_curve_name(curve.nid)); + ASSERT_TRUE(groups.back()); + } + + // Also create some arbitrary group. (This is P-256 with the wrong generator.) + groups.push_back(MakeCustomGroup()); + ASSERT_TRUE(groups.back()); + + for (const auto &a : groups) { + for (const auto &b : groups) { + if (a.get() == b.get()) { + continue; + } + + bssl::UniquePtr<EC_KEY> key(EC_KEY_new()); + ASSERT_TRUE(EC_KEY_set_group(key.get(), a.get())); + ASSERT_TRUE(EC_KEY_generate_key(key.get())); + + // ECDH across the groups should not work. + char out[64]; + const EC_POINT *peer = EC_GROUP_get0_generator(b.get()); + EXPECT_EQ(-1, + ECDH_compute_key(out, sizeof(out), peer, key.get(), nullptr)); + ERR_clear_error(); + } + } +} diff --git a/src/crypto/evp/p_rsa_asn1.c b/src/crypto/evp/p_rsa_asn1.c index 5157a89d..a1885383 100644 --- a/src/crypto/evp/p_rsa_asn1.c +++ b/src/crypto/evp/p_rsa_asn1.c @@ -63,19 +63,9 @@ #include <openssl/rsa.h> #include "../fipsmodule/rsa/internal.h" -#include "../internal.h" #include "internal.h" -static struct CRYPTO_STATIC_MUTEX g_buggy_lock = CRYPTO_STATIC_MUTEX_INIT; -static int g_buggy = 0; - -void EVP_set_buggy_rsa_parser(int buggy) { - CRYPTO_STATIC_MUTEX_lock_write(&g_buggy_lock); - g_buggy = buggy; - CRYPTO_STATIC_MUTEX_unlock_write(&g_buggy_lock); -} - static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) { // See RFC 3279, section 2.3.1. CBB spki, algorithm, oid, null, key_bitstring; @@ -96,11 +86,6 @@ static int rsa_pub_encode(CBB *out, const EVP_PKEY *key) { } static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { - int buggy; - CRYPTO_STATIC_MUTEX_lock_read(&g_buggy_lock); - buggy = g_buggy; - CRYPTO_STATIC_MUTEX_unlock_read(&g_buggy_lock); - // See RFC 3279, section 2.3.1. // The parameters must be NULL. @@ -112,13 +97,7 @@ static int rsa_pub_decode(EVP_PKEY *out, CBS *params, CBS *key) { return 0; } - // Estonian IDs issued between September 2014 to September 2015 are - // broken. See https://crbug.com/532048 and https://crbug.com/534766. - // - // TODO(davidben): Switch this to the strict version in March 2016 or when - // Chromium can force client certificates down a different codepath, whichever - // comes first. - RSA *rsa = buggy ? RSA_parse_public_key_buggy(key) : RSA_parse_public_key(key); + RSA *rsa = RSA_parse_public_key(key); if (rsa == NULL || CBS_len(key) != 0) { OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR); RSA_free(rsa); diff --git a/src/crypto/ex_data.c b/src/crypto/ex_data.c index af7e7e2d..71d60a52 100644 --- a/src/crypto/ex_data.c +++ b/src/crypto/ex_data.c @@ -113,7 +113,6 @@ #include <openssl/crypto.h> #include <openssl/err.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/stack.h> #include <openssl/thread.h> diff --git a/src/crypto/fipsmodule/bn/add.c b/src/crypto/fipsmodule/bn/add.c index bbe275ed..201c526d 100644 --- a/src/crypto/fipsmodule/bn/add.c +++ b/src/crypto/fipsmodule/bn/add.c @@ -133,7 +133,7 @@ int BN_uadd(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { while (dif) { dif--; t1 = *(ap++); - t2 = (t1 + 1) & BN_MASK2; + t2 = t1 + 1; *(rp++) = t2; if (t2) { carry = 0; @@ -162,8 +162,6 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) { BN_ULONG l; int i; - w &= BN_MASK2; - // degenerate case: w is zero if (!w) { return 1; @@ -185,7 +183,7 @@ int BN_add_word(BIGNUM *a, BN_ULONG w) { } for (i = 0; w != 0 && i < a->top; i++) { - a->d[i] = l = (a->d[i] + w) & BN_MASK2; + a->d[i] = l = a->d[i] + w; w = (w > l) ? 1 : 0; } @@ -285,12 +283,12 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { t2 = *(bp++); if (carry) { carry = (t1 <= t2); - t1 = (t1 - t2 - 1) & BN_MASK2; + t1 -= t2 + 1; } else { carry = (t1 < t2); - t1 = (t1 - t2) & BN_MASK2; + t1 -= t2; } - *(rp++) = t1 & BN_MASK2; + *(rp++) = t1; } if (carry) // subtracted @@ -303,7 +301,7 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { while (dif) { dif--; t1 = *(ap++); - t2 = (t1 - 1) & BN_MASK2; + t2 = t1 - 1; *(rp++) = t2; if (t1) { break; @@ -325,8 +323,6 @@ int BN_usub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) { int BN_sub_word(BIGNUM *a, BN_ULONG w) { int i; - w &= BN_MASK2; - // degenerate case: w is zero if (!w) { return 1; @@ -361,7 +357,7 @@ int BN_sub_word(BIGNUM *a, BN_ULONG w) { a->d[i] -= w; break; } else { - a->d[i] = (a->d[i] - w) & BN_MASK2; + a->d[i] -= w; i++; w = 1; } diff --git a/src/crypto/fipsmodule/bn/bn_test.cc b/src/crypto/fipsmodule/bn/bn_test.cc index fe03e5fa..975264e0 100644 --- a/src/crypto/fipsmodule/bn/bn_test.cc +++ b/src/crypto/fipsmodule/bn/bn_test.cc @@ -778,27 +778,27 @@ static int DecimalToBIGNUM(bssl::UniquePtr<BIGNUM> *out, const char *in) { TEST_F(BNTest, Dec2BN) { bssl::UniquePtr<BIGNUM> bn; int ret = DecimalToBIGNUM(&bn, "0"); - EXPECT_EQ(1, ret); + ASSERT_EQ(1, ret); EXPECT_TRUE(BN_is_zero(bn.get())); EXPECT_FALSE(BN_is_negative(bn.get())); ret = DecimalToBIGNUM(&bn, "256"); - EXPECT_EQ(3, ret); + ASSERT_EQ(3, ret); EXPECT_TRUE(BN_is_word(bn.get(), 256)); EXPECT_FALSE(BN_is_negative(bn.get())); ret = DecimalToBIGNUM(&bn, "-42"); - EXPECT_EQ(3, ret); + ASSERT_EQ(3, ret); EXPECT_TRUE(BN_abs_is_word(bn.get(), 42)); EXPECT_TRUE(BN_is_negative(bn.get())); ret = DecimalToBIGNUM(&bn, "-0"); - EXPECT_EQ(2, ret); + ASSERT_EQ(2, ret); EXPECT_TRUE(BN_is_zero(bn.get())); EXPECT_FALSE(BN_is_negative(bn.get())); ret = DecimalToBIGNUM(&bn, "42trailing garbage is ignored"); - EXPECT_EQ(2, ret); + ASSERT_EQ(2, ret); EXPECT_TRUE(BN_abs_is_word(bn.get(), 42)); EXPECT_FALSE(BN_is_negative(bn.get())); } @@ -806,27 +806,27 @@ TEST_F(BNTest, Dec2BN) { TEST_F(BNTest, Hex2BN) { bssl::UniquePtr<BIGNUM> bn; int ret = HexToBIGNUM(&bn, "0"); - EXPECT_EQ(1, ret); + ASSERT_EQ(1, ret); EXPECT_TRUE(BN_is_zero(bn.get())); EXPECT_FALSE(BN_is_negative(bn.get())); ret = HexToBIGNUM(&bn, "256"); - EXPECT_EQ(3, ret); + ASSERT_EQ(3, ret); EXPECT_TRUE(BN_is_word(bn.get(), 0x256)); EXPECT_FALSE(BN_is_negative(bn.get())); ret = HexToBIGNUM(&bn, "-42"); - EXPECT_EQ(3, ret); + ASSERT_EQ(3, ret); EXPECT_TRUE(BN_abs_is_word(bn.get(), 0x42)); EXPECT_TRUE(BN_is_negative(bn.get())); ret = HexToBIGNUM(&bn, "-0"); - EXPECT_EQ(2, ret); + ASSERT_EQ(2, ret); EXPECT_TRUE(BN_is_zero(bn.get())); EXPECT_FALSE(BN_is_negative(bn.get())); ret = HexToBIGNUM(&bn, "abctrailing garbage is ignored"); - EXPECT_EQ(3, ret); + ASSERT_EQ(3, ret); EXPECT_TRUE(BN_is_word(bn.get(), 0xabc)); EXPECT_FALSE(BN_is_negative(bn.get())); } @@ -1000,16 +1000,11 @@ static const ASN1InvalidTest kASN1InvalidTests[] = { {"\x03\x01\x00", 3}, // Empty contents. {"\x02\x00", 2}, -}; - -// kASN1BuggyTests contains incorrect encodings and the corresponding, expected -// results of |BN_parse_asn1_unsigned_buggy| given that input. -static const ASN1Test kASN1BuggyTests[] = { // Negative numbers. - {"128", "\x02\x01\x80", 3}, - {"255", "\x02\x01\xff", 3}, + {"\x02\x01\x80", 3}, + {"\x02\x01\xff", 3}, // Unnecessary leading zeros. - {"1", "\x02\x02\x00\x01", 4}, + {"\x02\x02\x00\x01", 4}, }; TEST_F(BNTest, ASN1) { @@ -1036,12 +1031,6 @@ TEST_F(BNTest, ASN1) { ASSERT_TRUE(CBB_finish(cbb.get(), &der, &der_len)); bssl::UniquePtr<uint8_t> delete_der(der); EXPECT_EQ(Bytes(test.der, test.der_len), Bytes(der, der_len)); - - // |BN_parse_asn1_unsigned_buggy| parses all valid input. - CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); - ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn2.get())); - EXPECT_EQ(0u, CBS_len(&cbs)); - EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn.get(), bn2.get()); } for (const ASN1InvalidTest &test : kASN1InvalidTests) { @@ -1053,35 +1042,6 @@ TEST_F(BNTest, ASN1) { EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get())) << "Parsed invalid input."; ERR_clear_error(); - - // All tests in kASN1InvalidTests are also rejected by - // |BN_parse_asn1_unsigned_buggy|. - CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); - EXPECT_FALSE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get())) - << "Parsed invalid input."; - ERR_clear_error(); - } - - for (const ASN1Test &test : kASN1BuggyTests) { - SCOPED_TRACE(Bytes(test.der, test.der_len)); - - // These broken encodings are rejected by |BN_parse_asn1_unsigned|. - bssl::UniquePtr<BIGNUM> bn(BN_new()); - ASSERT_TRUE(bn); - CBS cbs; - CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); - EXPECT_FALSE(BN_parse_asn1_unsigned(&cbs, bn.get())) - << "Parsed invalid input."; - ERR_clear_error(); - - // However |BN_parse_asn1_unsigned_buggy| accepts them. - bssl::UniquePtr<BIGNUM> bn2 = ASCIIToBIGNUM(test.value_ascii); - ASSERT_TRUE(bn2); - - CBS_init(&cbs, reinterpret_cast<const uint8_t*>(test.der), test.der_len); - ASSERT_TRUE(BN_parse_asn1_unsigned_buggy(&cbs, bn.get())); - EXPECT_EQ(0u, CBS_len(&cbs)); - EXPECT_BIGNUMS_EQUAL("decode ASN.1 buggy", bn2.get(), bn.get()); } // Serializing negative numbers is not supported. diff --git a/src/crypto/fipsmodule/bn/bn_test_to_fuzzer.go b/src/crypto/fipsmodule/bn/bn_test_to_fuzzer.go new file mode 100644 index 00000000..d1ee734c --- /dev/null +++ b/src/crypto/fipsmodule/bn/bn_test_to_fuzzer.go @@ -0,0 +1,234 @@ +// Copyright (c) 2017, Google Inc. +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION +// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +package main + +import ( + "bufio" + "crypto/sha1" + "encoding/hex" + "errors" + "fmt" + "io" + "io/ioutil" + "math/big" + "os" + "path/filepath" + "strings" +) + +type test struct { + LineNumber int + Type string + Values map[string]*big.Int +} + +type testScanner struct { + scanner *bufio.Scanner + lineNo int + err error + test test +} + +func newTestScanner(r io.Reader) *testScanner { + return &testScanner{scanner: bufio.NewScanner(r)} +} + +func (s *testScanner) scanLine() bool { + if !s.scanner.Scan() { + return false + } + s.lineNo++ + return true +} + +func (s *testScanner) addAttribute(line string) (key string, ok bool) { + fields := strings.SplitN(line, "=", 2) + if len(fields) != 2 { + s.setError(errors.New("invalid syntax")) + return "", false + } + + key = strings.TrimSpace(fields[0]) + value := strings.TrimSpace(fields[1]) + + valueInt, ok := new(big.Int).SetString(value, 16) + if !ok { + s.setError(fmt.Errorf("could not parse %q", value)) + return "", false + } + if _, dup := s.test.Values[key]; dup { + s.setError(fmt.Errorf("duplicate key %q", key)) + return "", false + } + s.test.Values[key] = valueInt + return key, true +} + +func (s *testScanner) Scan() bool { + s.test = test{ + Values: make(map[string]*big.Int), + } + + // Scan until the first attribute. + for { + if !s.scanLine() { + return false + } + if len(s.scanner.Text()) != 0 && s.scanner.Text()[0] != '#' { + break + } + } + + var ok bool + s.test.Type, ok = s.addAttribute(s.scanner.Text()) + if !ok { + return false + } + s.test.LineNumber = s.lineNo + + for s.scanLine() { + if len(s.scanner.Text()) == 0 { + break + } + + if s.scanner.Text()[0] == '#' { + continue + } + + if _, ok := s.addAttribute(s.scanner.Text()); !ok { + return false + } + } + return s.scanner.Err() == nil +} + +func (s *testScanner) Test() test { + return s.test +} + +func (s *testScanner) Err() error { + if s.err != nil { + return s.err + } + return s.scanner.Err() +} + +func (s *testScanner) setError(err error) { + s.err = fmt.Errorf("line %d: %s", s.lineNo, err) +} + +func checkKeys(t test, keys ...string) bool { + var foundErrors bool + + for _, k := range keys { + if _, ok := t.Values[k]; !ok { + fmt.Fprintf(os.Stderr, "Line %d: missing key %q.\n", t.LineNumber, k) + foundErrors = true + } + } + + for k, _ := range t.Values { + var found bool + for _, k2 := range keys { + if k == k2 { + found = true + break + } + } + if !found { + fmt.Fprintf(os.Stderr, "Line %d: unexpected key %q.\n", t.LineNumber, k) + foundErrors = true + } + } + + return !foundErrors +} + +func appendLengthPrefixed(ret, b []byte) []byte { + ret = append(ret, byte(len(b)>>8), byte(len(b))) + ret = append(ret, b...) + return ret +} + +func appendUnsigned(ret []byte, n *big.Int) []byte { + b := n.Bytes() + if n.Sign() == 0 { + b = []byte{0} + } + return appendLengthPrefixed(ret, b) +} + +func appendSigned(ret []byte, n *big.Int) []byte { + var sign byte + if n.Sign() < 0 { + sign = 1 + } + b := []byte{sign} + b = append(b, n.Bytes()...) + if n.Sign() == 0 { + b = append(b, 0) + } + return appendLengthPrefixed(ret, b) +} + +func main() { + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, "Usage: %s TESTS FUZZ_DIR\n", os.Args[0]) + os.Exit(1) + } + + in, err := os.Open(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "Error opening %s: %s.\n", os.Args[0], err) + os.Exit(1) + } + defer in.Close() + + fuzzerDir := os.Args[2] + + scanner := newTestScanner(in) + for scanner.Scan() { + var fuzzer string + var b []byte + test := scanner.Test() + switch test.Type { + case "Quotient": + if checkKeys(test, "A", "B", "Quotient", "Remainder") { + fuzzer = "bn_div" + b = appendSigned(b, test.Values["A"]) + b = appendSigned(b, test.Values["B"]) + } + case "ModExp": + if checkKeys(test, "A", "E", "M", "ModExp") { + fuzzer = "bn_mod_exp" + b = appendSigned(b, test.Values["A"]) + b = appendUnsigned(b, test.Values["E"]) + b = appendUnsigned(b, test.Values["M"]) + } + } + + if len(fuzzer) != 0 { + hash := sha1.Sum(b) + path := filepath.Join(fuzzerDir, fuzzer + "_corpus", hex.EncodeToString(hash[:])) + if err := ioutil.WriteFile(path, b, 0666); err != nil { + fmt.Fprintf(os.Stderr, "Error writing to %s: %s.\n", path, err) + os.Exit(1) + } + } + } + if scanner.Err() != nil { + fmt.Fprintf(os.Stderr, "Error reading tests: %s.\n", scanner.Err()) + } +} diff --git a/src/crypto/fipsmodule/bn/div.c b/src/crypto/fipsmodule/bn/div.c index 1bcff507..0b8b9b9d 100644 --- a/src/crypto/fipsmodule/bn/div.c +++ b/src/crypto/fipsmodule/bn/div.c @@ -128,7 +128,7 @@ static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) { } ret = q << BN_BITS4; - h = ((h << BN_BITS4) | (l >> BN_BITS4)) & BN_MASK2; + h = (h << BN_BITS4) | (l >> BN_BITS4); l = (l & BN_MASK2l) << BN_BITS4; } @@ -569,8 +569,6 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { BN_ULONG ret = 0; int i, j; - w &= BN_MASK2; - if (!w) { // actually this an error (division by zero) return (BN_ULONG) - 1; @@ -592,7 +590,7 @@ BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) { BN_ULONG d; BN_ULONG unused_rem; bn_div_rem_words(&d, &unused_rem, ret, l, w); - ret = (l - ((d * w) & BN_MASK2)) & BN_MASK2; + ret = l - (d * w); a->d[i] = d; } @@ -634,7 +632,6 @@ BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) { } #endif - w &= BN_MASK2; for (i = a->top - 1; i >= 0; i--) { #ifndef BN_ULLONG ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w; diff --git a/src/crypto/fipsmodule/bn/exponentiation.c b/src/crypto/fipsmodule/bn/exponentiation.c index f4e028b2..b6b7fa9e 100644 --- a/src/crypto/fipsmodule/bn/exponentiation.c +++ b/src/crypto/fipsmodule/bn/exponentiation.c @@ -655,9 +655,9 @@ int BN_mod_exp_mont(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, goto err; } // 2^(top*BN_BITS2) - m - r->d[0] = (0 - m->d[0]) & BN_MASK2; + r->d[0] = 0 - m->d[0]; for (i = 1; i < j; i++) { - r->d[i] = (~m->d[i]) & BN_MASK2; + r->d[i] = ~m->d[i]; } r->top = j; // Upper words will be zero if the corresponding words of 'm' @@ -963,9 +963,9 @@ int BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, // by Shay Gueron's suggestion if (m->d[top - 1] & (((BN_ULONG)1) << (BN_BITS2 - 1))) { // 2^(top*BN_BITS2) - m - tmp.d[0] = (0 - m->d[0]) & BN_MASK2; + tmp.d[0] = 0 - m->d[0]; for (i = 1; i < top; i++) { - tmp.d[i] = (~m->d[i]) & BN_MASK2; + tmp.d[i] = ~m->d[i]; } tmp.top = top; } else if (!BN_to_montgomery(&tmp, BN_value_one(), mont, ctx)) { diff --git a/src/crypto/fipsmodule/bn/generic.c b/src/crypto/fipsmodule/bn/generic.c index b70080f0..11c377ca 100644 --- a/src/crypto/fipsmodule/bn/generic.c +++ b/src/crypto/fipsmodule/bn/generic.c @@ -209,21 +209,21 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, assert(n >= 0); if (n <= 0) { - return (BN_ULONG)0; + return 0; } while (n & ~3) { ll += (BN_ULLONG)a[0] + b[0]; - r[0] = (BN_ULONG)ll & BN_MASK2; + r[0] = (BN_ULONG)ll; ll >>= BN_BITS2; ll += (BN_ULLONG)a[1] + b[1]; - r[1] = (BN_ULONG)ll & BN_MASK2; + r[1] = (BN_ULONG)ll; ll >>= BN_BITS2; ll += (BN_ULLONG)a[2] + b[2]; - r[2] = (BN_ULONG)ll & BN_MASK2; + r[2] = (BN_ULONG)ll; ll >>= BN_BITS2; ll += (BN_ULLONG)a[3] + b[3]; - r[3] = (BN_ULONG)ll & BN_MASK2; + r[3] = (BN_ULONG)ll; ll >>= BN_BITS2; a += 4; b += 4; @@ -232,7 +232,7 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, } while (n) { ll += (BN_ULLONG)a[0] + b[0]; - r[0] = (BN_ULONG)ll & BN_MASK2; + r[0] = (BN_ULONG)ll; ll >>= BN_BITS2; a++; b++; @@ -256,27 +256,27 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, c = 0; while (n & ~3) { t = a[0]; - t = (t + c) & BN_MASK2; + t += c; c = (t < c); - l = (t + b[0]) & BN_MASK2; + l = t + b[0]; c += (l < t); r[0] = l; t = a[1]; - t = (t + c) & BN_MASK2; + t += c; c = (t < c); - l = (t + b[1]) & BN_MASK2; + l = t + b[1]; c += (l < t); r[1] = l; t = a[2]; - t = (t + c) & BN_MASK2; + t += c; c = (t < c); - l = (t + b[2]) & BN_MASK2; + l = t + b[2]; c += (l < t); r[2] = l; t = a[3]; - t = (t + c) & BN_MASK2; + t += c; c = (t < c); - l = (t + b[3]) & BN_MASK2; + l = t + b[3]; c += (l < t); r[3] = l; a += 4; @@ -286,9 +286,9 @@ BN_ULONG bn_add_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, } while (n) { t = a[0]; - t = (t + c) & BN_MASK2; + t += c; c = (t < c); - l = (t + b[0]) & BN_MASK2; + l = t + b[0]; c += (l < t); r[0] = l; a++; @@ -314,25 +314,25 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, while (n & ~3) { t1 = a[0]; t2 = b[0]; - r[0] = (t1 - t2 - c) & BN_MASK2; + r[0] = t1 - t2 - c; if (t1 != t2) { c = (t1 < t2); } t1 = a[1]; t2 = b[1]; - r[1] = (t1 - t2 - c) & BN_MASK2; + r[1] = t1 - t2 - c; if (t1 != t2) { c = (t1 < t2); } t1 = a[2]; t2 = b[2]; - r[2] = (t1 - t2 - c) & BN_MASK2; + r[2] = t1 - t2 - c; if (t1 != t2) { c = (t1 < t2); } t1 = a[3]; t2 = b[3]; - r[3] = (t1 - t2 - c) & BN_MASK2; + r[3] = t1 - t2 - c; if (t1 != t2) { c = (t1 < t2); } @@ -344,7 +344,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, while (n) { t1 = a[0]; t2 = b[0]; - r[0] = (t1 - t2 - c) & BN_MASK2; + r[0] = t1 - t2 - c; if (t1 != t2) { c = (t1 < t2); } @@ -372,7 +372,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, t += (c0); /* no carry */ \ (c0) = (BN_ULONG)Lw(t); \ hi = (BN_ULONG)Hw(t); \ - (c1) = ((c1) + (hi)) & BN_MASK2; \ + (c1) += (hi); \ if ((c1) < hi) { \ (c2)++; \ } \ @@ -385,14 +385,14 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, BN_ULLONG tt = t + (c0); /* no carry */ \ (c0) = (BN_ULONG)Lw(tt); \ hi = (BN_ULONG)Hw(tt); \ - (c1) = ((c1) + hi) & BN_MASK2; \ + (c1) += hi; \ if ((c1) < hi) { \ (c2)++; \ } \ t += (c0); /* no carry */ \ (c0) = (BN_ULONG)Lw(t); \ hi = (BN_ULONG)Hw(t); \ - (c1) = ((c1) + hi) & BN_MASK2; \ + (c1) += hi; \ if ((c1) < hi) { \ (c2)++; \ } \ @@ -405,7 +405,7 @@ BN_ULONG bn_sub_words(BN_ULONG *r, const BN_ULONG *a, const BN_ULONG *b, t += (c0); /* no carry */ \ (c0) = (BN_ULONG)Lw(t); \ hi = (BN_ULONG)Hw(t); \ - (c1) = ((c1) + hi) & BN_MASK2; \ + (c1) += hi; \ if ((c1) < hi) { \ (c2)++; \ } \ diff --git a/src/crypto/fipsmodule/bn/internal.h b/src/crypto/fipsmodule/bn/internal.h index ecd7d6cb..b1e0b0de 100644 --- a/src/crypto/fipsmodule/bn/internal.h +++ b/src/crypto/fipsmodule/bn/internal.h @@ -191,8 +191,8 @@ extern "C" { } #if defined(BN_ULLONG) -#define Lw(t) (((BN_ULONG)(t))&BN_MASK2) -#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2) +#define Lw(t) ((BN_ULONG)(t)) +#define Hw(t) ((BN_ULONG)((t) >> BN_BITS2)) #endif // bn_correct_top decrements |bn->top| until |bn->d[top-1]| is non-zero or diff --git a/src/crypto/fipsmodule/bn/montgomery.c b/src/crypto/fipsmodule/bn/montgomery.c index 8024e276..5219187d 100644 --- a/src/crypto/fipsmodule/bn/montgomery.c +++ b/src/crypto/fipsmodule/bn/montgomery.c @@ -290,8 +290,8 @@ static int BN_from_montgomery_word(BIGNUM *ret, BIGNUM *r, n0 = mont->n0[0]; for (carry = 0, i = 0; i < nl; i++, rp++) { - v = bn_mul_add_words(rp, np, nl, (rp[0] * n0) & BN_MASK2); - v = (v + carry + rp[nl]) & BN_MASK2; + v = bn_mul_add_words(rp, np, nl, rp[0] * n0); + v += carry + rp[nl]; carry |= (v != rp[nl]); carry &= (v <= rp[nl]); rp[nl] = v; diff --git a/src/crypto/fipsmodule/bn/mul.c b/src/crypto/fipsmodule/bn/mul.c index a4e27f2a..b6f3ff18 100644 --- a/src/crypto/fipsmodule/bn/mul.c +++ b/src/crypto/fipsmodule/bn/mul.c @@ -141,7 +141,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, if (dl < 0) { for (;;) { t = b[0]; - r[0] = (0 - t - c) & BN_MASK2; + r[0] = 0 - t - c; if (t != 0) { c = 1; } @@ -150,7 +150,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = b[1]; - r[1] = (0 - t - c) & BN_MASK2; + r[1] = 0 - t - c; if (t != 0) { c = 1; } @@ -159,7 +159,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = b[2]; - r[2] = (0 - t - c) & BN_MASK2; + r[2] = 0 - t - c; if (t != 0) { c = 1; } @@ -168,7 +168,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = b[3]; - r[3] = (0 - t - c) & BN_MASK2; + r[3] = 0 - t - c; if (t != 0) { c = 1; } @@ -183,7 +183,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, int save_dl = dl; while (c) { t = a[0]; - r[0] = (t - c) & BN_MASK2; + r[0] = t - c; if (t != 0) { c = 0; } @@ -192,7 +192,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = a[1]; - r[1] = (t - c) & BN_MASK2; + r[1] = t - c; if (t != 0) { c = 0; } @@ -201,7 +201,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = a[2]; - r[2] = (t - c) & BN_MASK2; + r[2] = t - c; if (t != 0) { c = 0; } @@ -210,7 +210,7 @@ static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, } t = a[3]; - r[3] = (t - c) & BN_MASK2; + r[3] = t - c; if (t != 0) { c = 0; } @@ -407,7 +407,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, if (c1) { p = &(r[n + n2]); lo = *p; - ln = (lo + c1) & BN_MASK2; + ln = lo + c1; *p = ln; // The overflow will stop before we over write @@ -416,7 +416,7 @@ static void bn_mul_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n2, do { p++; lo = *p; - ln = (lo + 1) & BN_MASK2; + ln = lo + 1; *p = ln; } while (ln == 0); } @@ -544,7 +544,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, if (c1) { p = &(r[n + n2]); lo = *p; - ln = (lo + c1) & BN_MASK2; + ln = lo + c1; *p = ln; // The overflow will stop before we over write @@ -553,7 +553,7 @@ static void bn_mul_part_recursive(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b, int n, do { p++; lo = *p; - ln = (lo + 1) & BN_MASK2; + ln = lo + 1; *p = ln; } while (ln == 0); } @@ -757,7 +757,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t if (c1) { p = &(r[n + n2]); lo = *p; - ln = (lo + c1) & BN_MASK2; + ln = lo + c1; *p = ln; // The overflow will stop before we over write @@ -766,7 +766,7 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t do { p++; lo = *p; - ln = (lo + 1) & BN_MASK2; + ln = lo + 1; *p = ln; } while (ln == 0); } @@ -774,9 +774,6 @@ static void bn_sqr_recursive(BN_ULONG *r, const BN_ULONG *a, int n2, BN_ULONG *t } int BN_mul_word(BIGNUM *bn, BN_ULONG w) { - BN_ULONG ll; - - w &= BN_MASK2; if (!bn->top) { return 1; } @@ -786,7 +783,7 @@ int BN_mul_word(BIGNUM *bn, BN_ULONG w) { return 1; } - ll = bn_mul_words(bn->d, bn->d, bn->top, w); + BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->top, w); if (ll) { if (!bn_wexpand(bn, bn->top + 1)) { return 0; diff --git a/src/crypto/fipsmodule/bn/shift.c b/src/crypto/fipsmodule/bn/shift.c index d3fcf395..64afa782 100644 --- a/src/crypto/fipsmodule/bn/shift.c +++ b/src/crypto/fipsmodule/bn/shift.c @@ -90,8 +90,8 @@ int BN_lshift(BIGNUM *r, const BIGNUM *a, int n) { } else { for (i = a->top - 1; i >= 0; i--) { l = f[i]; - t[nw + i + 1] |= (l >> rb) & BN_MASK2; - t[nw + i] = (l << lb) & BN_MASK2; + t[nw + i + 1] |= l >> rb; + t[nw + i] = l << lb; } } OPENSSL_memset(t, 0, nw * sizeof(t[0])); @@ -121,7 +121,7 @@ int BN_lshift1(BIGNUM *r, const BIGNUM *a) { c = 0; for (i = 0; i < a->top; i++) { t = *(ap++); - *(rp++) = ((t << 1) | c) & BN_MASK2; + *(rp++) = (t << 1) | c; c = (t & BN_TBIT) ? 1 : 0; } if (c) { @@ -173,11 +173,12 @@ int BN_rshift(BIGNUM *r, const BIGNUM *a, int n) { } else { l = *(f++); for (i = j - 1; i != 0; i--) { - tmp = (l >> rb) & BN_MASK2; + tmp = l >> rb; l = *(f++); - *(t++) = (tmp | (l << lb)) & BN_MASK2; + *(t++) = tmp | (l << lb); } - if ((l = (l >> rb) & BN_MASK2)) { + l >>= rb; + if (l) { *(t) = l; } } @@ -214,7 +215,7 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) { } while (i > 0) { t = ap[--i]; - rp[i] = ((t >> 1) & BN_MASK2) | c; + rp[i] = (t >> 1) | c; c = (t & 1) ? BN_TBIT : 0; } r->top = j; @@ -227,19 +228,17 @@ int BN_rshift1(BIGNUM *r, const BIGNUM *a) { } int BN_set_bit(BIGNUM *a, int n) { - int i, j, k; - if (n < 0) { return 0; } - i = n / BN_BITS2; - j = n % BN_BITS2; + int i = n / BN_BITS2; + int j = n % BN_BITS2; if (a->top <= i) { if (!bn_wexpand(a, i + 1)) { return 0; } - for (k = a->top; k < i + 1; k++) { + for (int k = a->top; k < i + 1; k++) { a->d[k] = 0; } a->top = i + 1; @@ -269,13 +268,11 @@ int BN_clear_bit(BIGNUM *a, int n) { } int BN_is_bit_set(const BIGNUM *a, int n) { - int i, j; - if (n < 0) { return 0; } - i = n / BN_BITS2; - j = n % BN_BITS2; + int i = n / BN_BITS2; + int j = n % BN_BITS2; if (a->top <= i) { return 0; } @@ -284,14 +281,12 @@ int BN_is_bit_set(const BIGNUM *a, int n) { } int BN_mask_bits(BIGNUM *a, int n) { - int b, w; - if (n < 0) { return 0; } - w = n / BN_BITS2; - b = n % BN_BITS2; + int w = n / BN_BITS2; + int b = n % BN_BITS2; if (w >= a->top) { return 0; } diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c index a39ca599..600aedc8 100644 --- a/src/crypto/fipsmodule/ec/ec.c +++ b/src/crypto/fipsmodule/ec/ec.c @@ -80,6 +80,8 @@ #include "../delocate.h" +static void ec_point_free(EC_POINT *point, int free_group); + static const uint8_t kP224Params[6 * 28] = { // p 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, @@ -354,6 +356,7 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) { } OPENSSL_memset(ret, 0, sizeof(EC_GROUP)); + ret->references = 1; ret->meth = meth; BN_init(&ret->order); @@ -365,6 +368,19 @@ EC_GROUP *ec_group_new(const EC_METHOD *meth) { return ret; } +static void ec_group_set0_generator(EC_GROUP *group, EC_POINT *generator) { + assert(group->generator == NULL); + assert(group == generator->group); + + // Avoid a reference cycle. |group->generator| does not maintain an owning + // pointer to |group|. + group->generator = generator; + int is_zero = CRYPTO_refcount_dec_and_test_zero(&group->references); + + assert(!is_zero); + (void)is_zero; +} + EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { EC_GROUP *ret = ec_group_new(EC_GFp_mont_method()); @@ -372,9 +388,10 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, return NULL; } - if (ret->meth->group_set_curve == 0) { + if (ret->meth->group_set_curve == NULL) { OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return 0; + EC_GROUP_free(ret); + return NULL; } if (!ret->meth->group_set_curve(ret, p, a, b, ctx)) { EC_GROUP_free(ret); @@ -385,9 +402,13 @@ EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, const BIGNUM *a, int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor) { - if (group->curve_name != NID_undef || group->generator != NULL) { + if (group->curve_name != NID_undef || group->generator != NULL || + generator->group != group) { // |EC_GROUP_set_generator| may only be used with |EC_GROUP|s returned by // |EC_GROUP_new_curve_GFp| and may only used once on each group. + // Additionally, |generator| must been created from + // |EC_GROUP_new_curve_GFp|, not a copy, so that + // |generator->group->generator| is set correctly. return 0; } @@ -397,10 +418,16 @@ int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, return 0; } - group->generator = EC_POINT_new(group); - return group->generator != NULL && - EC_POINT_copy(group->generator, generator) && - BN_copy(&group->order, order); + EC_POINT *copy = EC_POINT_new(group); + if (copy == NULL || + !EC_POINT_copy(copy, generator) || + !BN_copy(&group->order, order)) { + EC_POINT_free(copy); + return 0; + } + + ec_group_set0_generator(group, copy); + return 1; } static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { @@ -459,7 +486,7 @@ static EC_GROUP *ec_group_new_from_data(unsigned built_in_index) { group->order_mont = monts[built_in_index]; } - group->generator = P; + ec_group_set0_generator(group, P); P = NULL; ok = 1; @@ -500,15 +527,16 @@ EC_GROUP *EC_GROUP_new_by_curve_name(int nid) { } void EC_GROUP_free(EC_GROUP *group) { - if (!group) { + if (group == NULL || + !CRYPTO_refcount_dec_and_test_zero(&group->references)) { return; } - if (group->meth->group_finish != 0) { + if (group->meth->group_finish != NULL) { group->meth->group_finish(group); } - EC_POINT_free(group->generator); + ec_point_free(group->generator, 0 /* don't free group */); BN_free(&group->order); OPENSSL_free(group); @@ -523,42 +551,37 @@ EC_GROUP *EC_GROUP_dup(const EC_GROUP *a) { return NULL; } - if (a->meth->group_copy == NULL) { - OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return NULL; - } + // Groups are logically immutable (but for |EC_GROUP_set_generator| which must + // be called early on), so we simply take a reference. + EC_GROUP *group = (EC_GROUP *)a; + CRYPTO_refcount_inc(&group->references); + return group; +} - EC_GROUP *ret = ec_group_new(a->meth); - if (ret == NULL) { - return NULL; +int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) { + // Note this function returns 0 if equal and non-zero otherwise. + if (a == b) { + return 0; } - - ret->order_mont = a->order_mont; - ret->curve_name = a->curve_name; - - if (a->generator != NULL) { - ret->generator = EC_POINT_dup(a->generator, ret); - if (ret->generator == NULL) { - goto err; - } + if (a->curve_name != b->curve_name) { + return 1; } - - if (!BN_copy(&ret->order, &a->order) || - !ret->meth->group_copy(ret, a)) { - goto err; + if (a->curve_name != NID_undef) { + // Built-in curves may be compared by curve name alone. + return 0; } - return ret; - -err: - EC_GROUP_free(ret); - return NULL; -} - -int EC_GROUP_cmp(const EC_GROUP *a, const EC_GROUP *b, BN_CTX *ignored) { - return a->curve_name == NID_undef || - b->curve_name == NID_undef || - a->curve_name != b->curve_name; + // |a| and |b| are both custom curves. We compare the entire curve + // structure. If |a| or |b| is incomplete (due to legacy OpenSSL mistakes, + // custom curve construction is sadly done in two parts) but otherwise not the + // same object, we consider them always unequal. + return a->generator == NULL || + b->generator == NULL || + BN_cmp(&a->order, &b->order) != 0 || + BN_cmp(&a->field, &b->field) != 0 || + BN_cmp(&a->a, &b->a) != 0 || + BN_cmp(&a->b, &b->b) != 0 || + ec_GFp_simple_cmp(a, a->generator, b->generator, NULL) != 0; } const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *group) { @@ -608,9 +631,9 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) { return NULL; } - ret->meth = group->meth; - - if (!ec_GFp_simple_point_init(ret)) { + ret->group = EC_GROUP_dup(group); + if (ret->group == NULL || + !ec_GFp_simple_point_init(ret)) { OPENSSL_free(ret); return NULL; } @@ -618,28 +641,25 @@ EC_POINT *EC_POINT_new(const EC_GROUP *group) { return ret; } -void EC_POINT_free(EC_POINT *point) { +static void ec_point_free(EC_POINT *point, int free_group) { if (!point) { return; } - ec_GFp_simple_point_finish(point); - + if (free_group) { + EC_GROUP_free(point->group); + } OPENSSL_free(point); } -void EC_POINT_clear_free(EC_POINT *point) { - if (!point) { - return; - } - - ec_GFp_simple_point_clear_finish(point); - - OPENSSL_free(point); +void EC_POINT_free(EC_POINT *point) { + ec_point_free(point, 1 /* free group */); } +void EC_POINT_clear_free(EC_POINT *point) { EC_POINT_free(point); } + int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src) { - if (dest->meth != src->meth) { + if (EC_GROUP_cmp(dest->group, src->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -665,7 +685,7 @@ EC_POINT *EC_POINT_dup(const EC_POINT *a, const EC_GROUP *group) { } int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -673,7 +693,7 @@ int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point) { } int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -682,7 +702,7 @@ int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point) { int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -691,7 +711,8 @@ int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { - if ((group->meth != a->meth) || (a->meth != b->meth)) { + if (EC_GROUP_cmp(group, a->group, NULL) != 0 || + EC_GROUP_cmp(group, b->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return -1; } @@ -699,7 +720,7 @@ int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, } int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -709,7 +730,7 @@ int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx) { int EC_POINTs_make_affine(const EC_GROUP *group, size_t num, EC_POINT *points[], BN_CTX *ctx) { for (size_t i = 0; i < num; i++) { - if (group->meth != points[i]->meth) { + if (EC_GROUP_cmp(group, points[i]->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -724,7 +745,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); return 0; } - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -734,7 +755,7 @@ int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -752,8 +773,9 @@ int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { - if ((group->meth != r->meth) || (r->meth != a->meth) || - (a->meth != b->meth)) { + if (EC_GROUP_cmp(group, r->group, NULL) != 0 || + EC_GROUP_cmp(group, a->group, NULL) != 0 || + EC_GROUP_cmp(group, b->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -763,7 +785,8 @@ int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) { - if ((group->meth != r->meth) || (r->meth != a->meth)) { + if (EC_GROUP_cmp(group, r->group, NULL) != 0 || + EC_GROUP_cmp(group, a->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -772,7 +795,7 @@ int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx) { - if (group->meth != a->meth) { + if (EC_GROUP_cmp(group, a->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -790,8 +813,8 @@ int EC_POINT_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, return 0; } - if (group->meth != r->meth || - (p != NULL && group->meth != p->meth)) { + if (EC_GROUP_cmp(group, r->group, NULL) != 0 || + (p != NULL && EC_GROUP_cmp(group, p->group, NULL) != 0)) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -803,7 +826,7 @@ int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } diff --git a/src/crypto/fipsmodule/ec/ec_montgomery.c b/src/crypto/fipsmodule/ec/ec_montgomery.c index c5f240bf..6670b84e 100644 --- a/src/crypto/fipsmodule/ec/ec_montgomery.c +++ b/src/crypto/fipsmodule/ec/ec_montgomery.c @@ -90,32 +90,6 @@ void ec_GFp_mont_group_finish(EC_GROUP *group) { ec_GFp_simple_group_finish(group); } -int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) { - BN_MONT_CTX_free(dest->mont); - dest->mont = NULL; - - if (!ec_GFp_simple_group_copy(dest, src)) { - return 0; - } - - if (src->mont != NULL) { - dest->mont = BN_MONT_CTX_new(); - if (dest->mont == NULL) { - return 0; - } - if (!BN_MONT_CTX_copy(dest->mont, src->mont)) { - goto err; - } - } - - return 1; - -err: - BN_MONT_CTX_free(dest->mont); - dest->mont = NULL; - return 0; -} - int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { BN_CTX *new_ctx = NULL; @@ -293,7 +267,6 @@ err: DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_mont_method) { out->group_init = ec_GFp_mont_group_init; out->group_finish = ec_GFp_mont_group_finish; - out->group_copy = ec_GFp_mont_group_copy; out->group_set_curve = ec_GFp_mont_group_set_curve; out->point_get_affine_coordinates = ec_GFp_mont_point_get_affine_coordinates; out->mul = ec_wNAF_mul /* XXX: Not constant time. */; diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc index 48b60ee9..0ee73787 100644 --- a/src/crypto/fipsmodule/ec/ec_test.cc +++ b/src/crypto/fipsmodule/ec/ec_test.cc @@ -276,6 +276,33 @@ TEST(ECTest, ArbitraryCurve) { // The key must be valid according to the new group too. EXPECT_TRUE(EC_KEY_check_key(key2.get())); + + // Make a second instance of |group|. + bssl::UniquePtr<EC_GROUP> group2( + EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get())); + ASSERT_TRUE(group2); + bssl::UniquePtr<EC_POINT> generator2(EC_POINT_new(group2.get())); + ASSERT_TRUE(generator2); + ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp( + group2.get(), generator2.get(), gx.get(), gy.get(), ctx.get())); + ASSERT_TRUE(EC_GROUP_set_generator(group2.get(), generator2.get(), + order.get(), BN_value_one())); + + EXPECT_EQ(0, EC_GROUP_cmp(group.get(), group.get(), NULL)); + EXPECT_EQ(0, EC_GROUP_cmp(group2.get(), group.get(), NULL)); + + // group3 uses the wrong generator. + bssl::UniquePtr<EC_GROUP> group3( + EC_GROUP_new_curve_GFp(p.get(), a.get(), b.get(), ctx.get())); + ASSERT_TRUE(group3); + bssl::UniquePtr<EC_POINT> generator3(EC_POINT_new(group3.get())); + ASSERT_TRUE(generator3); + ASSERT_TRUE(EC_POINT_set_affine_coordinates_GFp( + group3.get(), generator3.get(), x.get(), y.get(), ctx.get())); + ASSERT_TRUE(EC_GROUP_set_generator(group3.get(), generator3.get(), + order.get(), BN_value_one())); + + EXPECT_NE(0, EC_GROUP_cmp(group.get(), group3.get(), NULL)); } class ECCurveTest : public testing::TestWithParam<EC_builtin_curve> {}; diff --git a/src/crypto/fipsmodule/ec/internal.h b/src/crypto/fipsmodule/ec/internal.h index 39c9349a..f0657445 100644 --- a/src/crypto/fipsmodule/ec/internal.h +++ b/src/crypto/fipsmodule/ec/internal.h @@ -82,7 +82,6 @@ extern "C" { struct ec_method_st { int (*group_init)(EC_GROUP *); void (*group_finish)(EC_GROUP *); - int (*group_copy)(EC_GROUP *, const EC_GROUP *); int (*group_set_curve)(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); int (*point_get_affine_coordinates)(const EC_GROUP *, const EC_POINT *, @@ -114,6 +113,8 @@ const EC_METHOD *EC_GFp_mont_method(void); struct ec_group_st { const EC_METHOD *meth; + // Unlike all other |EC_POINT|s, |generator| does not own |generator->group| + // to avoid a reference cycle. EC_POINT *generator; BIGNUM order; @@ -130,13 +131,17 @@ struct ec_group_st { int a_is_minus3; // enable optimized point arithmetics for special case + CRYPTO_refcount_t references; + BN_MONT_CTX *mont; // Montgomery structure. BIGNUM one; // The value one. } /* EC_GROUP */; struct ec_point_st { - const EC_METHOD *meth; + // group is an owning reference to |group|, unless this is + // |group->generator|. + EC_GROUP *group; BIGNUM X; BIGNUM Y; @@ -145,7 +150,6 @@ struct ec_point_st { } /* EC_POINT */; EC_GROUP *ec_group_new(const EC_METHOD *meth); -int ec_group_copy(EC_GROUP *dest, const EC_GROUP *src); // ec_group_get_order_mont returns a Montgomery context for operations modulo // |group|'s order. It may return NULL in the case that |group| is not a @@ -158,7 +162,6 @@ int ec_wNAF_mul(const EC_GROUP *group, EC_POINT *r, const BIGNUM *g_scalar, // method functions in simple.c int ec_GFp_simple_group_init(EC_GROUP *); void ec_GFp_simple_group_finish(EC_GROUP *); -int ec_GFp_simple_group_copy(EC_GROUP *, const EC_GROUP *); int ec_GFp_simple_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, @@ -166,7 +169,6 @@ int ec_GFp_simple_group_get_curve(const EC_GROUP *, BIGNUM *p, BIGNUM *a, unsigned ec_GFp_simple_group_get_degree(const EC_GROUP *); int ec_GFp_simple_point_init(EC_POINT *); void ec_GFp_simple_point_finish(EC_POINT *); -void ec_GFp_simple_point_clear_finish(EC_POINT *); int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *); int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, @@ -205,7 +207,6 @@ int ec_GFp_mont_group_init(EC_GROUP *); int ec_GFp_mont_group_set_curve(EC_GROUP *, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *); void ec_GFp_mont_group_finish(EC_GROUP *); -int ec_GFp_mont_group_copy(EC_GROUP *, const EC_GROUP *); int ec_GFp_mont_field_mul(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *); int ec_GFp_mont_field_sqr(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, diff --git a/src/crypto/fipsmodule/ec/oct.c b/src/crypto/fipsmodule/ec/oct.c index cf51e4bc..7d623956 100644 --- a/src/crypto/fipsmodule/ec/oct.c +++ b/src/crypto/fipsmodule/ec/oct.c @@ -251,7 +251,7 @@ err: int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, const uint8_t *buf, size_t len, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -261,7 +261,7 @@ int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point, size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form, uint8_t *buf, size_t len, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } @@ -396,7 +396,7 @@ err: int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, int y_bit, BN_CTX *ctx) { - if (group->meth != point->meth) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); return 0; } diff --git a/src/crypto/fipsmodule/ec/p224-64.c b/src/crypto/fipsmodule/ec/p224-64.c index ec5a93d2..26a94b9e 100644 --- a/src/crypto/fipsmodule/ec/p224-64.c +++ b/src/crypto/fipsmodule/ec/p224-64.c @@ -1151,7 +1151,6 @@ err: DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) { out->group_init = ec_GFp_simple_group_init; out->group_finish = ec_GFp_simple_group_finish; - out->group_copy = ec_GFp_simple_group_copy; out->group_set_curve = ec_GFp_simple_group_set_curve; out->point_get_affine_coordinates = ec_GFp_nistp224_point_get_affine_coordinates; diff --git a/src/crypto/fipsmodule/ec/p256-64.c b/src/crypto/fipsmodule/ec/p256-64.c index f7d1ff11..04ae56ba 100644 --- a/src/crypto/fipsmodule/ec/p256-64.c +++ b/src/crypto/fipsmodule/ec/p256-64.c @@ -1694,7 +1694,6 @@ err: DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp256_method) { out->group_init = ec_GFp_simple_group_init; out->group_finish = ec_GFp_simple_group_finish; - out->group_copy = ec_GFp_simple_group_copy; out->group_set_curve = ec_GFp_simple_group_set_curve; out->point_get_affine_coordinates = ec_GFp_nistp256_point_get_affine_coordinates; diff --git a/src/crypto/fipsmodule/ec/p256-x86_64.c b/src/crypto/fipsmodule/ec/p256-x86_64.c index 8b516773..0004add8 100644 --- a/src/crypto/fipsmodule/ec/p256-x86_64.c +++ b/src/crypto/fipsmodule/ec/p256-x86_64.c @@ -547,7 +547,6 @@ static int ecp_nistz256_get_affine(const EC_GROUP *group, const EC_POINT *point, DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistz256_method) { out->group_init = ec_GFp_mont_group_init; out->group_finish = ec_GFp_mont_group_finish; - out->group_copy = ec_GFp_mont_group_copy; out->group_set_curve = ec_GFp_mont_group_set_curve; out->point_get_affine_coordinates = ecp_nistz256_get_affine; out->mul = ecp_nistz256_points_mul; diff --git a/src/crypto/fipsmodule/ec/simple.c b/src/crypto/fipsmodule/ec/simple.c index 75c06da1..f7faa45c 100644 --- a/src/crypto/fipsmodule/ec/simple.c +++ b/src/crypto/fipsmodule/ec/simple.c @@ -104,18 +104,6 @@ void ec_GFp_simple_group_finish(EC_GROUP *group) { BN_free(&group->one); } -int ec_GFp_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src) { - if (!BN_copy(&dest->field, &src->field) || - !BN_copy(&dest->a, &src->a) || - !BN_copy(&dest->b, &src->b) || - !BN_copy(&dest->one, &src->one)) { - return 0; - } - - dest->a_is_minus3 = src->a_is_minus3; - return 1; -} - int ec_GFp_simple_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { @@ -249,12 +237,6 @@ void ec_GFp_simple_point_finish(EC_POINT *point) { BN_free(&point->Z); } -void ec_GFp_simple_point_clear_finish(EC_POINT *point) { - BN_clear_free(&point->X); - BN_clear_free(&point->Y); - BN_clear_free(&point->Z); -} - int ec_GFp_simple_point_copy(EC_POINT *dest, const EC_POINT *src) { if (!BN_copy(&dest->X, &src->X) || !BN_copy(&dest->Y, &src->Y) || @@ -814,11 +796,11 @@ int ec_GFp_simple_cmp(const EC_GROUP *group, const EC_POINT *a, const BIGNUM *tmp1_, *tmp2_; int ret = -1; - if (EC_POINT_is_at_infinity(group, a)) { - return EC_POINT_is_at_infinity(group, b) ? 0 : 1; + if (ec_GFp_simple_is_at_infinity(group, a)) { + return ec_GFp_simple_is_at_infinity(group, b) ? 0 : 1; } - if (EC_POINT_is_at_infinity(group, b)) { + if (ec_GFp_simple_is_at_infinity(group, b)) { return 1; } diff --git a/src/crypto/fipsmodule/ec/wnaf.c b/src/crypto/fipsmodule/ec/wnaf.c index 0e3ee13a..842a8fb6 100644 --- a/src/crypto/fipsmodule/ec/wnaf.c +++ b/src/crypto/fipsmodule/ec/wnaf.c @@ -446,7 +446,7 @@ err: } if (val != NULL) { for (i = 0; i < num_val; i++) { - EC_POINT_clear_free(val[i]); + EC_POINT_free(val[i]); } OPENSSL_free(val); diff --git a/src/crypto/lhash/lhash.c b/src/crypto/lhash/lhash.c index 50545291..7bfd2897 100644 --- a/src/crypto/lhash/lhash.c +++ b/src/crypto/lhash/lhash.c @@ -73,6 +73,25 @@ static const size_t kMinNumBuckets = 16; static const size_t kMaxAverageChainLength = 2; static const size_t kMinAverageChainLength = 1; +struct lhash_st { + // num_items contains the total number of items in the hash table. + size_t num_items; + // buckets is an array of |num_buckets| pointers. Each points to the head of + // a chain of LHASH_ITEM objects that have the same hash value, mod + // |num_buckets|. + LHASH_ITEM **buckets; + // num_buckets contains the length of |buckets|. This value is always >= + // kMinNumBuckets. + size_t num_buckets; + // callback_depth contains the current depth of |lh_doall| or |lh_doall_arg| + // calls. If non-zero then this suppresses resizing of the |buckets| array, + // which would otherwise disrupt the iteration. + unsigned callback_depth; + + lhash_cmp_func comp; + lhash_hash_func hash; +}; + _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp) { _LHASH *ret = OPENSSL_malloc(sizeof(_LHASH)); if (ret == NULL) { diff --git a/src/crypto/pem/pem_lib.c b/src/crypto/pem/pem_lib.c index afa39d78..8f890961 100644 --- a/src/crypto/pem/pem_lib.c +++ b/src/crypto/pem/pem_lib.c @@ -764,13 +764,13 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, int PEM_def_callback(char *buf, int size, int rwflag, void *userdata) { - if (!buf || !userdata) { + if (!buf || !userdata || size < 0) { return 0; } size_t len = strlen((char *)userdata); if (len >= (size_t)size) { return 0; } - strcpy(buf, (char *)userdata); + BUF_strlcpy(buf, userdata, (size_t)size); return len; } diff --git a/src/crypto/rsa_extra/rsa_asn1.c b/src/crypto/rsa_extra/rsa_asn1.c index 23c91bd9..3cc6a9c3 100644 --- a/src/crypto/rsa_extra/rsa_asn1.c +++ b/src/crypto/rsa_extra/rsa_asn1.c @@ -69,22 +69,15 @@ #include "../internal.h" -static int parse_integer_buggy(CBS *cbs, BIGNUM **out, int buggy) { +static int parse_integer(CBS *cbs, BIGNUM **out) { assert(*out == NULL); *out = BN_new(); if (*out == NULL) { return 0; } - if (buggy) { - return BN_parse_asn1_unsigned_buggy(cbs, *out); - } return BN_parse_asn1_unsigned(cbs, *out); } -static int parse_integer(CBS *cbs, BIGNUM **out) { - return parse_integer_buggy(cbs, out, 0 /* not buggy */); -} - static int marshal_integer(CBB *cbb, BIGNUM *bn) { if (bn == NULL) { // An RSA object may be missing some components. @@ -94,14 +87,14 @@ static int marshal_integer(CBB *cbb, BIGNUM *bn) { return BN_marshal_asn1(cbb, bn); } -static RSA *parse_public_key(CBS *cbs, int buggy) { +RSA *RSA_parse_public_key(CBS *cbs) { RSA *ret = RSA_new(); if (ret == NULL) { return NULL; } CBS child; if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) || - !parse_integer_buggy(&child, &ret->n, buggy) || + !parse_integer(&child, &ret->n) || !parse_integer(&child, &ret->e) || CBS_len(&child) != 0) { OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING); @@ -119,18 +112,6 @@ static RSA *parse_public_key(CBS *cbs, int buggy) { return ret; } -RSA *RSA_parse_public_key(CBS *cbs) { - return parse_public_key(cbs, 0 /* not buggy */); -} - -RSA *RSA_parse_public_key_buggy(CBS *cbs) { - // Estonian IDs issued between September 2014 to September 2015 are - // broken. See https://crbug.com/532048 and https://crbug.com/534766. - // - // TODO(davidben): Remove this code and callers in March 2016. - return parse_public_key(cbs, 1 /* buggy */); -} - RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) { CBS cbs; CBS_init(&cbs, in, in_len); diff --git a/src/crypto/rsa_extra/rsa_test.cc b/src/crypto/rsa_extra/rsa_test.cc index 1cc71eab..23e8c67c 100644 --- a/src/crypto/rsa_extra/rsa_test.cc +++ b/src/crypto/rsa_extra/rsa_test.cc @@ -622,13 +622,6 @@ TEST(RSATest, ASN1) { sizeof(kEstonianRSAKey))); EXPECT_FALSE(rsa); ERR_clear_error(); - - // But |RSA_parse_public_key_buggy| will accept it. - CBS cbs; - CBS_init(&cbs, kEstonianRSAKey, sizeof(kEstonianRSAKey)); - rsa.reset(RSA_parse_public_key_buggy(&cbs)); - EXPECT_TRUE(rsa); - EXPECT_EQ(0u, CBS_len(&cbs)); } TEST(RSATest, BadExponent) { diff --git a/src/crypto/x509/by_dir.c b/src/crypto/x509/by_dir.c index d72f9ec2..635b851f 100644 --- a/src/crypto/x509/by_dir.c +++ b/src/crypto/x509/by_dir.c @@ -61,7 +61,6 @@ #include <openssl/buf.h> #include <openssl/err.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/thread.h> #include <openssl/x509.h> @@ -235,8 +234,7 @@ static int add_cert_dir(BY_DIR *ctx, const char *dir, int type) by_dir_entry_free(ent); return 0; } - strncpy(ent->dir, ss, len); - ent->dir[len] = '\0'; + BUF_strlcpy(ent->dir, ss, len + 1); if (!sk_BY_DIR_ENTRY_push(ctx->dirs, ent)) { by_dir_entry_free(ent); return 0; diff --git a/src/crypto/x509/by_file.c b/src/crypto/x509/by_file.c index 2bec572c..555cb854 100644 --- a/src/crypto/x509/by_file.c +++ b/src/crypto/x509/by_file.c @@ -59,7 +59,6 @@ #include <openssl/buf.h> #include <openssl/err.h> -#include <openssl/lhash.h> #include <openssl/pem.h> #include <openssl/thread.h> diff --git a/src/crypto/x509/x509_lu.c b/src/crypto/x509/x509_lu.c index 1014a05c..1a841dbe 100644 --- a/src/crypto/x509/x509_lu.c +++ b/src/crypto/x509/x509_lu.c @@ -58,7 +58,6 @@ #include <string.h> #include <openssl/err.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/thread.h> #include <openssl/x509.h> diff --git a/src/crypto/x509/x509_obj.c b/src/crypto/x509/x509_obj.c index 33eafc42..65b1bfb5 100644 --- a/src/crypto/x509/x509_obj.c +++ b/src/crypto/x509/x509_obj.c @@ -59,7 +59,6 @@ #include <openssl/buf.h> #include <openssl/err.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/obj.h> #include <openssl/x509.h> @@ -102,8 +101,7 @@ char *X509_NAME_oneline(X509_NAME *a, char *buf, int len) buf = b->data; OPENSSL_free(b); } - strncpy(buf, "NO X509_NAME", len); - buf[len - 1] = '\0'; + BUF_strlcpy(buf, "NO X509_NAME", len); return buf; } diff --git a/src/crypto/x509/x509_txt.c b/src/crypto/x509/x509_txt.c index 17e6cdb9..753e7202 100644 --- a/src/crypto/x509/x509_txt.c +++ b/src/crypto/x509/x509_txt.c @@ -54,13 +54,7 @@ * copied and put under another distribution licence * [including the GNU Public Licence.] */ -#include <openssl/asn1.h> -#include <openssl/buf.h> -#include <openssl/cipher.h> -#include <openssl/evp.h> -#include <openssl/lhash.h> #include <openssl/mem.h> -#include <openssl/obj.h> #include <openssl/x509.h> const char *X509_verify_cert_error_string(long n) diff --git a/src/crypto/x509/x509_vfy.c b/src/crypto/x509/x509_vfy.c index 8e258fef..aff2ee95 100644 --- a/src/crypto/x509/x509_vfy.c +++ b/src/crypto/x509/x509_vfy.c @@ -61,7 +61,6 @@ #include <openssl/buf.h> #include <openssl/err.h> #include <openssl/evp.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/obj.h> #include <openssl/thread.h> diff --git a/src/crypto/x509/x509_vpm.c b/src/crypto/x509/x509_vpm.c index 2317214c..d0f8f794 100644 --- a/src/crypto/x509/x509_vpm.c +++ b/src/crypto/x509/x509_vpm.c @@ -57,7 +57,6 @@ #include <string.h> #include <openssl/buf.h> -#include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/obj.h> #include <openssl/stack.h> diff --git a/src/crypto/x509v3/v3_alt.c b/src/crypto/x509v3/v3_alt.c index 62806519..b78a4105 100644 --- a/src/crypto/x509v3/v3_alt.c +++ b/src/crypto/x509v3/v3_alt.c @@ -166,9 +166,9 @@ STACK_OF(CONF_VALUE) *i2v_GENERAL_NAME(X509V3_EXT_METHOD *method, for (i = 0; i < 8; i++) { BIO_snprintf(htmp, sizeof htmp, "%X", p[0] << 8 | p[1]); p += 2; - strcat(oline, htmp); + BUF_strlcat(oline, htmp, sizeof(oline)); if (i != 7) - strcat(oline, ":"); + BUF_strlcat(oline, ":", sizeof(oline)); } } else { if (!X509V3_add_value("IP Address", "<invalid>", &ret)) @@ -588,8 +588,7 @@ static int do_othername(GENERAL_NAME *gen, char *value, X509V3_CTX *ctx) objtmp = OPENSSL_malloc(objlen + 1); if (objtmp == NULL) return 0; - strncpy(objtmp, value, objlen); - objtmp[objlen] = 0; + BUF_strlcpy(objtmp, value, objlen + 1); gen->d.otherName->type_id = OBJ_txt2obj(objtmp, 0); OPENSSL_free(objtmp); if (!gen->d.otherName->type_id) diff --git a/src/crypto/x509v3/v3_genn.c b/src/crypto/x509v3/v3_genn.c index 2331cd49..8c926879 100644 --- a/src/crypto/x509v3/v3_genn.c +++ b/src/crypto/x509v3/v3_genn.c @@ -231,6 +231,7 @@ int GENERAL_NAME_set0_othername(GENERAL_NAME *gen, oth = OTHERNAME_new(); if (!oth) return 0; + ASN1_TYPE_free(oth->value); oth->type_id = oid; oth->value = value; GENERAL_NAME_set0_value(gen, GEN_OTHERNAME, oth); diff --git a/src/crypto/x509v3/v3_info.c b/src/crypto/x509v3/v3_info.c index 40f451fe..ff96489e 100644 --- a/src/crypto/x509v3/v3_info.c +++ b/src/crypto/x509v3/v3_info.c @@ -192,8 +192,7 @@ static AUTHORITY_INFO_ACCESS *v2i_AUTHORITY_INFO_ACCESS(X509V3_EXT_METHOD OPENSSL_PUT_ERROR(X509V3, ERR_R_MALLOC_FAILURE); goto err; } - strncpy(objtmp, cnf->name, objlen); - objtmp[objlen] = 0; + BUF_strlcpy(objtmp, cnf->name, objlen + 1); acc->method = OBJ_txt2obj(objtmp, 0); if (!acc->method) { OPENSSL_PUT_ERROR(X509V3, X509V3_R_BAD_OBJECT); diff --git a/src/include/openssl/bn.h b/src/include/openssl/bn.h index 52333ac5..9960b751 100644 --- a/src/include/openssl/bn.h +++ b/src/include/openssl/bn.h @@ -317,10 +317,6 @@ OPENSSL_EXPORT int BN_get_u64(const BIGNUM *bn, uint64_t *out); // the result to |ret|. It returns one on success and zero on failure. OPENSSL_EXPORT int BN_parse_asn1_unsigned(CBS *cbs, BIGNUM *ret); -// BN_parse_asn1_unsigned_buggy acts like |BN_parse_asn1_unsigned| but tolerates -// some invalid encodings. Do not use this function. -OPENSSL_EXPORT int BN_parse_asn1_unsigned_buggy(CBS *cbs, BIGNUM *ret); - // BN_marshal_asn1 marshals |bn| as a non-negative DER INTEGER and appends the // result to |cbb|. It returns one on success and zero on failure. OPENSSL_EXPORT int BN_marshal_asn1(CBB *cbb, const BIGNUM *bn); diff --git a/src/include/openssl/ec.h b/src/include/openssl/ec.h index 4a08a9b1..dee41b7a 100644 --- a/src/include/openssl/ec.h +++ b/src/include/openssl/ec.h @@ -162,10 +162,6 @@ OPENSSL_EXPORT EC_POINT *EC_POINT_new(const EC_GROUP *group); // EC_POINT_free frees |point| and the data that it points to. OPENSSL_EXPORT void EC_POINT_free(EC_POINT *point); -// EC_POINT_clear_free clears the data that |point| points to, frees it and -// then frees |point| itself. -OPENSSL_EXPORT void EC_POINT_clear_free(EC_POINT *point); - // EC_POINT_copy sets |*dest| equal to |*src|. It returns one on success and // zero otherwise. OPENSSL_EXPORT int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src); @@ -306,7 +302,7 @@ OPENSSL_EXPORT EC_GROUP *EC_GROUP_new_curve_GFp(const BIGNUM *p, // EC_GROUP_set_generator sets the generator for |group| to |generator|, which // must have the given order and cofactor. It may only be used with |EC_GROUP| // objects returned by |EC_GROUP_new_curve_GFp| and may only be used once on -// each group. +// each group. |generator| must have been created using |group|. OPENSSL_EXPORT int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, @@ -350,6 +346,9 @@ typedef struct { OPENSSL_EXPORT size_t EC_get_builtin_curves(EC_builtin_curve *out_curves, size_t max_num_curves); +// EC_POINT_clear_free calls |EC_POINT_free|. +OPENSSL_EXPORT void EC_POINT_clear_free(EC_POINT *point); + // Old code expects to get EC_KEY from ec.h. #include <openssl/ec_key.h> diff --git a/src/include/openssl/evp.h b/src/include/openssl/evp.h index c57d7c77..f5eb2007 100644 --- a/src/include/openssl/evp.h +++ b/src/include/openssl/evp.h @@ -225,10 +225,6 @@ OPENSSL_EXPORT EVP_PKEY *EVP_parse_private_key(CBS *cbs); // success and zero on error. OPENSSL_EXPORT int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key); -// EVP_set_buggy_rsa_parser configures whether |RSA_parse_public_key_buggy| is -// used by |EVP_parse_public_key|. By default, it is not used. -OPENSSL_EXPORT void EVP_set_buggy_rsa_parser(int buggy); - // Signing diff --git a/src/include/openssl/lhash.h b/src/include/openssl/lhash.h index 7525c087..1ceeb699 100644 --- a/src/include/openssl/lhash.h +++ b/src/include/openssl/lhash.h @@ -125,24 +125,7 @@ typedef int (*lhash_cmp_func)(const void *a, const void *b); // uint32_t. typedef uint32_t (*lhash_hash_func)(const void *a); -typedef struct lhash_st { - // num_items contains the total number of items in the hash table. - size_t num_items; - // buckets is an array of |num_buckets| pointers. Each points to the head of - // a chain of LHASH_ITEM objects that have the same hash value, mod - // |num_buckets|. - LHASH_ITEM **buckets; - // num_buckets contains the length of |buckets|. This value is always >= - // kMinNumBuckets. - size_t num_buckets; - // callback_depth contains the current depth of |lh_doall| or |lh_doall_arg| - // calls. If non-zero then this suppresses resizing of the |buckets| array, - // which would otherwise disrupt the iteration. - unsigned callback_depth; - - lhash_cmp_func comp; - lhash_hash_func hash; -} _LHASH; +typedef struct lhash_st _LHASH; // lh_new returns a new, empty hash table or NULL on error. OPENSSL_EXPORT _LHASH *lh_new(lhash_hash_func hash, lhash_cmp_func comp); diff --git a/src/include/openssl/rsa.h b/src/include/openssl/rsa.h index 3f453188..74268cfe 100644 --- a/src/include/openssl/rsa.h +++ b/src/include/openssl/rsa.h @@ -428,10 +428,6 @@ OPENSSL_EXPORT int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len, // error. OPENSSL_EXPORT RSA *RSA_parse_public_key(CBS *cbs); -// RSA_parse_public_key_buggy behaves like |RSA_parse_public_key|, but it -// tolerates some invalid encodings. Do not use this function. -OPENSSL_EXPORT RSA *RSA_parse_public_key_buggy(CBS *cbs); - // RSA_public_key_from_bytes parses |in| as a DER-encoded RSAPublicKey structure // (RFC 3447). It returns a newly-allocated |RSA| or NULL on error. OPENSSL_EXPORT RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len); diff --git a/src/include/openssl/x509_vfy.h b/src/include/openssl/x509_vfy.h index 991cbdaf..208a3807 100644 --- a/src/include/openssl/x509_vfy.h +++ b/src/include/openssl/x509_vfy.h @@ -64,8 +64,6 @@ #ifndef HEADER_X509_VFY_H #define HEADER_X509_VFY_H -#include <openssl/bio.h> -#include <openssl/lhash.h> #include <openssl/thread.h> #ifdef __cplusplus diff --git a/src/include/openssl/x509v3.h b/src/include/openssl/x509v3.h index dd56bbcc..abd52c0b 100644 --- a/src/include/openssl/x509v3.h +++ b/src/include/openssl/x509v3.h @@ -57,6 +57,7 @@ #include <openssl/bio.h> #include <openssl/conf.h> +#include <openssl/lhash.h> #include <openssl/x509.h> #ifdef __cplusplus diff --git a/src/ssl/d1_both.cc b/src/ssl/d1_both.cc index 798deb09..c219f5ae 100644 --- a/src/ssl/d1_both.cc +++ b/src/ssl/d1_both.cc @@ -144,23 +144,18 @@ static const unsigned int kDefaultMTU = 1500 - 28; // Receiving handshake messages. -static void dtls1_hm_fragment_free(hm_fragment *frag) { - if (frag == NULL) { - return; - } - OPENSSL_free(frag->data); - OPENSSL_free(frag->reassembly); - OPENSSL_free(frag); +hm_fragment::~hm_fragment() { + OPENSSL_free(data); + OPENSSL_free(reassembly); } -static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { +static UniquePtr<hm_fragment> dtls1_hm_fragment_new( + const struct hm_header_st *msg_hdr) { ScopedCBB cbb; - hm_fragment *frag = (hm_fragment *)OPENSSL_malloc(sizeof(hm_fragment)); - if (frag == NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return NULL; + UniquePtr<hm_fragment> frag = MakeUnique<hm_fragment>(); + if (!frag) { + return nullptr; } - OPENSSL_memset(frag, 0, sizeof(hm_fragment)); frag->type = msg_hdr->type; frag->seq = msg_hdr->seq; frag->msg_len = msg_hdr->msg_len; @@ -170,7 +165,7 @@ static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { (uint8_t *)OPENSSL_malloc(DTLS1_HM_HEADER_LENGTH + msg_hdr->msg_len); if (frag->data == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } if (!CBB_init_fixed(cbb.get(), frag->data, DTLS1_HM_HEADER_LENGTH) || @@ -181,7 +176,7 @@ static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { !CBB_add_u24(cbb.get(), msg_hdr->msg_len) || !CBB_finish(cbb.get(), NULL, NULL)) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } // If the handshake message is empty, |frag->reassembly| is NULL. @@ -189,22 +184,18 @@ static hm_fragment *dtls1_hm_fragment_new(const struct hm_header_st *msg_hdr) { // Initialize reassembly bitmask. if (msg_hdr->msg_len + 7 < msg_hdr->msg_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW); - goto err; + return nullptr; } size_t bitmask_len = (msg_hdr->msg_len + 7) / 8; frag->reassembly = (uint8_t *)OPENSSL_malloc(bitmask_len); if (frag->reassembly == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; + return nullptr; } OPENSSL_memset(frag->reassembly, 0, bitmask_len); } return frag; - -err: - dtls1_hm_fragment_free(frag); - return NULL; } // bit_range returns a |uint8_t| with bits |start|, inclusive, to |end|, @@ -262,8 +253,8 @@ static void dtls1_hm_fragment_mark(hm_fragment *frag, size_t start, // dtls1_is_current_message_complete returns whether the current handshake // message is complete. static bool dtls1_is_current_message_complete(const SSL *ssl) { - hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq % - SSL_MAX_HANDSHAKE_FLIGHT]; + size_t idx = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; + hm_fragment *frag = ssl->d1->incoming_messages[idx].get(); return frag != NULL && frag->reassembly == NULL; } @@ -280,7 +271,7 @@ static hm_fragment *dtls1_get_incoming_message( } size_t idx = msg_hdr->seq % SSL_MAX_HANDSHAKE_FLIGHT; - hm_fragment *frag = ssl->d1->incoming_messages[idx]; + hm_fragment *frag = ssl->d1->incoming_messages[idx].get(); if (frag != NULL) { assert(frag->seq == msg_hdr->seq); // The new fragment must be compatible with the previous fragments from this @@ -295,13 +286,12 @@ static hm_fragment *dtls1_get_incoming_message( } // This is the first fragment from this message. - frag = dtls1_hm_fragment_new(msg_hdr); - if (frag == NULL) { + ssl->d1->incoming_messages[idx] = dtls1_hm_fragment_new(msg_hdr); + if (!ssl->d1->incoming_messages[idx]) { *out_alert = SSL_AD_INTERNAL_ERROR; return NULL; } - ssl->d1->incoming_messages[idx] = frag; - return frag; + return ssl->d1->incoming_messages[idx].get(); } ssl_open_record_t dtls1_open_handshake(SSL *ssl, size_t *out_consumed, @@ -420,8 +410,8 @@ bool dtls1_get_message(SSL *ssl, SSLMessage *out) { return false; } - hm_fragment *frag = ssl->d1->incoming_messages[ssl->d1->handshake_read_seq % - SSL_MAX_HANDSHAKE_FLIGHT]; + size_t idx = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; + hm_fragment *frag = ssl->d1->incoming_messages[idx].get(); out->type = frag->type; CBS_init(&out->body, frag->data + DTLS1_HM_HEADER_LENGTH, frag->msg_len); CBS_init(&out->raw, frag->data, DTLS1_HM_HEADER_LENGTH + frag->msg_len); @@ -437,8 +427,7 @@ void dtls1_next_message(SSL *ssl) { assert(ssl->s3->has_message); assert(dtls1_is_current_message_complete(ssl)); size_t index = ssl->d1->handshake_read_seq % SSL_MAX_HANDSHAKE_FLIGHT; - dtls1_hm_fragment_free(ssl->d1->incoming_messages[index]); - ssl->d1->incoming_messages[index] = NULL; + ssl->d1->incoming_messages[index].reset(); ssl->d1->handshake_read_seq++; ssl->s3->has_message = false; // If we previously sent a flight, mark it as having a reply, so @@ -448,13 +437,6 @@ void dtls1_next_message(SSL *ssl) { } } -void dtls_clear_incoming_messages(SSL *ssl) { - for (size_t i = 0; i < SSL_MAX_HANDSHAKE_FLIGHT; i++) { - dtls1_hm_fragment_free(ssl->d1->incoming_messages[i]); - ssl->d1->incoming_messages[i] = NULL; - } -} - bool dtls_has_unprocessed_handshake_data(const SSL *ssl) { if (ssl->d1->has_change_cipher_spec) { return true; @@ -467,7 +449,7 @@ bool dtls_has_unprocessed_handshake_data(const SSL *ssl) { assert(dtls1_is_current_message_complete(ssl)); continue; } - if (ssl->d1->incoming_messages[i] != NULL) { + if (ssl->d1->incoming_messages[i] != nullptr) { return true; } } @@ -510,10 +492,14 @@ ssl_open_record_t dtls1_open_change_cipher_spec(SSL *ssl, size_t *out_consumed, // Sending handshake messages. +void DTLS_OUTGOING_MESSAGE::Clear() { + OPENSSL_free(data); + data = nullptr; +} + void dtls_clear_outgoing_messages(SSL *ssl) { for (size_t i = 0; i < ssl->d1->outgoing_messages_len; i++) { - OPENSSL_free(ssl->d1->outgoing_messages[i].data); - ssl->d1->outgoing_messages[i].data = NULL; + ssl->d1->outgoing_messages[i].Clear(); } ssl->d1->outgoing_messages_len = 0; ssl->d1->outgoing_written = 0; @@ -552,7 +538,7 @@ bool dtls1_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg) { // add_outgoing adds a new handshake message or ChangeCipherSpec to the current // outgoing flight. It returns true on success and false on error. -static bool add_outgoing(SSL *ssl, int is_ccs, Array<uint8_t> data) { +static bool add_outgoing(SSL *ssl, bool is_ccs, Array<uint8_t> data) { if (ssl->d1->outgoing_messages_complete) { // If we've begun writing a new flight, we received the peer flight. Discard // the timer and the our flight. @@ -594,11 +580,11 @@ static bool add_outgoing(SSL *ssl, int is_ccs, Array<uint8_t> data) { } bool dtls1_add_message(SSL *ssl, Array<uint8_t> data) { - return add_outgoing(ssl, 0 /* handshake */, std::move(data)); + return add_outgoing(ssl, false /* handshake */, std::move(data)); } bool dtls1_add_change_cipher_spec(SSL *ssl) { - return add_outgoing(ssl, 1 /* ChangeCipherSpec */, Array<uint8_t>()); + return add_outgoing(ssl, true /* ChangeCipherSpec */, Array<uint8_t>()); } bool dtls1_add_alert(SSL *ssl, uint8_t level, uint8_t desc) { @@ -808,14 +794,14 @@ static int send_flight(SSL *ssl) { // Retry this packet the next time around. ssl->d1->outgoing_written = old_written; ssl->d1->outgoing_offset = old_offset; - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; ret = bio_ret; goto err; } } if (BIO_flush(ssl->wbio) <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; goto err; } diff --git a/src/ssl/d1_lib.cc b/src/ssl/d1_lib.cc index 38bc5bec..eff06eec 100644 --- a/src/ssl/d1_lib.cc +++ b/src/ssl/d1_lib.cc @@ -78,18 +78,24 @@ namespace bssl { // before failing the DTLS handshake. #define DTLS1_MAX_TIMEOUTS 12 +DTLS1_STATE::DTLS1_STATE() + : has_change_cipher_spec(false), + outgoing_messages_complete(false), + flight_has_reply(false) {} + +DTLS1_STATE::~DTLS1_STATE() {} + bool dtls1_new(SSL *ssl) { if (!ssl3_new(ssl)) { return false; } - DTLS1_STATE *d1 = (DTLS1_STATE *)OPENSSL_malloc(sizeof *d1); - if (d1 == NULL) { + UniquePtr<DTLS1_STATE> d1 = MakeUnique<DTLS1_STATE>(); + if (!d1) { ssl3_free(ssl); return false; } - OPENSSL_memset(d1, 0, sizeof *d1); - ssl->d1 = d1; + ssl->d1 = d1.release(); // Set the version to the highest supported version. // @@ -103,15 +109,11 @@ bool dtls1_new(SSL *ssl) { void dtls1_free(SSL *ssl) { ssl3_free(ssl); - if (ssl == NULL || ssl->d1 == NULL) { + if (ssl == NULL) { return; } - dtls_clear_incoming_messages(ssl); - dtls_clear_outgoing_messages(ssl); - Delete(ssl->d1->last_aead_write_ctx); - - OPENSSL_free(ssl->d1); + Delete(ssl->d1); ssl->d1 = NULL; } diff --git a/src/ssl/d1_pkt.cc b/src/ssl/d1_pkt.cc index c6be93d5..d29a5c28 100644 --- a/src/ssl/d1_pkt.cc +++ b/src/ssl/d1_pkt.cc @@ -187,8 +187,8 @@ ssl_open_record_t dtls1_open_app_data(SSL *ssl, Span<uint8_t> *out, return ssl_open_record_success; } -int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake, - const uint8_t *buf, int len) { +int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *in, + int len) { assert(!SSL_in_init(ssl)); *out_needs_handshake = false; @@ -211,7 +211,7 @@ int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake, return 0; } - int ret = dtls1_write_record(ssl, SSL3_RT_APPLICATION_DATA, buf, (size_t)len, + int ret = dtls1_write_record(ssl, SSL3_RT_APPLICATION_DATA, in, (size_t)len, dtls1_use_current_epoch); if (ret <= 0) { return ret; @@ -219,29 +219,29 @@ int dtls1_write_app_data(SSL *ssl, bool *out_needs_handshake, return len; } -int dtls1_write_record(SSL *ssl, int type, const uint8_t *buf, size_t len, +int dtls1_write_record(SSL *ssl, int type, const uint8_t *in, size_t len, enum dtls1_use_epoch_t use_epoch) { + SSLBuffer *buf = &ssl->s3->write_buffer; assert(len <= SSL3_RT_MAX_PLAIN_LENGTH); // There should never be a pending write buffer in DTLS. One can't write half // a datagram, so the write buffer is always dropped in // |ssl_write_buffer_flush|. - assert(!ssl_write_buffer_is_pending(ssl)); + assert(buf->empty()); if (len > SSL3_RT_MAX_PLAIN_LENGTH) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } - size_t max_out = len + SSL_max_seal_overhead(ssl); - uint8_t *out; size_t ciphertext_len; - if (!ssl_write_buffer_init(ssl, &out, max_out) || - !dtls_seal_record(ssl, out, &ciphertext_len, max_out, type, buf, len, - use_epoch)) { - ssl_write_buffer_clear(ssl); + if (!buf->EnsureCap(ssl_seal_align_prefix_len(ssl), + len + SSL_max_seal_overhead(ssl)) || + !dtls_seal_record(ssl, buf->remaining().data(), &ciphertext_len, + buf->remaining().size(), type, in, len, use_epoch)) { + buf->Clear(); return -1; } - ssl_write_buffer_set_len(ssl, ciphertext_len); + buf->DidWrite(ciphertext_len); int ret = ssl_write_buffer_flush(ssl); if (ret <= 0) { diff --git a/src/ssl/dtls_method.cc b/src/ssl/dtls_method.cc index fab19be4..91a955f5 100644 --- a/src/ssl/dtls_method.cc +++ b/src/ssl/dtls_method.cc @@ -94,8 +94,7 @@ static bool dtls1_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { OPENSSL_memset(&ssl->d1->bitmap, 0, sizeof(ssl->d1->bitmap)); OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); - Delete(ssl->s3->aead_read_ctx); - ssl->s3->aead_read_ctx = aead_ctx.release(); + ssl->s3->aead_read_ctx = std::move(aead_ctx); return true; } @@ -106,9 +105,8 @@ static bool dtls1_set_write_state(SSL *ssl, sizeof(ssl->s3->write_sequence)); OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); - Delete(ssl->d1->last_aead_write_ctx); - ssl->d1->last_aead_write_ctx = ssl->s3->aead_write_ctx; - ssl->s3->aead_write_ctx = aead_ctx.release(); + ssl->d1->last_aead_write_ctx = std::move(ssl->s3->aead_write_ctx); + ssl->s3->aead_write_ctx = std::move(aead_ctx); return true; } diff --git a/src/ssl/dtls_record.cc b/src/ssl/dtls_record.cc index a7466405..5e795fa3 100644 --- a/src/ssl/dtls_record.cc +++ b/src/ssl/dtls_record.cc @@ -275,10 +275,10 @@ static const SSLAEADContext *get_write_aead(const SSL *ssl, enum dtls1_use_epoch_t use_epoch) { if (use_epoch == dtls1_use_previous_epoch) { assert(ssl->d1->w_epoch >= 1); - return ssl->d1->last_aead_write_ctx; + return ssl->d1->last_aead_write_ctx.get(); } - return ssl->s3->aead_write_ctx; + return ssl->s3->aead_write_ctx.get(); } size_t dtls_max_seal_overhead(const SSL *ssl, @@ -303,12 +303,12 @@ int dtls_seal_record(SSL *ssl, uint8_t *out, size_t *out_len, size_t max_out, // Determine the parameters for the current epoch. uint16_t epoch = ssl->d1->w_epoch; - SSLAEADContext *aead = ssl->s3->aead_write_ctx; + SSLAEADContext *aead = ssl->s3->aead_write_ctx.get(); uint8_t *seq = ssl->s3->write_sequence; if (use_epoch == dtls1_use_previous_epoch) { assert(ssl->d1->w_epoch >= 1); epoch = ssl->d1->w_epoch - 1; - aead = ssl->d1->last_aead_write_ctx; + aead = ssl->d1->last_aead_write_ctx.get(); seq = ssl->d1->last_write_sequence; } diff --git a/src/ssl/handshake.cc b/src/ssl/handshake.cc index 8531ca43..ed114848 100644 --- a/src/ssl/handshake.cc +++ b/src/ssl/handshake.cc @@ -149,17 +149,15 @@ SSL_HANDSHAKE::~SSL_HANDSHAKE() { ssl->ctx->x509_method->hs_flush_cached_ca_names(this); } -SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl) { +UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl) { UniquePtr<SSL_HANDSHAKE> hs = MakeUnique<SSL_HANDSHAKE>(ssl); if (!hs || !hs->transcript.Init()) { return nullptr; } - return hs.release(); + return hs; } -void ssl_handshake_free(SSL_HANDSHAKE *hs) { Delete(hs); } - bool ssl_check_message_type(SSL *ssl, const SSLMessage &msg, int type) { if (msg.type != type) { ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE); @@ -282,7 +280,7 @@ static void set_crypto_buffer(CRYPTO_BUFFER **dest, CRYPTO_BUFFER *src) { enum ssl_verify_result_t ssl_verify_peer_cert(SSL_HANDSHAKE *hs) { SSL *const ssl = hs->ssl; - const SSL_SESSION *prev_session = ssl->s3->established_session; + const SSL_SESSION *prev_session = ssl->s3->established_session.get(); if (prev_session != NULL) { // If renegotiating, the server must not change the server certificate. See // https://mitls.org/pages/attacks/3SHAKE. We never resume on renegotiation, @@ -505,10 +503,10 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) { ssl_open_record_t ret; if (hs->wait == ssl_hs_read_change_cipher_spec) { ret = ssl_open_change_cipher_spec(ssl, &consumed, &alert, - ssl_read_buffer(ssl)); + ssl->s3->read_buffer.span()); } else { - ret = - ssl_open_handshake(ssl, &consumed, &alert, ssl_read_buffer(ssl)); + ret = ssl_open_handshake(ssl, &consumed, &alert, + ssl->s3->read_buffer.span()); } if (ret == ssl_open_record_error && hs->wait == ssl_hs_read_server_hello) { @@ -533,7 +531,7 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) { if (retry) { continue; } - ssl_read_buffer_discard(ssl); + ssl->s3->read_buffer.DiscardConsumed(); break; } @@ -548,42 +546,42 @@ int ssl_run_handshake(SSL_HANDSHAKE *hs, bool *out_early_return) { } case ssl_hs_certificate_selection_pending: - ssl->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; + ssl->s3->rwstate = SSL_CERTIFICATE_SELECTION_PENDING; hs->wait = ssl_hs_ok; return -1; case ssl_hs_x509_lookup: - ssl->rwstate = SSL_X509_LOOKUP; + ssl->s3->rwstate = SSL_X509_LOOKUP; hs->wait = ssl_hs_ok; return -1; case ssl_hs_channel_id_lookup: - ssl->rwstate = SSL_CHANNEL_ID_LOOKUP; + ssl->s3->rwstate = SSL_CHANNEL_ID_LOOKUP; hs->wait = ssl_hs_ok; return -1; case ssl_hs_private_key_operation: - ssl->rwstate = SSL_PRIVATE_KEY_OPERATION; + ssl->s3->rwstate = SSL_PRIVATE_KEY_OPERATION; hs->wait = ssl_hs_ok; return -1; case ssl_hs_pending_session: - ssl->rwstate = SSL_PENDING_SESSION; + ssl->s3->rwstate = SSL_PENDING_SESSION; hs->wait = ssl_hs_ok; return -1; case ssl_hs_pending_ticket: - ssl->rwstate = SSL_PENDING_TICKET; + ssl->s3->rwstate = SSL_PENDING_TICKET; hs->wait = ssl_hs_ok; return -1; case ssl_hs_certificate_verify: - ssl->rwstate = SSL_CERTIFICATE_VERIFY; + ssl->s3->rwstate = SSL_CERTIFICATE_VERIFY; hs->wait = ssl_hs_ok; return -1; case ssl_hs_early_data_rejected: - ssl->rwstate = SSL_EARLY_DATA_REJECTED; + ssl->s3->rwstate = SSL_EARLY_DATA_REJECTED; // Cause |SSL_write| to start failing immediately. hs->can_early_write = false; return -1; diff --git a/src/ssl/handshake_client.cc b/src/ssl/handshake_client.cc index 5466b56c..ff8ebd81 100644 --- a/src/ssl/handshake_client.cc +++ b/src/ssl/handshake_client.cc @@ -1476,14 +1476,15 @@ static enum ssl_hs_wait_t do_send_client_finished(SSL_HANDSHAKE *hs) { if (hs->next_proto_neg_seen) { static const uint8_t kZero[32] = {0}; - size_t padding_len = 32 - ((ssl->s3->next_proto_negotiated_len + 2) % 32); + size_t padding_len = + 32 - ((ssl->s3->next_proto_negotiated.size() + 2) % 32); ScopedCBB cbb; CBB body, child; if (!ssl->method->init_message(ssl, cbb.get(), &body, SSL3_MT_NEXT_PROTO) || !CBB_add_u8_length_prefixed(&body, &child) || - !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated, - ssl->s3->next_proto_negotiated_len) || + !CBB_add_bytes(&child, ssl->s3->next_proto_negotiated.data(), + ssl->s3->next_proto_negotiated.size()) || !CBB_add_u8_length_prefixed(&body, &child) || !CBB_add_bytes(&child, kZero, padding_len) || !ssl_add_message_cbb(ssl, cbb.get())) { @@ -1517,8 +1518,8 @@ static bool can_false_start(const SSL_HANDSHAKE *hs) { // False Start only for TLS 1.2 with an ECDHE+AEAD cipher and ALPN or NPN. return !SSL_is_dtls(ssl) && SSL_version(ssl) == TLS1_2_VERSION && - (ssl->s3->alpn_selected != NULL || - ssl->s3->next_proto_negotiated != NULL) && + (!ssl->s3->alpn_selected.empty() || + !ssl->s3->next_proto_negotiated.empty()) && hs->new_cipher->algorithm_mkey == SSL_kECDHE && hs->new_cipher->algorithm_mac == SSL_AEAD; } @@ -1664,18 +1665,16 @@ static enum ssl_hs_wait_t do_finish_client_handshake(SSL_HANDSHAKE *hs) { ssl->method->on_handshake_complete(ssl); - SSL_SESSION_free(ssl->s3->established_session); if (ssl->session != NULL) { SSL_SESSION_up_ref(ssl->session); - ssl->s3->established_session = ssl->session; + ssl->s3->established_session.reset(ssl->session); } else { // We make a copy of the session in order to maintain the immutability // of the new established_session due to False Start. The caller may // have taken a reference to the temporary session. ssl->s3->established_session = - SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL) - .release(); - if (ssl->s3->established_session == NULL) { + SSL_SESSION_dup(hs->new_session.get(), SSL_SESSION_DUP_ALL); + if (!ssl->s3->established_session) { return ssl_hs_error; } // Renegotiations do not participate in session resumption. diff --git a/src/ssl/handshake_server.cc b/src/ssl/handshake_server.cc index 7b282d87..d3468755 100644 --- a/src/ssl/handshake_server.cc +++ b/src/ssl/handshake_server.cc @@ -1392,8 +1392,7 @@ static enum ssl_hs_wait_t do_read_next_proto(SSL_HANDSHAKE *hs) { return ssl_hs_error; } - if (!CBS_stow(&selected_protocol, &ssl->s3->next_proto_negotiated, - &ssl->s3->next_proto_negotiated_len)) { + if (!ssl->s3->next_proto_negotiated.CopyFrom(selected_protocol)) { return ssl_hs_error; } @@ -1510,12 +1509,11 @@ static enum ssl_hs_wait_t do_finish_server_handshake(SSL_HANDSHAKE *hs) { ssl->ctx->x509_method->session_clear(hs->new_session.get()); } - SSL_SESSION_free(ssl->s3->established_session); if (ssl->session != NULL) { SSL_SESSION_up_ref(ssl->session); - ssl->s3->established_session = ssl->session; + ssl->s3->established_session.reset(ssl->session); } else { - ssl->s3->established_session = hs->new_session.release(); + ssl->s3->established_session = std::move(hs->new_session); ssl->s3->established_session->not_resumable = 0; } diff --git a/src/ssl/internal.h b/src/ssl/internal.h index 174445ae..7e1801ab 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -746,10 +746,10 @@ class SSLAEADContext { struct DTLS1_BITMAP { // map is a bit mask of the last 64 sequence numbers. Bit // |1<<i| corresponds to |max_seq_num - i|. - uint64_t map; + uint64_t map = 0; // max_seq_num is the largest sequence number seen so far as a 64-bit // integer. - uint64_t max_seq_num; + uint64_t max_seq_num = 0; }; @@ -998,9 +998,6 @@ struct SSLMessage { // in a handshake message for |ssl|. size_t ssl_max_handshake_message_len(const SSL *ssl); -// dtls_clear_incoming_messages releases all buffered incoming messages. -void dtls_clear_incoming_messages(SSL *ssl); - // tls_can_accept_handshake_data returns whether |ssl| is able to accept more // data into handshake buffer. bool tls_can_accept_handshake_data(const SSL *ssl, uint8_t *out_alert); @@ -1014,10 +1011,17 @@ bool tls_has_unprocessed_handshake_data(const SSL *ssl); bool dtls_has_unprocessed_handshake_data(const SSL *ssl); struct DTLS_OUTGOING_MESSAGE { - uint8_t *data; - uint32_t len; - uint16_t epoch; - char is_ccs; + DTLS_OUTGOING_MESSAGE() {} + DTLS_OUTGOING_MESSAGE(const DTLS_OUTGOING_MESSAGE &) = delete; + DTLS_OUTGOING_MESSAGE &operator=(const DTLS_OUTGOING_MESSAGE &) = delete; + ~DTLS_OUTGOING_MESSAGE() { Clear(); } + + void Clear(); + + uint8_t *data = nullptr; + uint32_t len = 0; + uint16_t epoch = 0; + bool is_ccs = false; }; // dtls_clear_outgoing_messages releases all buffered outgoing messages. @@ -1036,8 +1040,57 @@ void ssl_do_msg_callback(SSL *ssl, int is_write, int content_type, // Transport buffers. -// ssl_read_buffer returns the current read buffer. -Span<uint8_t> ssl_read_buffer(SSL *ssl); +class SSLBuffer { + public: + SSLBuffer() {} + ~SSLBuffer() { Clear(); } + + SSLBuffer(const SSLBuffer &) = delete; + SSLBuffer &operator=(const SSLBuffer &) = delete; + + uint8_t *data() { return buf_ + offset_; } + size_t size() const { return size_; } + bool empty() const { return size_ == 0; } + size_t cap() const { return cap_; } + + Span<uint8_t> span() { return MakeSpan(data(), size()); } + + Span<uint8_t> remaining() { + return MakeSpan(data() + size(), cap() - size()); + } + + // Clear releases the buffer. + void Clear(); + + // EnsureCap ensures the buffer has capacity at least |new_cap|, aligned such + // that data written after |header_len| is aligned to a + // |SSL3_ALIGN_PAYLOAD|-byte boundary. It returns true on success and false + // on error. + bool EnsureCap(size_t header_len, size_t new_cap); + + // DidWrite extends the buffer by |len|. The caller must have filled in to + // this point. + void DidWrite(size_t len); + + // Consume consumes |len| bytes from the front of the buffer. The memory + // consumed will remain valid until the next call to |DiscardConsumed| or + // |Clear|. + void Consume(size_t len); + + // DiscardConsumed discards the consumed bytes from the buffer. If the buffer + // is now empty, it releases memory used by it. + void DiscardConsumed(); + + private: + // buf_ is the memory allocated for this buffer. + uint8_t *buf_ = nullptr; + // offset_ is the offset into |buf_| which the buffer contents start at. + uint16_t offset_ = 0; + // size_ is the size of the buffer contents from |buf_| + |offset_|. + uint16_t size_ = 0; + // cap_ is how much memory beyond |buf_| + |offset_| is available. + uint16_t cap_ = 0; +}; // ssl_read_buffer_extend_to extends the read buffer to the desired length. For // TLS, it reads to the end of the buffer until the buffer is |len| bytes @@ -1048,49 +1101,18 @@ Span<uint8_t> ssl_read_buffer(SSL *ssl); // non-empty. int ssl_read_buffer_extend_to(SSL *ssl, size_t len); -// ssl_read_buffer_consume consumes |len| bytes from the read buffer. It -// advances the data pointer and decrements the length. The memory consumed will -// remain valid until the next call to |ssl_read_buffer_extend| or it is -// discarded with |ssl_read_buffer_discard|. -void ssl_read_buffer_consume(SSL *ssl, size_t len); - -// ssl_read_buffer_discard discards the consumed bytes from the read buffer. If -// the buffer is now empty, it releases memory used by it. -void ssl_read_buffer_discard(SSL *ssl); - -// ssl_read_buffer_clear releases all memory associated with the read buffer and -// zero-initializes it. -void ssl_read_buffer_clear(SSL *ssl); - -// ssl_handle_open_record handles the result of passing |ssl_read_buffer| to a -// record-processing function. If |ret| is a success or if the caller should -// retry, it returns one and sets |*out_retry|. Otherwise, it returns <= 0. +// ssl_handle_open_record handles the result of passing |ssl->s3->read_buffer| +// to a record-processing function. If |ret| is a success or if the caller +// should retry, it returns one and sets |*out_retry|. Otherwise, it returns <= +// 0. int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret, size_t consumed, uint8_t alert); -// ssl_write_buffer_is_pending returns one if the write buffer has pending data -// and zero if is empty. -int ssl_write_buffer_is_pending(const SSL *ssl); - -// ssl_write_buffer_init initializes the write buffer. On success, it sets -// |*out_ptr| to the start of the write buffer with space for up to |max_len| -// bytes. It returns one on success and zero on failure. Call -// |ssl_write_buffer_set_len| to complete initialization. -int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len); - -// ssl_write_buffer_set_len is called after |ssl_write_buffer_init| to complete -// initialization after |len| bytes are written to the buffer. -void ssl_write_buffer_set_len(SSL *ssl, size_t len); - // ssl_write_buffer_flush flushes the write buffer to the transport. It returns // one on success and <= 0 on error. For DTLS, whether or not the write // succeeds, the write buffer will be cleared. int ssl_write_buffer_flush(SSL *ssl); -// ssl_write_buffer_clear releases all memory associated with the write buffer -// and zero-initializes it. -void ssl_write_buffer_clear(SSL *ssl); - // Certificate functions. @@ -1468,10 +1490,7 @@ struct SSL_HANDSHAKE { uint16_t early_data_written = 0; }; -SSL_HANDSHAKE *ssl_handshake_new(SSL *ssl); - -// ssl_handshake_free releases all memory associated with |hs|. -void ssl_handshake_free(SSL_HANDSHAKE *hs); +UniquePtr<SSL_HANDSHAKE> ssl_handshake_new(SSL *ssl); // ssl_check_message_type checks if |msg| has type |type|. If so it returns // one. Otherwise, it sends an alert and returns zero. @@ -1556,6 +1575,10 @@ bool tls13_get_cert_verify_signature_input( SSL_HANDSHAKE *hs, Array<uint8_t> *out, enum ssl_cert_verify_context_t cert_verify_context); +// ssl_is_alpn_protocol_allowed returns whether |protocol| is a valid server +// selection for |ssl|'s client preferences. +bool ssl_is_alpn_protocol_allowed(const SSL *ssl, Span<const uint8_t> protocol); + // ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns // true on successful negotiation or if nothing was negotiated. It returns false // and sets |*out_alert| to an alert on error. @@ -2134,17 +2157,6 @@ struct SSLContext { bool ed25519_enabled:1; }; -struct SSL3_BUFFER { - // buf is the memory allocated for this buffer. - uint8_t *buf; - // offset is the offset into |buf| which the buffer contents start at. - uint16_t offset; - // len is the length of the buffer contents from |buf| + |offset|. - uint16_t len; - // cap is how much memory beyond |buf| + |offset| is available. - uint16_t cap; -}; - // An ssl_shutdown_t describes the shutdown state of one end of the connection, // whether it is alive or has been shutdown via close_notify or fatal alert. enum ssl_shutdown_t { @@ -2154,55 +2166,65 @@ enum ssl_shutdown_t { }; struct SSL3_STATE { - uint8_t read_sequence[8]; - uint8_t write_sequence[8]; + static constexpr bool kAllowUniquePtr = true; + + SSL3_STATE(); + ~SSL3_STATE(); - uint8_t server_random[SSL3_RANDOM_SIZE]; - uint8_t client_random[SSL3_RANDOM_SIZE]; + uint8_t read_sequence[8] = {0}; + uint8_t write_sequence[8] = {0}; + + uint8_t server_random[SSL3_RANDOM_SIZE] = {0}; + uint8_t client_random[SSL3_RANDOM_SIZE] = {0}; // read_buffer holds data from the transport to be processed. - SSL3_BUFFER read_buffer; + SSLBuffer read_buffer; // write_buffer holds data to be written to the transport. - SSL3_BUFFER write_buffer; + SSLBuffer write_buffer; // pending_app_data is the unconsumed application data. It points into // |read_buffer|. Span<uint8_t> pending_app_data; // partial write - check the numbers match - unsigned int wnum; // number of bytes sent so far - int wpend_tot; // number bytes written - int wpend_type; - int wpend_ret; // number of bytes submitted - const uint8_t *wpend_buf; + unsigned int wnum = 0; // number of bytes sent so far + int wpend_tot = 0; // number bytes written + int wpend_type = 0; + int wpend_ret = 0; // number of bytes submitted + const uint8_t *wpend_buf = nullptr; // read_shutdown is the shutdown state for the read half of the connection. - enum ssl_shutdown_t read_shutdown; + enum ssl_shutdown_t read_shutdown = ssl_shutdown_none; // write_shutdown is the shutdown state for the write half of the connection. - enum ssl_shutdown_t write_shutdown; + enum ssl_shutdown_t write_shutdown = ssl_shutdown_none; // read_error, if |read_shutdown| is |ssl_shutdown_error|, is the error for // the receive half of the connection. - ERR_SAVE_STATE *read_error; + UniquePtr<ERR_SAVE_STATE> read_error; + + int alert_dispatch = 0; - int alert_dispatch; + int total_renegotiations = 0; - int total_renegotiations; + // This holds a variable that indicates what we were doing when a 0 or -1 is + // returned. This is needed for non-blocking IO so we know what request + // needs re-doing when in SSL_accept or SSL_connect + int rwstate = SSL_NOTHING; // early_data_skipped is the amount of early data that has been skipped by the // record layer. - uint16_t early_data_skipped; + uint16_t early_data_skipped = 0; // empty_record_count is the number of consecutive empty records received. - uint8_t empty_record_count; + uint8_t empty_record_count = 0; // warning_alert_count is the number of consecutive warning alerts // received. - uint8_t warning_alert_count; + uint8_t warning_alert_count = 0; // key_update_count is the number of consecutive KeyUpdates received. - uint8_t key_update_count; + uint8_t key_update_count = 0; // skip_early_data instructs the record layer to skip unexpected early data // messages when 0RTT is rejected. @@ -2246,56 +2268,49 @@ struct SSL3_STATE { // wpend_pending is true if we have a pending write outstanding. bool wpend_pending:1; - uint8_t send_alert[2]; + uint8_t send_alert[2] = {0}; + + // hs_buf is the buffer of handshake data to process. + UniquePtr<BUF_MEM> hs_buf; // pending_flight is the pending outgoing flight. This is used to flush each // handshake flight in a single write. |write_buffer| must be written out // before this data. - BUF_MEM *pending_flight; + UniquePtr<BUF_MEM> pending_flight; // pending_flight_offset is the number of bytes of |pending_flight| which have // been successfully written. - uint32_t pending_flight_offset; + uint32_t pending_flight_offset = 0; // aead_read_ctx is the current read cipher state. - SSLAEADContext *aead_read_ctx; + UniquePtr<SSLAEADContext> aead_read_ctx; // aead_write_ctx is the current write cipher state. - SSLAEADContext *aead_write_ctx; + UniquePtr<SSLAEADContext> aead_write_ctx; // hs is the handshake state for the current handshake or NULL if there isn't // one. - SSL_HANDSHAKE *hs; + UniquePtr<SSL_HANDSHAKE> hs; - uint8_t write_traffic_secret[EVP_MAX_MD_SIZE]; - uint8_t read_traffic_secret[EVP_MAX_MD_SIZE]; - uint8_t exporter_secret[EVP_MAX_MD_SIZE]; - uint8_t early_exporter_secret[EVP_MAX_MD_SIZE]; - uint8_t write_traffic_secret_len; - uint8_t read_traffic_secret_len; - uint8_t exporter_secret_len; - uint8_t early_exporter_secret_len; + uint8_t write_traffic_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t read_traffic_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t exporter_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t early_exporter_secret[EVP_MAX_MD_SIZE] = {0}; + uint8_t write_traffic_secret_len = 0; + uint8_t read_traffic_secret_len = 0; + uint8_t exporter_secret_len = 0; + uint8_t early_exporter_secret_len = 0; // Connection binding to prevent renegotiation attacks - uint8_t previous_client_finished[12]; - uint8_t previous_client_finished_len; - uint8_t previous_server_finished_len; - uint8_t previous_server_finished[12]; - - // State pertaining to the pending handshake. - // - // TODO(davidben): Move everything not needed after the handshake completes to - // |hs| and remove this. - struct { - uint8_t new_mac_secret_len; - uint8_t new_key_len; - uint8_t new_fixed_iv_len; - } tmp; + uint8_t previous_client_finished[12] = {0}; + uint8_t previous_client_finished_len = 0; + uint8_t previous_server_finished_len = 0; + uint8_t previous_server_finished[12] = {0}; // established_session is the session established by the connection. This // session is only filled upon the completion of the handshake and is // immutable. - SSL_SESSION *established_session; + UniquePtr<SSL_SESSION> established_session; // Next protocol negotiation. For the client, this is the protocol that we // sent in NextProtocol and is set when handling ServerHello extensions. @@ -2303,8 +2318,7 @@ struct SSL3_STATE { // For a server, this is the client's selected_protocol from NextProtocol and // is set when handling the NextProtocol message, before the Finished // message. - uint8_t *next_proto_negotiated; - size_t next_proto_negotiated_len; + Array<uint8_t> next_proto_negotiated; // ALPN information // (we are in the process of transitioning from NPN to ALPN.) @@ -2312,22 +2326,21 @@ struct SSL3_STATE { // In a server these point to the selected ALPN protocol after the // ClientHello has been processed. In a client these contain the protocol // that the server selected once the ServerHello has been processed. - uint8_t *alpn_selected; - size_t alpn_selected_len; + Array<uint8_t> alpn_selected; // hostname, on the server, is the value of the SNI extension. - char *hostname; + UniquePtr<char> hostname; // For a server: // If |tlsext_channel_id_valid| is true, then this contains the // verified Channel ID from the client: a P256 point, (x,y), where // each are big-endian values. - uint8_t tlsext_channel_id[64]; + uint8_t tlsext_channel_id[64] = {0}; // ticket_age_skew is the difference, in seconds, between the client-sent // ticket age and the server-computed value in TLS 1.3 server connections // which resumed a session. - int32_t ticket_age_skew; + int32_t ticket_age_skew = 0; }; // lengths of messages @@ -2351,18 +2364,26 @@ struct hm_header_st { // An hm_fragment is an incoming DTLS message, possibly not yet assembled. struct hm_fragment { + static constexpr bool kAllowUniquePtr = true; + + hm_fragment() {} + hm_fragment(const hm_fragment &) = delete; + hm_fragment &operator=(const hm_fragment &) = delete; + + ~hm_fragment(); + // type is the type of the message. - uint8_t type; + uint8_t type = 0; // seq is the sequence number of this message. - uint16_t seq; + uint16_t seq = 0; // msg_len is the length of the message body. - uint32_t msg_len; + uint32_t msg_len = 0; // data is a pointer to the message, including message header. It has length // |DTLS1_HM_HEADER_LENGTH| + |msg_len|. - uint8_t *data; + uint8_t *data = nullptr; // reassembly is a bitmask of |msg_len| bits corresponding to which parts of // the message have been received. It is NULL if the message is complete. - uint8_t *reassembly; + uint8_t *reassembly = nullptr; }; struct OPENSSL_timeval { @@ -2371,6 +2392,11 @@ struct OPENSSL_timeval { }; struct DTLS1_STATE { + static constexpr bool kAllowUniquePtr = true; + + DTLS1_STATE(); + ~DTLS1_STATE(); + // has_change_cipher_spec is true if we have received a ChangeCipherSpec from // the peer in this epoch. bool has_change_cipher_spec:1; @@ -2385,54 +2411,54 @@ struct DTLS1_STATE { // peer sent the final flight. bool flight_has_reply:1; - uint8_t cookie[DTLS1_COOKIE_LENGTH]; - size_t cookie_len; + uint8_t cookie[DTLS1_COOKIE_LENGTH] = {0}; + size_t cookie_len = 0; // The current data and handshake epoch. This is initially undefined, and // starts at zero once the initial handshake is completed. - uint16_t r_epoch; - uint16_t w_epoch; + uint16_t r_epoch = 0; + uint16_t w_epoch = 0; // records being received in the current epoch DTLS1_BITMAP bitmap; - uint16_t handshake_write_seq; - uint16_t handshake_read_seq; + uint16_t handshake_write_seq = 0; + uint16_t handshake_read_seq = 0; // save last sequence number for retransmissions - uint8_t last_write_sequence[8]; - SSLAEADContext *last_aead_write_ctx; + uint8_t last_write_sequence[8] = {0}; + UniquePtr<SSLAEADContext> last_aead_write_ctx; // incoming_messages is a ring buffer of incoming handshake messages that have // yet to be processed. The front of the ring buffer is message number // |handshake_read_seq|, at position |handshake_read_seq| % // |SSL_MAX_HANDSHAKE_FLIGHT|. - hm_fragment *incoming_messages[SSL_MAX_HANDSHAKE_FLIGHT]; + UniquePtr<hm_fragment> incoming_messages[SSL_MAX_HANDSHAKE_FLIGHT]; // outgoing_messages is the queue of outgoing messages from the last handshake // flight. DTLS_OUTGOING_MESSAGE outgoing_messages[SSL_MAX_HANDSHAKE_FLIGHT]; - uint8_t outgoing_messages_len; + uint8_t outgoing_messages_len = 0; // outgoing_written is the number of outgoing messages that have been // written. - uint8_t outgoing_written; + uint8_t outgoing_written = 0; // outgoing_offset is the number of bytes of the next outgoing message have // been written. - uint32_t outgoing_offset; + uint32_t outgoing_offset = 0; - unsigned int mtu; // max DTLS packet size + unsigned mtu = 0; // max DTLS packet size // num_timeouts is the number of times the retransmit timer has fired since // the last time it was reset. - unsigned int num_timeouts; + unsigned num_timeouts = 0; // Indicates when the last handshake msg or heartbeat sent will // timeout. - struct OPENSSL_timeval next_timeout; + struct OPENSSL_timeval next_timeout = {0, 0}; // timeout_duration_ms is the timeout duration in milliseconds. - unsigned timeout_duration_ms; + unsigned timeout_duration_ms = 0; }; // SSLConnection backs the public |SSL| type. Due to compatibility constraints, @@ -2472,8 +2498,6 @@ struct SSLConnection { // progress. enum ssl_hs_wait_t (*do_handshake)(SSL_HANDSHAKE *hs); - BUF_MEM *init_buf; // buffer used during init - SSL3_STATE *s3; // SSLv3 variables DTLS1_STATE *d1; // DTLSv1 variables @@ -2493,11 +2517,6 @@ struct SSLConnection { // This is used to hold the server certificate used CERT *cert; - // This holds a variable that indicates what we were doing when a 0 or -1 is - // returned. This is needed for non-blocking IO so we know what request - // needs re-doing when in SSL_accept or SSL_connect - int rwstate; - // initial_timeout_duration_ms is the default DTLS timeout duration in // milliseconds. It's used to initialize the timer any time it's restarted. unsigned initial_timeout_duration_ms; @@ -2601,7 +2620,6 @@ struct SSLConnection { }; // From draft-ietf-tls-tls13-18, used in determining PSK modes. -#define SSL_PSK_KE 0x0 #define SSL_PSK_DHE_KE 0x1 // From draft-ietf-tls-tls13-16, used in determining whether to respond with a diff --git a/src/ssl/s3_both.cc b/src/ssl/s3_both.cc index 14590857..ede4ba7e 100644 --- a/src/ssl/s3_both.cc +++ b/src/ssl/s3_both.cc @@ -137,9 +137,9 @@ static bool add_record_to_flight(SSL *ssl, uint8_t type, // We'll never add a flight while in the process of writing it out. assert(ssl->s3->pending_flight_offset == 0); - if (ssl->s3->pending_flight == NULL) { - ssl->s3->pending_flight = BUF_MEM_new(); - if (ssl->s3->pending_flight == NULL) { + if (ssl->s3->pending_flight == nullptr) { + ssl->s3->pending_flight.reset(BUF_MEM_new()); + if (ssl->s3->pending_flight == nullptr) { return false; } } @@ -152,7 +152,7 @@ static bool add_record_to_flight(SSL *ssl, uint8_t type, } size_t len; - if (!BUF_MEM_reserve(ssl->s3->pending_flight, new_cap) || + if (!BUF_MEM_reserve(ssl->s3->pending_flight.get(), new_cap) || !tls_seal_record(ssl, (uint8_t *)ssl->s3->pending_flight->data + ssl->s3->pending_flight->length, @@ -229,7 +229,7 @@ bool ssl3_add_alert(SSL *ssl, uint8_t level, uint8_t desc) { } int ssl3_flush_flight(SSL *ssl) { - if (ssl->s3->pending_flight == NULL) { + if (ssl->s3->pending_flight == nullptr) { return 1; } @@ -246,10 +246,10 @@ int ssl3_flush_flight(SSL *ssl) { // If there is pending data in the write buffer, it must be flushed out before // any new data in pending_flight. - if (ssl_write_buffer_is_pending(ssl)) { + if (!ssl->s3->write_buffer.empty()) { int ret = ssl_write_buffer_flush(ssl); if (ret <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; return ret; } } @@ -261,7 +261,7 @@ int ssl3_flush_flight(SSL *ssl) { ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset, ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset); if (ret <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; return ret; } @@ -269,12 +269,11 @@ int ssl3_flush_flight(SSL *ssl) { } if (BIO_flush(ssl->wbio) <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; return -1; } - BUF_MEM_free(ssl->s3->pending_flight); - ssl->s3->pending_flight = NULL; + ssl->s3->pending_flight.reset(); ssl->s3->pending_flight_offset = 0; return 1; } @@ -303,7 +302,7 @@ static ssl_open_record_t read_v2_client_hello(SSL *ssl, size_t *out_consumed, return ssl_open_record_partial; } - CBS v2_client_hello = CBS(ssl_read_buffer(ssl).subspan(2, msg_length)); + CBS v2_client_hello = CBS(ssl->s3->read_buffer.span().subspan(2, msg_length)); // The V2ClientHello without the length is incorporated into the handshake // hash. This is only ever called at the start of the handshake, so hs is // guaranteed to be non-NULL. @@ -352,9 +351,9 @@ static ssl_open_record_t read_v2_client_hello(SSL *ssl, size_t *out_consumed, 1 /* compression length */ + 1 /* compression */; ScopedCBB client_hello; CBB hello_body, cipher_suites; - if (!BUF_MEM_reserve(ssl->init_buf, max_v3_client_hello) || - !CBB_init_fixed(client_hello.get(), (uint8_t *)ssl->init_buf->data, - ssl->init_buf->max) || + if (!BUF_MEM_reserve(ssl->s3->hs_buf.get(), max_v3_client_hello) || + !CBB_init_fixed(client_hello.get(), (uint8_t *)ssl->s3->hs_buf->data, + ssl->s3->hs_buf->max) || !CBB_add_u8(client_hello.get(), SSL3_MT_CLIENT_HELLO) || !CBB_add_u24_length_prefixed(client_hello.get(), &hello_body) || !CBB_add_u16(&hello_body, version) || @@ -387,7 +386,7 @@ static ssl_open_record_t read_v2_client_hello(SSL *ssl, size_t *out_consumed, // Add the null compression scheme and finish. if (!CBB_add_u8(&hello_body, 1) || !CBB_add_u8(&hello_body, 0) || - !CBB_finish(client_hello.get(), NULL, &ssl->init_buf->length)) { + !CBB_finish(client_hello.get(), NULL, &ssl->s3->hs_buf->length)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return ssl_open_record_error; } @@ -399,15 +398,15 @@ static ssl_open_record_t read_v2_client_hello(SSL *ssl, size_t *out_consumed, static bool parse_message(const SSL *ssl, SSLMessage *out, size_t *out_bytes_needed) { - if (ssl->init_buf == NULL) { + if (!ssl->s3->hs_buf) { *out_bytes_needed = 4; return false; } CBS cbs; uint32_t len; - CBS_init(&cbs, reinterpret_cast<const uint8_t *>(ssl->init_buf->data), - ssl->init_buf->length); + CBS_init(&cbs, reinterpret_cast<const uint8_t *>(ssl->s3->hs_buf->data), + ssl->s3->hs_buf->length); if (!CBS_get_u8(&cbs, &out->type) || !CBS_get_u24(&cbs, &len)) { *out_bytes_needed = 4; @@ -419,7 +418,7 @@ static bool parse_message(const SSL *ssl, SSLMessage *out, return false; } - CBS_init(&out->raw, reinterpret_cast<const uint8_t *>(ssl->init_buf->data), + CBS_init(&out->raw, reinterpret_cast<const uint8_t *>(ssl->s3->hs_buf->data), 4 + len); out->is_v2_hello = ssl->s3->is_v2_hello; return true; @@ -469,16 +468,16 @@ bool tls_has_unprocessed_handshake_data(const SSL *ssl) { } } - return ssl->init_buf != NULL && ssl->init_buf->length > msg_len; + return ssl->s3->hs_buf && ssl->s3->hs_buf->length > msg_len; } ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed, uint8_t *out_alert, Span<uint8_t> in) { *out_consumed = 0; // Re-create the handshake buffer if needed. - if (ssl->init_buf == NULL) { - ssl->init_buf = BUF_MEM_new(); - if (ssl->init_buf == NULL) { + if (!ssl->s3->hs_buf) { + ssl->s3->hs_buf.reset(BUF_MEM_new()); + if (!ssl->s3->hs_buf) { *out_alert = SSL_AD_INTERNAL_ERROR; return ssl_open_record_error; } @@ -552,7 +551,7 @@ ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed, } // Append the entire handshake record to the buffer. - if (!BUF_MEM_append(ssl->init_buf, body.data(), body.size())) { + if (!BUF_MEM_append(ssl->s3->hs_buf.get(), body.data(), body.size())) { *out_alert = SSL_AD_INTERNAL_ERROR; return ssl_open_record_error; } @@ -563,23 +562,23 @@ ssl_open_record_t ssl3_open_handshake(SSL *ssl, size_t *out_consumed, void ssl3_next_message(SSL *ssl) { SSLMessage msg; if (!ssl3_get_message(ssl, &msg) || - ssl->init_buf == NULL || - ssl->init_buf->length < CBS_len(&msg.raw)) { + !ssl->s3->hs_buf || + ssl->s3->hs_buf->length < CBS_len(&msg.raw)) { assert(0); return; } - OPENSSL_memmove(ssl->init_buf->data, ssl->init_buf->data + CBS_len(&msg.raw), - ssl->init_buf->length - CBS_len(&msg.raw)); - ssl->init_buf->length -= CBS_len(&msg.raw); + OPENSSL_memmove(ssl->s3->hs_buf->data, + ssl->s3->hs_buf->data + CBS_len(&msg.raw), + ssl->s3->hs_buf->length - CBS_len(&msg.raw)); + ssl->s3->hs_buf->length -= CBS_len(&msg.raw); ssl->s3->is_v2_hello = false; ssl->s3->has_message = false; // Post-handshake messages are rare, so release the buffer after every // message. During the handshake, |on_handshake_complete| will release it. - if (!SSL_in_init(ssl) && ssl->init_buf->length == 0) { - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; + if (!SSL_in_init(ssl) && ssl->s3->hs_buf->length == 0) { + ssl->s3->hs_buf.reset(); } } diff --git a/src/ssl/s3_lib.cc b/src/ssl/s3_lib.cc index f3f99fa4..b925cd72 100644 --- a/src/ssl/s3_lib.cc +++ b/src/ssl/s3_lib.cc @@ -164,30 +164,35 @@ namespace bssl { -bool ssl3_new(SSL *ssl) { - UniquePtr<SSLAEADContext> aead_read_ctx = - SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); - UniquePtr<SSLAEADContext> aead_write_ctx = - SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); - if (!aead_read_ctx || !aead_write_ctx) { - return false; - } +SSL3_STATE::SSL3_STATE() + : skip_early_data(false), + have_version(false), + v2_hello_done(false), + is_v2_hello(false), + has_message(false), + initial_handshake_complete(false), + session_reused(false), + send_connection_binding(false), + tlsext_channel_id_valid(false), + key_update_pending(false), + wpend_pending(false) {} + +SSL3_STATE::~SSL3_STATE() {} - SSL3_STATE *s3 = (SSL3_STATE *)OPENSSL_malloc(sizeof *s3); - if (s3 == NULL) { +bool ssl3_new(SSL *ssl) { + UniquePtr<SSL3_STATE> s3 = MakeUnique<SSL3_STATE>(); + if (!s3) { return false; } - OPENSSL_memset(s3, 0, sizeof *s3); + s3->aead_read_ctx = SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); + s3->aead_write_ctx = SSLAEADContext::CreateNullCipher(SSL_is_dtls(ssl)); s3->hs = ssl_handshake_new(ssl); - if (s3->hs == NULL) { - OPENSSL_free(s3); + if (!s3->aead_read_ctx || !s3->aead_write_ctx || !s3->hs) { return false; } - s3->aead_read_ctx = aead_read_ctx.release(); - s3->aead_write_ctx = aead_write_ctx.release(); - ssl->s3 = s3; + ssl->s3 = s3.release(); // Set the version to the highest supported version. // @@ -203,20 +208,7 @@ void ssl3_free(SSL *ssl) { return; } - ssl_read_buffer_clear(ssl); - ssl_write_buffer_clear(ssl); - - ERR_SAVE_STATE_free(ssl->s3->read_error); - SSL_SESSION_free(ssl->s3->established_session); - ssl_handshake_free(ssl->s3->hs); - OPENSSL_free(ssl->s3->next_proto_negotiated); - OPENSSL_free(ssl->s3->alpn_selected); - OPENSSL_free(ssl->s3->hostname); - Delete(ssl->s3->aead_read_ctx); - Delete(ssl->s3->aead_write_ctx); - BUF_MEM_free(ssl->s3->pending_flight); - - OPENSSL_free(ssl->s3); + Delete(ssl->s3); ssl->s3 = NULL; } diff --git a/src/ssl/s3_pkt.cc b/src/ssl/s3_pkt.cc index 7966e6f2..285abb36 100644 --- a/src/ssl/s3_pkt.cc +++ b/src/ssl/s3_pkt.cc @@ -124,9 +124,9 @@ namespace bssl { -static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len); +static int do_ssl3_write(SSL *ssl, int type, const uint8_t *in, unsigned len); -int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf, +int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *in, int len) { assert(ssl_can_write(ssl)); assert(!ssl->s3->aead_write_ctx->is_null_cipher()); @@ -180,7 +180,7 @@ int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf, nw = n; } - int ret = do_ssl3_write(ssl, SSL3_RT_APPLICATION_DATA, &buf[tot], nw); + int ret = do_ssl3_write(ssl, SSL3_RT_APPLICATION_DATA, &in[tot], nw); if (ret <= 0) { ssl->s3->wnum = tot; return ret; @@ -199,11 +199,11 @@ int ssl3_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf, } } -static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf, +static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *in, unsigned int len) { if (ssl->s3->wpend_tot > (int)len || (!(ssl->mode & SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER) && - ssl->s3->wpend_buf != buf) || + ssl->s3->wpend_buf != in) || ssl->s3->wpend_type != type) { OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_WRITE_RETRY); return -1; @@ -218,13 +218,14 @@ static int ssl3_write_pending(SSL *ssl, int type, const uint8_t *buf, } // do_ssl3_write writes an SSL record of the given type. -static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { +static int do_ssl3_write(SSL *ssl, int type, const uint8_t *in, unsigned len) { // If there is still data from the previous record, flush it. if (ssl->s3->wpend_pending) { - return ssl3_write_pending(ssl, type, buf, len); + return ssl3_write_pending(ssl, type, in, len); } - if (len > SSL3_RT_MAX_PLAIN_LENGTH) { + SSLBuffer *buf = &ssl->s3->write_buffer; + if (len > SSL3_RT_MAX_PLAIN_LENGTH || buf->size() > 0) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } @@ -234,7 +235,7 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { } size_t flight_len = 0; - if (ssl->s3->pending_flight != NULL) { + if (ssl->s3->pending_flight != nullptr) { flight_len = ssl->s3->pending_flight->length - ssl->s3->pending_flight_offset; } @@ -246,9 +247,7 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { } max_out += flight_len; - uint8_t *out; - size_t ciphertext_len; - if (!ssl_write_buffer_init(ssl, &out, max_out)) { + if (!buf->EnsureCap(flight_len + ssl_seal_align_prefix_len(ssl), max_out)) { return -1; } @@ -256,20 +255,22 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { // acknowledgment or 0-RTT key change messages. |pending_flight| must be clear // when data is added to |write_buffer| or it will be written in the wrong // order. - if (ssl->s3->pending_flight != NULL) { + if (ssl->s3->pending_flight != nullptr) { OPENSSL_memcpy( - out, ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset, + buf->remaining().data(), + ssl->s3->pending_flight->data + ssl->s3->pending_flight_offset, flight_len); - BUF_MEM_free(ssl->s3->pending_flight); - ssl->s3->pending_flight = NULL; + ssl->s3->pending_flight.reset(); ssl->s3->pending_flight_offset = 0; + buf->DidWrite(flight_len); } - if (!tls_seal_record(ssl, out + flight_len, &ciphertext_len, - max_out - flight_len, type, buf, len)) { + size_t ciphertext_len; + if (!tls_seal_record(ssl, buf->remaining().data(), &ciphertext_len, + buf->remaining().size(), type, in, len)) { return -1; } - ssl_write_buffer_set_len(ssl, flight_len + ciphertext_len); + buf->DidWrite(ciphertext_len); // Now that we've made progress on the connection, uncork KeyUpdate // acknowledgments. @@ -278,13 +279,13 @@ static int do_ssl3_write(SSL *ssl, int type, const uint8_t *buf, unsigned len) { // Memorize arguments so that ssl3_write_pending can detect bad write retries // later. ssl->s3->wpend_tot = len; - ssl->s3->wpend_buf = buf; + ssl->s3->wpend_buf = in; ssl->s3->wpend_type = type; ssl->s3->wpend_ret = len; ssl->s3->wpend_pending = true; // We now just need to write the buffer. - return ssl3_write_pending(ssl, type, buf, len); + return ssl3_write_pending(ssl, type, in, len); } ssl_open_record_t ssl3_open_app_data(SSL *ssl, Span<uint8_t> *out, @@ -320,11 +321,11 @@ ssl_open_record_t ssl3_open_app_data(SSL *ssl, Span<uint8_t> *out, return ssl_open_record_error; } - if (ssl->init_buf == NULL) { - ssl->init_buf = BUF_MEM_new(); + if (!ssl->s3->hs_buf) { + ssl->s3->hs_buf.reset(BUF_MEM_new()); } - if (ssl->init_buf == NULL || - !BUF_MEM_append(ssl->init_buf, body.data(), body.size())) { + if (!ssl->s3->hs_buf || + !BUF_MEM_append(ssl->s3->hs_buf.get(), body.data(), body.size())) { *out_alert = SSL_AD_INTERNAL_ERROR; return ssl_open_record_error; } @@ -408,7 +409,7 @@ int ssl_send_alert(SSL *ssl, int level, int desc) { ssl->s3->alert_dispatch = 1; ssl->s3->send_alert[0] = level; ssl->s3->send_alert[1] = desc; - if (!ssl_write_buffer_is_pending(ssl)) { + if (ssl->s3->write_buffer.empty()) { // Nothing is being written out, so the alert may be dispatched // immediately. return ssl->method->dispatch_alert(ssl); diff --git a/src/ssl/ssl_buffer.cc b/src/ssl/ssl_buffer.cc index 412df736..da1de930 100644 --- a/src/ssl/ssl_buffer.cc +++ b/src/ssl/ssl_buffer.cc @@ -36,17 +36,22 @@ static_assert(0xffff <= INT_MAX, "uint16_t does not fit in int"); static_assert((SSL3_ALIGN_PAYLOAD & (SSL3_ALIGN_PAYLOAD - 1)) == 0, "SSL3_ALIGN_PAYLOAD must be a power of 2"); -// ensure_buffer ensures |buf| has capacity at least |cap|, aligned such that -// data written after |header_len| is aligned to a |SSL3_ALIGN_PAYLOAD|-byte -// boundary. It returns one on success and zero on error. -static int ensure_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) { - if (cap > 0xffff) { +void SSLBuffer::Clear() { + free(buf_); // Allocated with malloc(). + buf_ = nullptr; + offset_ = 0; + size_ = 0; + cap_ = 0; +} + +bool SSLBuffer::EnsureCap(size_t header_len, size_t new_cap) { + if (new_cap > 0xffff) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return false; } - if (buf->cap >= cap) { - return 1; + if (cap_ >= new_cap) { + return true; } // Add up to |SSL3_ALIGN_PAYLOAD| - 1 bytes of slack for alignment. @@ -54,88 +59,88 @@ static int ensure_buffer(SSL3_BUFFER *buf, size_t header_len, size_t cap) { // Since this buffer gets allocated quite frequently and doesn't contain any // sensitive data, we allocate with malloc rather than |OPENSSL_malloc| and // avoid zeroing on free. - uint8_t *new_buf = (uint8_t *)malloc(cap + SSL3_ALIGN_PAYLOAD - 1); + uint8_t *new_buf = (uint8_t *)malloc(new_cap + SSL3_ALIGN_PAYLOAD - 1); if (new_buf == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; + return false; } // Offset the buffer such that the record body is aligned. size_t new_offset = (0 - header_len - (uintptr_t)new_buf) & (SSL3_ALIGN_PAYLOAD - 1); - if (buf->buf != NULL) { - OPENSSL_memcpy(new_buf + new_offset, buf->buf + buf->offset, buf->len); - free(buf->buf); // Allocated with malloc(). + if (buf_ != NULL) { + OPENSSL_memcpy(new_buf + new_offset, buf_ + offset_, size_); + free(buf_); // Allocated with malloc(). } - buf->buf = new_buf; - buf->offset = new_offset; - buf->cap = cap; - return 1; + buf_ = new_buf; + offset_ = new_offset; + cap_ = new_cap; + return true; } -static void consume_buffer(SSL3_BUFFER *buf, size_t len) { - if (len > buf->len) { +void SSLBuffer::DidWrite(size_t new_size) { + if (new_size > cap() - size()) { abort(); } - buf->offset += (uint16_t)len; - buf->len -= (uint16_t)len; - buf->cap -= (uint16_t)len; + size_ += new_size; } -static void clear_buffer(SSL3_BUFFER *buf) { - free(buf->buf); // Allocated with malloc(). - OPENSSL_memset(buf, 0, sizeof(SSL3_BUFFER)); +void SSLBuffer::Consume(size_t len) { + if (len > size_) { + abort(); + } + offset_ += (uint16_t)len; + size_ -= (uint16_t)len; + cap_ -= (uint16_t)len; } -Span<uint8_t> ssl_read_buffer(SSL *ssl) { - return MakeSpan(ssl->s3->read_buffer.buf + ssl->s3->read_buffer.offset, - ssl->s3->read_buffer.len); +void SSLBuffer::DiscardConsumed() { + if (size_ == 0) { + Clear(); + } } static int dtls_read_buffer_next_packet(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; + SSLBuffer *buf = &ssl->s3->read_buffer; - if (buf->len > 0) { + if (!buf->empty()) { // It is an error to call |dtls_read_buffer_extend| when the read buffer is // not empty. OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return -1; } - // Read a single packet from |ssl->rbio|. |buf->cap| must fit in an int. - int ret = BIO_read(ssl->rbio, buf->buf + buf->offset, (int)buf->cap); + // Read a single packet from |ssl->rbio|. |buf->cap()| must fit in an int. + int ret = BIO_read(ssl->rbio, buf->data(), static_cast<int>(buf->cap())); if (ret <= 0) { - ssl->rwstate = SSL_READING; + ssl->s3->rwstate = SSL_READING; return ret; } - // |BIO_read| was bound by |buf->cap|, so this cannot overflow. - buf->len = (uint16_t)ret; + buf->DidWrite(static_cast<size_t>(ret)); return 1; } static int tls_read_buffer_extend_to(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; + SSLBuffer *buf = &ssl->s3->read_buffer; - if (len > buf->cap) { + if (len > buf->cap()) { OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL); return -1; } // Read until the target length is reached. - while (buf->len < len) { + while (buf->size() < len) { // The amount of data to read is bounded by |buf->cap|, which must fit in an // int. - int ret = BIO_read(ssl->rbio, buf->buf + buf->offset + buf->len, - (int)(len - buf->len)); + int ret = BIO_read(ssl->rbio, buf->data() + buf->size(), + static_cast<int>(len - buf->size())); if (ret <= 0) { - ssl->rwstate = SSL_READING; + ssl->s3->rwstate = SSL_READING; return ret; } - // |BIO_read| was bound by |buf->cap - buf->len|, so this cannot - // overflow. - buf->len += (uint16_t)ret; + buf->DidWrite(static_cast<size_t>(ret)); } return 1; @@ -143,7 +148,7 @@ static int tls_read_buffer_extend_to(SSL *ssl, size_t len) { int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { // |ssl_read_buffer_extend_to| implicitly discards any consumed data. - ssl_read_buffer_discard(ssl); + ssl->s3->read_buffer.DiscardConsumed(); if (SSL_is_dtls(ssl)) { static_assert( @@ -154,7 +159,7 @@ int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { len = DTLS1_RT_HEADER_LENGTH + SSL3_RT_MAX_ENCRYPTED_LENGTH; } - if (!ensure_buffer(&ssl->s3->read_buffer, ssl_record_prefix_len(ssl), len)) { + if (!ssl->s3->read_buffer.EnsureCap(ssl_record_prefix_len(ssl), len)) { return -1; } @@ -174,43 +179,20 @@ int ssl_read_buffer_extend_to(SSL *ssl, size_t len) { if (ret <= 0) { // If the buffer was empty originally and remained empty after attempting to // extend it, release the buffer until the next attempt. - ssl_read_buffer_discard(ssl); + ssl->s3->read_buffer.DiscardConsumed(); } return ret; } -void ssl_read_buffer_consume(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->read_buffer; - - consume_buffer(buf, len); - - // The TLS stack never reads beyond the current record, so there will never be - // unconsumed data. If read-ahead is ever reimplemented, - // |ssl_read_buffer_discard| will require a |memcpy| to shift the excess back - // to the front of the buffer, to ensure there is enough space for the next - // record. - assert(SSL_is_dtls(ssl) || len == 0 || buf->len == 0); -} - -void ssl_read_buffer_discard(SSL *ssl) { - if (ssl->s3->read_buffer.len == 0) { - ssl_read_buffer_clear(ssl); - } -} - -void ssl_read_buffer_clear(SSL *ssl) { - clear_buffer(&ssl->s3->read_buffer); -} - int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret, size_t consumed, uint8_t alert) { *out_retry = false; if (ret != ssl_open_record_partial) { - ssl_read_buffer_consume(ssl, consumed); + ssl->s3->read_buffer.Consume(consumed); } if (ret != ssl_open_record_success) { // Nothing was returned to the caller, so discard anything marked consumed. - ssl_read_buffer_discard(ssl); + ssl->s3->read_buffer.DiscardConsumed(); } switch (ret) { case ssl_open_record_success: @@ -243,10 +225,6 @@ int ssl_handle_open_record(SSL *ssl, bool *out_retry, ssl_open_record_t ret, } -int ssl_write_buffer_is_pending(const SSL *ssl) { - return ssl->s3->write_buffer.len > 0; -} - static_assert(SSL3_RT_HEADER_LENGTH * 2 + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD * 2 + SSL3_RT_MAX_PLAIN_LENGTH <= @@ -258,61 +236,37 @@ static_assert(DTLS1_RT_HEADER_LENGTH + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD + 0xffff, "maximum DTLS write buffer is too large"); -int ssl_write_buffer_init(SSL *ssl, uint8_t **out_ptr, size_t max_len) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - - if (buf->buf != NULL) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; - } - - if (!ensure_buffer(buf, ssl_seal_align_prefix_len(ssl), max_len)) { - return 0; - } - *out_ptr = buf->buf + buf->offset; - return 1; -} - -void ssl_write_buffer_set_len(SSL *ssl, size_t len) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - - if (len > buf->cap) { - abort(); - } - buf->len = len; -} - static int tls_write_buffer_flush(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; + SSLBuffer *buf = &ssl->s3->write_buffer; - while (buf->len > 0) { - int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); + while (!buf->empty()) { + int ret = BIO_write(ssl->wbio, buf->data(), buf->size()); if (ret <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; return ret; } - consume_buffer(buf, (size_t)ret); + buf->Consume(static_cast<size_t>(ret)); } - ssl_write_buffer_clear(ssl); + buf->Clear(); return 1; } static int dtls_write_buffer_flush(SSL *ssl) { - SSL3_BUFFER *buf = &ssl->s3->write_buffer; - if (buf->len == 0) { + SSLBuffer *buf = &ssl->s3->write_buffer; + if (buf->empty()) { return 1; } - int ret = BIO_write(ssl->wbio, buf->buf + buf->offset, buf->len); + int ret = BIO_write(ssl->wbio, buf->data(), buf->size()); if (ret <= 0) { - ssl->rwstate = SSL_WRITING; + ssl->s3->rwstate = SSL_WRITING; // If the write failed, drop the write buffer anyway. Datagram transports // can't write half a packet, so the caller is expected to retry from the // top. - ssl_write_buffer_clear(ssl); + buf->Clear(); return ret; } - ssl_write_buffer_clear(ssl); + buf->Clear(); return 1; } @@ -329,8 +283,4 @@ int ssl_write_buffer_flush(SSL *ssl) { } } -void ssl_write_buffer_clear(SSL *ssl) { - clear_buffer(&ssl->s3->write_buffer); -} - } // namespace bssl diff --git a/src/ssl/ssl_lib.cc b/src/ssl/ssl_lib.cc index e3f8a88f..2fc6ffd9 100644 --- a/src/ssl/ssl_lib.cc +++ b/src/ssl/ssl_lib.cc @@ -201,20 +201,19 @@ bool CBBFinishArray(CBB *cbb, Array<uint8_t> *out) { void ssl_reset_error_state(SSL *ssl) { // Functions which use |SSL_get_error| must reset I/O and error state on // entry. - ssl->rwstate = SSL_NOTHING; + ssl->s3->rwstate = SSL_NOTHING; ERR_clear_error(); ERR_clear_system_error(); } void ssl_set_read_error(SSL* ssl) { ssl->s3->read_shutdown = ssl_shutdown_error; - ERR_SAVE_STATE_free(ssl->s3->read_error); - ssl->s3->read_error = ERR_save_state(); + ssl->s3->read_error.reset(ERR_save_state()); } static bool check_read_error(const SSL *ssl) { if (ssl->s3->read_shutdown == ssl_shutdown_error) { - ERR_restore_state(ssl->s3->read_error); + ERR_restore_state(ssl->s3->read_error.get()); return false; } return true; @@ -300,16 +299,16 @@ void ssl_update_cache(SSL_HANDSHAKE *hs, int mode) { // A client may see new sessions on abbreviated handshakes if the server // decides to renew the ticket. Once the handshake is completed, it should be // inserted into the cache. - if (ssl->s3->established_session != ssl->session || + if (ssl->s3->established_session.get() != ssl->session || (!ssl->server && hs->ticket_expected)) { if (use_internal_cache) { - SSL_CTX_add_session(ctx, ssl->s3->established_session); + SSL_CTX_add_session(ctx, ssl->s3->established_session.get()); } if (ctx->new_session_cb != NULL) { - SSL_SESSION_up_ref(ssl->s3->established_session); - if (!ctx->new_session_cb(ssl, ssl->s3->established_session)) { + SSL_SESSION_up_ref(ssl->s3->established_session.get()); + if (!ctx->new_session_cb(ssl, ssl->s3->established_session.get())) { // |new_session_cb|'s return value signals whether it took ownership. - SSL_SESSION_free(ssl->s3->established_session); + SSL_SESSION_free(ssl->s3->established_session.get()); } } } @@ -717,8 +716,6 @@ SSL *SSL_new(SSL_CTX *ctx) { goto err; } - ssl->rwstate = SSL_NOTHING; - CRYPTO_new_ex_data(&ssl->ex_data); ssl->psk_identity_hint = NULL; @@ -763,8 +760,6 @@ void SSL_free(SSL *ssl) { BIO_free_all(ssl->rbio); BIO_free_all(ssl->wbio); - BUF_MEM_free(ssl->init_buf); - // add extra stuff ssl_cipher_preference_list_free(ssl->cipher_list); @@ -860,7 +855,7 @@ int SSL_do_handshake(SSL *ssl) { } // Run the handshake. - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL_HANDSHAKE *hs = ssl->s3->hs.get(); bool early_return = false; int ret = ssl_run_handshake(hs, &early_return); @@ -872,8 +867,7 @@ int SSL_do_handshake(SSL *ssl) { // Destroy the handshake object if the handshake has completely finished. if (!early_return) { - ssl_handshake_free(ssl->s3->hs); - ssl->s3->hs = NULL; + ssl->s3->hs.reset(); } return 1; @@ -937,18 +931,18 @@ static int ssl_do_post_handshake(SSL *ssl, const SSLMessage &msg) { // protocol, namely in HTTPS, just before reading the HTTP response. Require // the record-layer be idle and avoid complexities of sending a handshake // record while an application_data record is being written. - if (ssl_write_buffer_is_pending(ssl) || + if (!ssl->s3->write_buffer.empty() || ssl->s3->write_shutdown != ssl_shutdown_none) { goto no_renegotiation; } // Begin a new handshake. - if (ssl->s3->hs != NULL) { + if (ssl->s3->hs != nullptr) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); return 0; } ssl->s3->hs = ssl_handshake_new(ssl); - if (ssl->s3->hs == NULL) { + if (ssl->s3->hs == nullptr) { return 0; } @@ -1004,7 +998,7 @@ static int ssl_read_impl(SSL *ssl) { uint8_t alert = SSL_AD_DECODE_ERROR; size_t consumed = 0; auto ret = ssl_open_app_data(ssl, &ssl->s3->pending_app_data, &consumed, - &alert, ssl_read_buffer(ssl)); + &alert, ssl->s3->read_buffer.span()); bool retry; int bio_ret = ssl_handle_open_record(ssl, &retry, ret, consumed, alert); if (bio_ret <= 0) { @@ -1029,7 +1023,7 @@ int SSL_read(SSL *ssl, void *buf, int num) { ssl->s3->pending_app_data = ssl->s3->pending_app_data.subspan(static_cast<size_t>(ret)); if (ssl->s3->pending_app_data.empty()) { - ssl_read_buffer_discard(ssl); + ssl->s3->read_buffer.DiscardConsumed(); } return ret; } @@ -1125,7 +1119,7 @@ int SSL_shutdown(SSL *ssl) { // time out because the peer never received our close_notify. Report to // the caller that the channel has fully shut down. if (ssl->s3->read_shutdown == ssl_shutdown_error) { - ERR_restore_state(ssl->s3->read_error); + ERR_restore_state(ssl->s3->read_error.get()); return -1; } ssl->s3->read_shutdown = ssl_shutdown_close_notify; @@ -1190,7 +1184,7 @@ int SSL_early_data_accepted(const SSL *ssl) { } void SSL_reset_early_data_reject(SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL_HANDSHAKE *hs = ssl->s3->hs.get(); if (hs == NULL || hs->wait != ssl_hs_early_data_rejected) { abort(); @@ -1242,7 +1236,7 @@ int SSL_get_error(const SSL *ssl, int ret_code) { return SSL_ERROR_SYSCALL; } - switch (ssl->rwstate) { + switch (ssl->s3->rwstate) { case SSL_PENDING_SESSION: return SSL_ERROR_PENDING_SESSION; @@ -1863,7 +1857,7 @@ const char *SSL_get_servername(const SSL *ssl, const int type) { return ssl->tlsext_hostname; } - return ssl->s3->hostname; + return ssl->s3->hostname.get(); } int SSL_get_servername_type(const SSL *ssl) { @@ -1996,8 +1990,8 @@ found: void SSL_get0_next_proto_negotiated(const SSL *ssl, const uint8_t **out_data, unsigned *out_len) { - *out_data = ssl->s3->next_proto_negotiated; - *out_len = ssl->s3->next_proto_negotiated_len; + *out_data = ssl->s3->next_proto_negotiated.data(); + *out_len = ssl->s3->next_proto_negotiated.size(); } void SSL_CTX_set_next_protos_advertised_cb( @@ -2054,8 +2048,8 @@ void SSL_get0_alpn_selected(const SSL *ssl, const uint8_t **out_data, *out_data = ssl->s3->hs->early_session->early_alpn; *out_len = ssl->s3->hs->early_session->early_alpn_len; } else { - *out_data = ssl->s3->alpn_selected; - *out_len = ssl->s3->alpn_selected_len; + *out_data = ssl->s3->alpn_selected.data(); + *out_len = ssl->s3->alpn_selected.size(); } } @@ -2296,7 +2290,7 @@ void *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx) { return CRYPTO_get_ex_data(&ctx->ex_data, idx); } -int SSL_want(const SSL *ssl) { return ssl->rwstate; } +int SSL_want(const SSL *ssl) { return ssl->s3->rwstate; } void SSL_CTX_set_tmp_rsa_callback(SSL_CTX *ctx, RSA *(*cb)(SSL *ssl, int is_export, @@ -2434,7 +2428,7 @@ int SSL_in_init(const SSL *ssl) { // This returns false once all the handshake state has been finalized, to // allow callbacks and getters based on SSL_in_init to return the correct // values. - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL_HANDSHAKE *hs = ssl->s3->hs.get(); return hs != nullptr && !hs->handshake_finalized; } @@ -2547,7 +2541,7 @@ size_t SSL_get_server_random(const SSL *ssl, uint8_t *out, size_t max_out) { } const SSL_CIPHER *SSL_get_pending_cipher(const SSL *ssl) { - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL_HANDSHAKE *hs = ssl->s3->hs.get(); if (hs == NULL) { return NULL; } @@ -2574,23 +2568,12 @@ int SSL_clear(SSL *ssl) { // In OpenSSL, reusing a client |SSL| with |SSL_clear| causes the previously // established session to be offered the next time around. wpa_supplicant // depends on this behavior, so emulate it. - SSL_SESSION *session = NULL; + UniquePtr<SSL_SESSION> session; if (!ssl->server && ssl->s3->established_session != NULL) { - session = ssl->s3->established_session; - SSL_SESSION_up_ref(session); + session.reset(ssl->s3->established_session.get()); + SSL_SESSION_up_ref(session.get()); } - // TODO(davidben): Some state on |ssl| is reset both in |SSL_new| and - // |SSL_clear| because it is per-connection state rather than configuration - // state. Per-connection state should be on |ssl->s3| and |ssl->d1| so it is - // naturally reset at the right points between |SSL_new|, |SSL_clear|, and - // |ssl3_new|. - - ssl->rwstate = SSL_NOTHING; - - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; - // The ssl->d1->mtu is simultaneously configuration (preserved across // clear) and connection-specific state (gets reset). // @@ -2602,7 +2585,6 @@ int SSL_clear(SSL *ssl) { ssl->method->ssl_free(ssl); if (!ssl->method->ssl_new(ssl)) { - SSL_SESSION_free(session); return 0; } @@ -2610,9 +2592,8 @@ int SSL_clear(SSL *ssl) { ssl->d1->mtu = mtu; } - if (session != NULL) { - SSL_set_session(ssl, session); - SSL_SESSION_free(session); + if (session != nullptr) { + SSL_set_session(ssl, session.get()); } return 1; diff --git a/src/ssl/ssl_session.cc b/src/ssl/ssl_session.cc index ea3c53f5..34e7b317 100644 --- a/src/ssl/ssl_session.cc +++ b/src/ssl/ssl_session.cc @@ -999,9 +999,9 @@ SSL_SESSION *SSL_get_session(const SSL *ssl) { // we return the intermediate session, either |session| (for resumption) or // |new_session| if doing a full handshake. if (!SSL_in_init(ssl)) { - return ssl->s3->established_session; + return ssl->s3->established_session.get(); } - SSL_HANDSHAKE *hs = ssl->s3->hs; + SSL_HANDSHAKE *hs = ssl->s3->hs.get(); if (hs->early_session) { return hs->early_session.get(); } diff --git a/src/ssl/ssl_stat.cc b/src/ssl/ssl_stat.cc index 37e0324f..01153e94 100644 --- a/src/ssl/ssl_stat.cc +++ b/src/ssl/ssl_stat.cc @@ -89,12 +89,12 @@ const char *SSL_state_string_long(const SSL *ssl) { - if (ssl->s3->hs == NULL) { + if (ssl->s3->hs == nullptr) { return "SSL negotiation finished successfully"; } - return ssl->server ? ssl_server_handshake_state(ssl->s3->hs) - : ssl_client_handshake_state(ssl->s3->hs); + return ssl->server ? ssl_server_handshake_state(ssl->s3->hs.get()) + : ssl_client_handshake_state(ssl->s3->hs.get()); } const char *SSL_state_string(const SSL *ssl) { diff --git a/src/ssl/ssl_test.cc b/src/ssl/ssl_test.cc index 5e9cde14..ab50a57e 100644 --- a/src/ssl/ssl_test.cc +++ b/src/ssl/ssl_test.cc @@ -75,10 +75,7 @@ static const VersionParam kAllVersions[] = { {TLS1_VERSION, VersionParam::is_tls, "TLS1"}, {TLS1_1_VERSION, VersionParam::is_tls, "TLS1_1"}, {TLS1_2_VERSION, VersionParam::is_tls, "TLS1_2"}, -// TLS 1.3 requires RSA-PSS, which is disabled for Android system builds. -#if !defined(BORINGSSL_ANDROID_SYSTEM) {TLS1_3_VERSION, VersionParam::is_tls, "TLS1_3"}, -#endif {DTLS1_VERSION, VersionParam::is_dtls, "DTLS1"}, {DTLS1_2_VERSION, VersionParam::is_dtls, "DTLS1_2"}, }; @@ -1974,8 +1971,6 @@ TEST(SSLTest, ClientHello) { 0x01, 0x00, 0x00, 0x1f, 0xff, 0x01, 0x00, 0x01, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18}}, - // This test assumes RSA-PSS, which is disabled for Android system builds. -#if !defined(BORINGSSL_ANDROID_SYSTEM) {TLS1_2_VERSION, {0x16, 0x03, 0x01, 0x00, 0x8e, 0x01, 0x00, 0x00, 0x8a, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -1990,7 +1985,6 @@ TEST(SSLTest, ClientHello) { 0x05, 0x05, 0x01, 0x08, 0x06, 0x06, 0x01, 0x02, 0x01, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x00, 0x0a, 0x00, 0x08, 0x00, 0x06, 0x00, 0x1d, 0x00, 0x17, 0x00, 0x18}}, -#endif // TODO(davidben): Add a change detector for TLS 1.3 once the spec and our // implementation has settled enough that it won't change. }; diff --git a/src/ssl/t1_enc.cc b/src/ssl/t1_enc.cc index e1578bda..1298a105 100644 --- a/src/ssl/t1_enc.cc +++ b/src/ssl/t1_enc.cc @@ -316,68 +316,65 @@ static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret, return 1; } -static int tls1_setup_key_block(SSL_HANDSHAKE *hs) { - SSL *const ssl = hs->ssl; - if (!hs->key_block.empty()) { - return 1; - } - - SSL_SESSION *session = ssl->session; - if (hs->new_session) { - session = hs->new_session.get(); - } - +static bool get_key_block_lengths(const SSL *ssl, size_t *out_mac_secret_len, + size_t *out_key_len, size_t *out_iv_len, + const SSL_CIPHER *cipher) { const EVP_AEAD *aead = NULL; - size_t mac_secret_len, fixed_iv_len; - if (session->cipher == NULL || - !ssl_cipher_get_evp_aead(&aead, &mac_secret_len, &fixed_iv_len, - session->cipher, ssl_protocol_version(ssl), - SSL_is_dtls(ssl))) { + if (!ssl_cipher_get_evp_aead(&aead, out_mac_secret_len, out_iv_len, cipher, + ssl_protocol_version(ssl), SSL_is_dtls(ssl))) { OPENSSL_PUT_ERROR(SSL, SSL_R_CIPHER_OR_HASH_UNAVAILABLE); - return 0; + return false; } - size_t key_len = EVP_AEAD_key_length(aead); - if (mac_secret_len > 0) { + + *out_key_len = EVP_AEAD_key_length(aead); + if (*out_mac_secret_len > 0) { // For "stateful" AEADs (i.e. compatibility with pre-AEAD cipher suites) the // key length reported by |EVP_AEAD_key_length| will include the MAC key // bytes and initial implicit IV. - if (key_len < mac_secret_len + fixed_iv_len) { + if (*out_key_len < *out_mac_secret_len + *out_iv_len) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + return false; } - key_len -= mac_secret_len + fixed_iv_len; + *out_key_len -= *out_mac_secret_len + *out_iv_len; } - assert(mac_secret_len < 256); - assert(key_len < 256); - assert(fixed_iv_len < 256); + return true; +} - ssl->s3->tmp.new_mac_secret_len = (uint8_t)mac_secret_len; - ssl->s3->tmp.new_key_len = (uint8_t)key_len; - ssl->s3->tmp.new_fixed_iv_len = (uint8_t)fixed_iv_len; +static bool setup_key_block(SSL_HANDSHAKE *hs) { + SSL *const ssl = hs->ssl; + if (!hs->key_block.empty()) { + return true; + } + size_t mac_secret_len, key_len, fixed_iv_len; Array<uint8_t> key_block; - if (!key_block.Init(SSL_get_key_block_len(ssl)) || + if (!get_key_block_lengths(ssl, &mac_secret_len, &key_len, &fixed_iv_len, + hs->new_cipher) || + !key_block.Init(2 * (mac_secret_len + key_len + fixed_iv_len)) || !SSL_generate_key_block(ssl, key_block.data(), key_block.size())) { - return 0; + return false; } hs->key_block = std::move(key_block); - return 1; + return true; } int tls1_change_cipher_state(SSL_HANDSHAKE *hs, evp_aead_direction_t direction) { SSL *const ssl = hs->ssl; // Ensure the key block is set up. - if (!tls1_setup_key_block(hs)) { + size_t mac_secret_len, key_len, iv_len; + if (!setup_key_block(hs) || + !get_key_block_lengths(ssl, &mac_secret_len, &key_len, &iv_len, + hs->new_cipher)) { return 0; } - size_t mac_secret_len = ssl->s3->tmp.new_mac_secret_len; - size_t key_len = ssl->s3->tmp.new_key_len; - size_t iv_len = ssl->s3->tmp.new_fixed_iv_len; - assert((mac_secret_len + key_len + iv_len) * 2 == hs->key_block.size()); + if ((mac_secret_len + key_len + iv_len) * 2 != hs->key_block.size()) { + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; + } Span<const uint8_t> key_block = hs->key_block; Span<const uint8_t> mac_secret, key, iv; @@ -448,9 +445,14 @@ int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out, using namespace bssl; size_t SSL_get_key_block_len(const SSL *ssl) { - return 2 * ((size_t)ssl->s3->tmp.new_mac_secret_len + - (size_t)ssl->s3->tmp.new_key_len + - (size_t)ssl->s3->tmp.new_fixed_iv_len); + size_t mac_secret_len, key_len, fixed_iv_len; + if (!get_key_block_lengths(ssl, &mac_secret_len, &key_len, &fixed_iv_len, + SSL_get_current_cipher(ssl))) { + ERR_clear_error(); + return 0; + } + + return 2 * (mac_secret_len + key_len + fixed_iv_len); } int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) { diff --git a/src/ssl/t1_lib.cc b/src/ssl/t1_lib.cc index 5d85cb0c..31b51c9d 100644 --- a/src/ssl/t1_lib.cc +++ b/src/ssl/t1_lib.cc @@ -418,25 +418,15 @@ static const uint16_t kVerifySignatureAlgorithms[] = { // List our preferred algorithms first. SSL_SIGN_ED25519, SSL_SIGN_ECDSA_SECP256R1_SHA256, -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA256, -#endif SSL_SIGN_RSA_PKCS1_SHA256, // Larger hashes are acceptable. SSL_SIGN_ECDSA_SECP384R1_SHA384, -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA384, -#endif SSL_SIGN_RSA_PKCS1_SHA384, - // TODO(davidben): Remove this. -#if defined(BORINGSSL_ANDROID_SYSTEM) - SSL_SIGN_ECDSA_SECP521R1_SHA512, -#endif -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA512, -#endif SSL_SIGN_RSA_PKCS1_SHA512, // For now, SHA-1 is still accepted but least preferable. @@ -454,24 +444,18 @@ static const uint16_t kSignSignatureAlgorithms[] = { // List our preferred algorithms first. SSL_SIGN_ED25519, SSL_SIGN_ECDSA_SECP256R1_SHA256, -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA256, -#endif SSL_SIGN_RSA_PKCS1_SHA256, // If needed, sign larger hashes. // // TODO(davidben): Determine which of these may be pruned. SSL_SIGN_ECDSA_SECP384R1_SHA384, -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA384, -#endif SSL_SIGN_RSA_PKCS1_SHA384, SSL_SIGN_ECDSA_SECP521R1_SHA512, -#if !defined(BORINGSSL_ANDROID_SYSTEM) SSL_SIGN_RSA_PSS_SHA512, -#endif SSL_SIGN_RSA_PKCS1_SHA512, // If the peer supports nothing else, sign with SHA-1. @@ -640,10 +624,12 @@ static bool ext_sni_parse_clienthello(SSL_HANDSHAKE *hs, uint8_t *out_alert, } // Copy the hostname as a string. - if (!CBS_strdup(&host_name, &ssl->s3->hostname)) { + char *raw = nullptr; + if (!CBS_strdup(&host_name, &raw)) { *out_alert = SSL_AD_INTERNAL_ERROR; return false; } + ssl->s3->hostname.reset(raw); hs->should_ack_sni = true; return true; @@ -862,7 +848,7 @@ static bool ext_ems_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, } // Whether EMS is negotiated may not change on renegotiation. - if (ssl->s3->established_session != NULL && + if (ssl->s3->established_session != nullptr && hs->extended_master_secret != !!ssl->s3->established_session->extended_master_secret) { OPENSSL_PUT_ERROR(SSL, SSL_R_RENEGOTIATION_EMS_MISMATCH); @@ -1150,7 +1136,7 @@ static bool ext_npn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, assert(!SSL_is_dtls(ssl)); assert(ssl->ctx->next_proto_select_cb != NULL); - if (ssl->s3->alpn_selected != NULL) { + if (!ssl->s3->alpn_selected.empty()) { // NPN and ALPN may not be negotiated in the same connection. *out_alert = SSL_AD_ILLEGAL_PARAMETER; OPENSSL_PUT_ERROR(SSL, SSL_R_NEGOTIATED_BOTH_NPN_AND_ALPN); @@ -1172,22 +1158,14 @@ static bool ext_npn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, uint8_t selected_len; if (ssl->ctx->next_proto_select_cb( ssl, &selected, &selected_len, orig_contents, orig_len, - ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return false; - } - - OPENSSL_free(ssl->s3->next_proto_negotiated); - ssl->s3->next_proto_negotiated = - (uint8_t *)BUF_memdup(selected, selected_len); - if (ssl->s3->next_proto_negotiated == NULL) { + ssl->ctx->next_proto_select_cb_arg) != SSL_TLSEXT_ERR_OK || + !ssl->s3->next_proto_negotiated.CopyFrom( + MakeConstSpan(selected, selected_len))) { *out_alert = SSL_AD_INTERNAL_ERROR; return false; } - ssl->s3->next_proto_negotiated_len = selected_len; hs->next_proto_neg_seen = true; - return true; } @@ -1388,37 +1366,13 @@ static bool ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, return false; } - if (!ssl->ctx->allow_unknown_alpn_protos) { - // Check that the protocol name is one of the ones we advertised. - bool protocol_ok = false; - CBS client_protocol_name_list, client_protocol_name; - CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list, - ssl->alpn_client_proto_list_len); - while (CBS_len(&client_protocol_name_list) > 0) { - if (!CBS_get_u8_length_prefixed(&client_protocol_name_list, - &client_protocol_name)) { - *out_alert = SSL_AD_INTERNAL_ERROR; - return false; - } - - if (CBS_len(&client_protocol_name) == CBS_len(&protocol_name) && - OPENSSL_memcmp(CBS_data(&client_protocol_name), - CBS_data(&protocol_name), - CBS_len(&protocol_name)) == 0) { - protocol_ok = true; - break; - } - } - - if (!protocol_ok) { - OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL); - *out_alert = SSL_AD_ILLEGAL_PARAMETER; - return false; - } + if (!ssl_is_alpn_protocol_allowed(ssl, protocol_name)) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_ALPN_PROTOCOL); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return false; } - if (!CBS_stow(&protocol_name, &ssl->s3->alpn_selected, - &ssl->s3->alpn_selected_len)) { + if (!ssl->s3->alpn_selected.CopyFrom(protocol_name)) { *out_alert = SSL_AD_INTERNAL_ERROR; return false; } @@ -1426,6 +1380,34 @@ static bool ext_alpn_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, return true; } +bool ssl_is_alpn_protocol_allowed(const SSL *ssl, + Span<const uint8_t> protocol) { + if (ssl->alpn_client_proto_list == nullptr) { + return false; + } + + if (ssl->ctx->allow_unknown_alpn_protos) { + return true; + } + + // Check that the protocol name is one of the ones we advertised. + CBS client_protocol_name_list, client_protocol_name; + CBS_init(&client_protocol_name_list, ssl->alpn_client_proto_list, + ssl->alpn_client_proto_list_len); + while (CBS_len(&client_protocol_name_list) > 0) { + if (!CBS_get_u8_length_prefixed(&client_protocol_name_list, + &client_protocol_name)) { + return false; + } + + if (client_protocol_name == protocol) { + return true; + } + } + + return false; +} + bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, const SSL_CLIENT_HELLO *client_hello) { SSL *const ssl = hs->ssl; @@ -1470,13 +1452,11 @@ bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, ssl, &selected, &selected_len, CBS_data(&protocol_name_list), CBS_len(&protocol_name_list), ssl->ctx->alpn_select_cb_arg) == SSL_TLSEXT_ERR_OK) { - OPENSSL_free(ssl->s3->alpn_selected); - ssl->s3->alpn_selected = (uint8_t *)BUF_memdup(selected, selected_len); - if (ssl->s3->alpn_selected == NULL) { + if (!ssl->s3->alpn_selected.CopyFrom( + MakeConstSpan(selected, selected_len))) { *out_alert = SSL_AD_INTERNAL_ERROR; return false; } - ssl->s3->alpn_selected_len = selected_len; } return true; @@ -1484,7 +1464,7 @@ bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, static bool ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { SSL *const ssl = hs->ssl; - if (ssl->s3->alpn_selected == NULL) { + if (ssl->s3->alpn_selected.empty()) { return true; } @@ -1493,8 +1473,8 @@ static bool ext_alpn_add_serverhello(SSL_HANDSHAKE *hs, CBB *out) { !CBB_add_u16_length_prefixed(out, &contents) || !CBB_add_u16_length_prefixed(&contents, &proto_list) || !CBB_add_u8_length_prefixed(&proto_list, &proto) || - !CBB_add_bytes(&proto, ssl->s3->alpn_selected, - ssl->s3->alpn_selected_len) || + !CBB_add_bytes(&proto, ssl->s3->alpn_selected.data(), + ssl->s3->alpn_selected.size()) || !CBB_flush(out)) { return false; } @@ -1998,11 +1978,19 @@ static bool ext_psk_key_exchange_modes_parse_clienthello(SSL_HANDSHAKE *hs, static bool ext_early_data_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { SSL *const ssl = hs->ssl; - if (ssl->session == NULL || + if (!ssl->cert->enable_early_data || + // Session must be 0-RTT capable. + ssl->session == NULL || ssl_session_protocol_version(ssl->session) < TLS1_3_VERSION || ssl->session->ticket_max_early_data == 0 || + // The second ClientHello never offers early data. hs->received_hello_retry_request || - !ssl->cert->enable_early_data) { + // In case ALPN preferences changed since this session was established, + // avoid reporting a confusing value in |SSL_get0_alpn_selected|. + (ssl->session->early_alpn_len != 0 && + !ssl_is_alpn_protocol_allowed( + ssl, MakeConstSpan(ssl->session->early_alpn, + ssl->session->early_alpn_len)))) { return true; } diff --git a/src/ssl/test/bssl_shim.cc b/src/ssl/test/bssl_shim.cc index 1d7b996a..d439cb55 100644 --- a/src/ssl/test/bssl_shim.cc +++ b/src/ssl/test/bssl_shim.cc @@ -1101,7 +1101,6 @@ static void MessageCallback(int is_write, int version, int content_type, // Connect returns a new socket connected to localhost on |port| or -1 on // error. static int Connect(uint16_t port) { - time_t start_time = time(nullptr); for (int af : { AF_INET6, AF_INET }) { int sock = socket(af, SOCK_STREAM, 0); if (sock == -1) { @@ -1148,11 +1147,6 @@ static int Connect(uint16_t port) { } PrintSocketError("connect"); - // TODO(davidben): Remove this logging when https://crbug.com/boringssl/199 is - // resolved. - fprintf(stderr, "start_time = %lld, end_time = %lld\n", - static_cast<long long>(start_time), - static_cast<long long>(time(nullptr))); return -1; } @@ -2201,6 +2195,12 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, SSL *ssl, return false; } + if (is_resume && !is_retry && !config->is_server && + config->expect_no_offer_early_data && SSL_in_early_data(ssl)) { + fprintf(stderr, "Client unexpectedly offered early data.\n"); + return false; + } + if (config->handshake_twice) { do { ret = SSL_do_handshake(ssl); diff --git a/src/ssl/test/runner/conn.go b/src/ssl/test/runner/conn.go index 0edbe5c9..71b52f2c 100644 --- a/src/ssl/test/runner/conn.go +++ b/src/ssl/test/runner/conn.go @@ -244,14 +244,6 @@ func (hc *halfConn) resetCipher() { hc.incEpoch() } -func (hc *halfConn) doKeyUpdate(c *Conn, isOutgoing bool) { - side := serverWrite - if c.isClient == isOutgoing { - side = clientWrite - } - hc.useTrafficSecret(hc.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), hc.trafficSecret), side) -} - // incSeq increments the sequence number. func (hc *halfConn) incSeq(isOutgoing bool) { limit := 0 @@ -737,6 +729,26 @@ func (hc *halfConn) splitBlock(b *block, n int) (*block, *block) { return b, bb } +func (c *Conn) useInTrafficSecret(version uint16, suite *cipherSuite, secret []byte) error { + if c.hand.Len() != 0 { + return c.in.setErrorLocked(errors.New("tls: buffered handshake messages on cipher change")) + } + side := serverWrite + if !c.isClient { + side = clientWrite + } + c.in.useTrafficSecret(version, suite, secret, side) + return nil +} + +func (c *Conn) useOutTrafficSecret(version uint16, suite *cipherSuite, secret []byte) { + side := serverWrite + if c.isClient { + side = clientWrite + } + c.out.useTrafficSecret(version, suite, secret, side) +} + func (c *Conn) doReadRecord(want recordType) (recordType, *block, error) { RestartReadRecord: if c.isDTLS { @@ -940,8 +952,11 @@ Again: break } if !isResumptionExperiment(c.wireVersion) { - err := c.in.changeCipherSpec(c.config) - if err != nil { + if c.hand.Len() != 0 { + c.in.setErrorLocked(errors.New("tls: buffered handshake messages on cipher change")) + break + } + if err := c.in.changeCipherSpec(c.config); err != nil { c.in.setErrorLocked(c.sendAlert(err.(alert))) } } @@ -1522,7 +1537,9 @@ func (c *Conn) handlePostHandshakeMessage() error { if c.config.Bugs.RejectUnsolicitedKeyUpdate { return errors.New("tls: unexpected KeyUpdate message") } - c.in.doKeyUpdate(c, false) + if err := c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.in.trafficSecret)); err != nil { + return err + } if keyUpdate.keyUpdateRequest == keyUpdateRequested { c.keyUpdateRequested = true } @@ -1554,8 +1571,7 @@ func (c *Conn) ReadKeyUpdateACK() error { return errors.New("tls: received invalid KeyUpdate message") } - c.in.doKeyUpdate(c, false) - return nil + return c.useInTrafficSecret(c.in.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.in.trafficSecret)) } func (c *Conn) Renegotiate() error { @@ -1885,7 +1901,7 @@ func (c *Conn) sendKeyUpdateLocked(keyUpdateRequest byte) error { if err := c.flushHandshake(); err != nil { return err } - c.out.doKeyUpdate(c, true) + c.useOutTrafficSecret(c.out.wireVersion, c.cipherSuite, updateTrafficSecret(c.cipherSuite.hash(), c.out.trafficSecret)) return nil } diff --git a/src/ssl/test/runner/handshake_client.go b/src/ssl/test/runner/handshake_client.go index ef6a4644..30105a5b 100644 --- a/src/ssl/test/runner/handshake_client.go +++ b/src/ssl/test/runner/handshake_client.go @@ -411,7 +411,7 @@ NextCipherSuite: finishedHash.addEntropy(session.masterSecret) finishedHash.Write(helloBytes) earlyTrafficSecret := finishedHash.deriveSecret(earlyTrafficLabel) - c.out.useTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret, clientWrite) + c.useOutTrafficSecret(session.wireVersion, pskCipherSuite, earlyTrafficSecret) for _, earlyData := range c.config.Bugs.SendEarlyData { if _, err := c.writeRecord(recordTypeApplicationData, earlyData); err != nil { return err @@ -754,7 +754,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // traffic key. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.in.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) + if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret); err != nil { + return err + } msg, err := c.readHandshake() if err != nil { @@ -888,7 +890,9 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { // Switch to application data keys on read. In particular, any alerts // from the client certificate are read over these keys. - c.in.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) + if err := c.useInTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret); err != nil { + return err + } // If we're expecting 0.5-RTT messages from the server, read them // now. @@ -934,7 +938,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) } - c.out.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) + c.useOutTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret) if certReq != nil && !c.config.Bugs.SkipClientCertificate { certMsg := &certificateMsg{ @@ -1020,7 +1024,7 @@ func (hs *clientHandshakeState) doTLS13Handshake() error { c.flushHandshake() // Switch to application data keys. - c.out.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) + c.useOutTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret) c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) return nil diff --git a/src/ssl/test/runner/handshake_server.go b/src/ssl/test/runner/handshake_server.go index 0ffb72cc..f50772e3 100644 --- a/src/ssl/test/runner/handshake_server.go +++ b/src/ssl/test/runner/handshake_server.go @@ -648,8 +648,7 @@ ResendHelloRetryRequest: // AcceptAnyBinder is set. See https://crbug.com/115. if hs.sessionState != nil && !config.Bugs.AcceptAnySession { binderToVerify := newClientHello.pskBinders[pskIndex] - err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...)) - if err != nil { + if err := verifyPSKBinder(newClientHello, hs.sessionState, binderToVerify, append(oldClientHelloBytes, helloRetryRequest.marshal()...)); err != nil { return err } } @@ -664,7 +663,9 @@ ResendHelloRetryRequest: } if encryptedExtensions.extensions.hasEarlyData { earlyTrafficSecret := hs.finishedHash.deriveSecret(earlyTrafficLabel) - c.in.useTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret, clientWrite) + if err := c.useInTrafficSecret(c.wireVersion, hs.suite, earlyTrafficSecret); err != nil { + return err + } for _, expectedMsg := range config.Bugs.ExpectEarlyData { if err := c.readRecord(recordTypeApplicationData); err != nil { @@ -761,7 +762,7 @@ ResendHelloRetryRequest: // Switch to handshake traffic keys. serverHandshakeTrafficSecret := hs.finishedHash.deriveSecret(serverHandshakeTrafficLabel) - c.out.useTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret, serverWrite) + c.useOutTrafficSecret(c.wireVersion, hs.suite, serverHandshakeTrafficSecret) // Derive handshake traffic read key, but don't switch yet. clientHandshakeTrafficSecret := hs.finishedHash.deriveSecret(clientHandshakeTrafficLabel) @@ -902,7 +903,7 @@ ResendHelloRetryRequest: // Switch to application data keys on write. In particular, any alerts // from the client certificate are sent over these keys. - c.out.useTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret, serverWrite) + c.useOutTrafficSecret(c.wireVersion, hs.suite, serverTrafficSecret) // Send 0.5-RTT messages. for _, halfRTTMsg := range config.Bugs.SendHalfRTTData { @@ -928,7 +929,9 @@ ResendHelloRetryRequest: } // Switch input stream to handshake traffic keys. - c.in.useTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret, clientWrite) + if err := c.useInTrafficSecret(c.wireVersion, hs.suite, clientHandshakeTrafficSecret); err != nil { + return err + } // If we requested a client certificate, then the client must send a // certificate message, even if it's empty. @@ -1032,7 +1035,9 @@ ResendHelloRetryRequest: hs.writeClientHash(clientFinished.marshal()) // Switch to application data keys on read. - c.in.useTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret, clientWrite) + if err := c.useInTrafficSecret(c.wireVersion, hs.suite, clientTrafficSecret); err != nil { + return err + } c.cipherSuite = hs.suite c.resumptionSecret = hs.finishedHash.deriveSecret(resumptionLabel) diff --git a/src/ssl/test/runner/runner.go b/src/ssl/test/runner/runner.go index e666404f..d34eaa68 100644 --- a/src/ssl/test/runner/runner.go +++ b/src/ssl/test/runner/runner.go @@ -901,28 +901,20 @@ var ( // exit first. func acceptOrWait(listener *net.TCPListener, waitChan chan error) (net.Conn, error) { type connOrError struct { - conn net.Conn - err error - startTime, endTime time.Time + conn net.Conn + err error } connChan := make(chan connOrError, 1) go func() { - startTime := time.Now() if !*useGDB { listener.SetDeadline(time.Now().Add(*idleTimeout)) } conn, err := listener.Accept() - endTime := time.Now() - connChan <- connOrError{conn, err, startTime, endTime} + connChan <- connOrError{conn, err} close(connChan) }() select { case result := <-connChan: - if result.err != nil { - // TODO(davidben): Remove this logging when - // https://crbug.com/boringssl/199 is resolved. - fmt.Fprintf(os.Stderr, "acceptOrWait failed, startTime=%v, endTime=%v\n", result.startTime, result.endTime) - } return result.conn, result.err case childErr := <-waitChan: waitChan <- childErr @@ -2761,11 +2753,12 @@ read alert 1 0 }, }, { - // Test the server so there is a large certificate as - // well as application data. + // Test the TLS 1.2 server so there is a large + // unencrypted certificate as well as application data. testType: serverTest, - name: "MaxSendFragment", + name: "MaxSendFragment-TLS12", config: Config{ + MaxVersion: VersionTLS12, Bugs: ProtocolBugs{ MaxReceivePlaintext: 512, }, @@ -2777,11 +2770,50 @@ read alert 1 0 }, }, { - // Test the server so there is a large certificate as - // well as application data. + // Test the TLS 1.2 server so there is a large + // unencrypted certificate as well as application data. testType: serverTest, - name: "MaxSendFragment-TooLarge", + name: "MaxSendFragment-TLS12-TooLarge", config: Config{ + MaxVersion: VersionTLS12, + Bugs: ProtocolBugs{ + // Ensure that some of the records are + // 512. + MaxReceivePlaintext: 511, + }, + }, + messageLen: 1024, + flags: []string{ + "-max-send-fragment", "512", + "-read-size", "1024", + }, + shouldFail: true, + expectedLocalError: "local error: record overflow", + }, + { + // Test the TLS 1.3 server so there is a large encrypted + // certificate as well as application data. + testType: serverTest, + name: "MaxSendFragment-TLS13", + config: Config{ + MaxVersion: VersionTLS13, + Bugs: ProtocolBugs{ + MaxReceivePlaintext: 512, + }, + }, + messageLen: 1024, + flags: []string{ + "-max-send-fragment", "512", + "-read-size", "1024", + }, + }, + { + // Test the TLS 1.3 server so there is a large encrypted + // certificate as well as application data. + testType: serverTest, + name: "MaxSendFragment-TLS13-TooLarge", + config: Config{ + MaxVersion: VersionTLS13, Bugs: ProtocolBugs{ // Ensure that some of the records are // 512. @@ -11726,6 +11758,28 @@ func addTLS13HandshakeTests() { expectedError: ":ALPN_MISMATCH_ON_EARLY_DATA:", }) + // Test that the client does not offer early data if it is incompatible + // with ALPN preferences. + testCases = append(testCases, testCase{ + testType: clientTest, + name: "TLS13-EarlyData-ALPNPreferenceChanged", + config: Config{ + MaxVersion: VersionTLS13, + MaxEarlyDataSize: 16384, + NextProtos: []string{"foo", "bar"}, + }, + resumeSession: true, + flags: []string{ + "-enable-early-data", + "-expect-early-data-info", + "-expect-no-offer-early-data", + "-on-initial-advertise-alpn", "\x03foo", + "-on-resume-advertise-alpn", "\x03bar", + "-on-initial-expect-alpn", "foo", + "-on-resume-expect-alpn", "bar", + }, + }) + // Test that the server correctly rejects 0-RTT when the previous // session did not allow early data on resumption. testCases = append(testCases, testCase{ diff --git a/src/ssl/test/test_config.cc b/src/ssl/test/test_config.cc index 6df8d2ac..33548515 100644 --- a/src/ssl/test/test_config.cc +++ b/src/ssl/test/test_config.cc @@ -121,6 +121,7 @@ const Flag<bool> kBoolFlags[] = { { "-expect-no-session-id", &TestConfig::expect_no_session_id }, { "-expect-accept-early-data", &TestConfig::expect_accept_early_data }, { "-expect-reject-early-data", &TestConfig::expect_reject_early_data }, + { "-expect-no-offer-early-data", &TestConfig::expect_no_offer_early_data }, { "-no-op-extra-handshake", &TestConfig::no_op_extra_handshake }, { "-handshake-twice", &TestConfig::handshake_twice }, { "-allow-unknown-alpn-protos", &TestConfig::allow_unknown_alpn_protos }, diff --git a/src/ssl/test/test_config.h b/src/ssl/test/test_config.h index 9af64bcb..b96d9e52 100644 --- a/src/ssl/test/test_config.h +++ b/src/ssl/test/test_config.h @@ -90,6 +90,7 @@ struct TestConfig { bool expect_early_data_info = false; bool expect_accept_early_data = false; bool expect_reject_early_data = false; + bool expect_no_offer_early_data = false; bool use_ticket_callback = false; bool renew_ticket = false; bool enable_early_data = false; diff --git a/src/ssl/tls13_client.cc b/src/ssl/tls13_client.cc index a03c5815..b6307eeb 100644 --- a/src/ssl/tls13_client.cc +++ b/src/ssl/tls13_client.cc @@ -390,21 +390,21 @@ static enum ssl_hs_wait_t do_read_encrypted_extensions(SSL_HANDSHAKE *hs) { } // Store the negotiated ALPN in the session. - if (ssl->s3->alpn_selected != NULL) { + if (!ssl->s3->alpn_selected.empty()) { hs->new_session->early_alpn = (uint8_t *)BUF_memdup( - ssl->s3->alpn_selected, ssl->s3->alpn_selected_len); + ssl->s3->alpn_selected.data(), ssl->s3->alpn_selected.size()); if (hs->new_session->early_alpn == NULL) { ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } - hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len; + hs->new_session->early_alpn_len = ssl->s3->alpn_selected.size(); } if (ssl->early_data_accepted) { if (hs->early_session->cipher != hs->new_session->cipher || - hs->early_session->early_alpn_len != ssl->s3->alpn_selected_len || - OPENSSL_memcmp(hs->early_session->early_alpn, ssl->s3->alpn_selected, - ssl->s3->alpn_selected_len) != 0) { + MakeConstSpan(hs->early_session->early_alpn, + hs->early_session->early_alpn_len) != + ssl->s3->alpn_selected) { OPENSSL_PUT_ERROR(SSL, SSL_R_ALPN_MISMATCH_ON_EARLY_DATA); return ssl_hs_error; } @@ -781,8 +781,8 @@ int tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg) { return 1; } - UniquePtr<SSL_SESSION> session(SSL_SESSION_dup(ssl->s3->established_session, - SSL_SESSION_INCLUDE_NONAUTH)); + UniquePtr<SSL_SESSION> session = SSL_SESSION_dup( + ssl->s3->established_session.get(), SSL_SESSION_INCLUDE_NONAUTH); if (!session) { return 0; } diff --git a/src/ssl/tls13_server.cc b/src/ssl/tls13_server.cc index 09437a5f..89c9d462 100644 --- a/src/ssl/tls13_server.cc +++ b/src/ssl/tls13_server.cc @@ -371,8 +371,8 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { hs->new_session = SSL_SESSION_dup(session.get(), SSL_SESSION_DUP_AUTH_ONLY); - if (// Early data must be acceptable for this ticket. - ssl->cert->enable_early_data && + if (ssl->cert->enable_early_data && + // Early data must be acceptable for this ticket. session->ticket_max_early_data != 0 && // The client must have offered early data. hs->early_data_offered && @@ -381,9 +381,8 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { // Custom extensions is incompatible with 0-RTT. hs->custom_extensions.received == 0 && // The negotiated ALPN must match the one in the ticket. - ssl->s3->alpn_selected_len == session->early_alpn_len && - OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn, - ssl->s3->alpn_selected_len) == 0) { + ssl->s3->alpn_selected == + MakeConstSpan(session->early_alpn, session->early_alpn_len)) { ssl->early_data_accepted = true; } @@ -412,14 +411,14 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) { hs->new_session->cipher = hs->new_cipher; // Store the initial negotiated ALPN in the session. - if (ssl->s3->alpn_selected != NULL) { + if (!ssl->s3->alpn_selected.empty()) { hs->new_session->early_alpn = (uint8_t *)BUF_memdup( - ssl->s3->alpn_selected, ssl->s3->alpn_selected_len); + ssl->s3->alpn_selected.data(), ssl->s3->alpn_selected.size()); if (hs->new_session->early_alpn == NULL) { ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); return ssl_hs_error; } - hs->new_session->early_alpn_len = ssl->s3->alpn_selected_len; + hs->new_session->early_alpn_len = ssl->s3->alpn_selected.size(); } if (ssl->ctx->dos_protection_cb != NULL && diff --git a/src/ssl/tls_method.cc b/src/ssl/tls_method.cc index 94b9e205..c5b01782 100644 --- a/src/ssl/tls_method.cc +++ b/src/ssl/tls_method.cc @@ -73,14 +73,13 @@ static void ssl3_on_handshake_complete(SSL *ssl) { // The handshake should have released its final message. assert(!ssl->s3->has_message); - // During the handshake, |init_buf| is retained. Release if it there is no + // During the handshake, |hs_buf| is retained. Release if it there is no // excess in it. There may be excess left if there server sent Finished and // HelloRequest in the same record. // // TODO(davidben): SChannel does not support this. Reject this case. - if (ssl->init_buf != NULL && ssl->init_buf->length == 0) { - BUF_MEM_free(ssl->init_buf); - ssl->init_buf = NULL; + if (ssl->s3->hs_buf && ssl->s3->hs_buf->length == 0) { + ssl->s3->hs_buf.reset(); } } @@ -93,17 +92,13 @@ static bool ssl3_set_read_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { } OPENSSL_memset(ssl->s3->read_sequence, 0, sizeof(ssl->s3->read_sequence)); - - Delete(ssl->s3->aead_read_ctx); - ssl->s3->aead_read_ctx = aead_ctx.release(); + ssl->s3->aead_read_ctx = std::move(aead_ctx); return true; } static bool ssl3_set_write_state(SSL *ssl, UniquePtr<SSLAEADContext> aead_ctx) { OPENSSL_memset(ssl->s3->write_sequence, 0, sizeof(ssl->s3->write_sequence)); - - Delete(ssl->s3->aead_write_ctx); - ssl->s3->aead_write_ctx = aead_ctx.release(); + ssl->s3->aead_write_ctx = std::move(aead_ctx); return true; } diff --git a/src/util/BUILD.toplevel b/src/util/BUILD.toplevel index af7bd303..6e569ec8 100644 --- a/src/util/BUILD.toplevel +++ b/src/util/BUILD.toplevel @@ -46,6 +46,11 @@ config_setting( values = {"cpu": "x64_windows"}, ) +config_setting( + name = "android", + values = {"crosstool_top": "//external:android/crosstool"} +) + posix_copts = [ # Assembler option --noexecstack adds .note.GNU-stack to each object to # ensure that binaries can be built with non-executable stack. @@ -120,6 +125,9 @@ cc_library( includes = ["src/include"], linkopts = select({ ":mac_x86_64": [], + # Android supports pthreads, but does not provide a libpthread + # to link against. + ":android": [], "//conditions:default": ["-lpthread"], }), visibility = ["//visibility:public"], |