diff --git a/.github/workflows/actions-ci.yml b/.github/workflows/actions-ci.yml index 311d54b17a..bdaba2cf42 100644 --- a/.github/workflows/actions-ci.yml +++ b/.github/workflows/actions-ci.yml @@ -281,18 +281,23 @@ jobs: - name: Build SSL run: cmake --build ./build --target ssl - clang-18-pedantic: + clang-19-pedantic: if: github.repository_owner == 'aws' needs: [ sanity-test-run ] runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 + - name: Install clang-19 + run: | + wget https://apt.llvm.org/llvm.sh + chmod u+x llvm.sh + sudo ./llvm.sh 19 - name: Setup CMake uses: threeal/cmake-action@v1.3.0 with: generator: Ninja - c-compiler: clang-18 - cxx-compiler: clang++-18 + c-compiler: clang-19 + cxx-compiler: clang++-19 options: CMAKE_BUILD_TYPE=Release CMAKE_C_FLAGS=-pedantic CMAKE_CXX_FLAGS=-pedantic - name: Build Crypto run: cmake --build ./build --target crypto @@ -392,6 +397,38 @@ jobs: - name: Run tests run: cmake --build ./build --target run_tests + clang-19-sanity: + if: github.repository_owner == 'aws' + needs: [ sanity-test-run ] + strategy: + fail-fast: false + matrix: + fips: + - "0" + - "1" + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 + with: + go-version: '>=1.18' + - name: Install clang-19 + run: | + wget https://apt.llvm.org/llvm.sh + chmod u+x llvm.sh + sudo ./llvm.sh 19 + - name: Setup CMake + uses: threeal/cmake-action@v1.3.0 + with: + generator: Ninja + c-compiler: clang-19 + cxx-compiler: clang++-19 + options: FIPS=${{ matrix.fips }} CMAKE_BUILD_TYPE=Release + - name: Build Project + run: cmake --build ./build --target all + - name: Run tests + run: cmake --build ./build --target run_tests + OpenBSD-x86-64: needs: [sanity-test-run] runs-on: ubuntu-latest diff --git a/crypto/fipsmodule/ec/ec_nistp.c b/crypto/fipsmodule/ec/ec_nistp.c index f3025ee3bd..e2415fd0c5 100644 --- a/crypto/fipsmodule/ec/ec_nistp.c +++ b/crypto/fipsmodule/ec/ec_nistp.c @@ -19,7 +19,7 @@ // | 2. | x | x | x* | // | 3. | x | x | | // | 4. | x | x | x* | -// | 5. | | | | +// | 5. | x | x | | // * For P-256, only the Fiat-crypto implementation in p256.c is replaced. #include "ec_nistp.h" @@ -317,9 +317,13 @@ static void scalar_rwnaf(int16_t *out, size_t window_size, #define SCALAR_MUL_TABLE_MAX_NUM_FELEM_LIMBS \ (SCALAR_MUL_TABLE_NUM_POINTS * 3 * FELEM_MAX_NUM_OF_LIMBS) +// The maximum number of bits for a scalar. +#define SCALAR_MUL_MAX_SCALAR_BITS (521) + // Maximum number of windows (digits) for a scalar encoding which is // determined by the maximum scalar bit size -- 521 bits in our case. -#define SCALAR_MUL_MAX_NUM_WINDOWS DIV_AND_CEIL(521, SCALAR_MUL_WINDOW_SIZE) +#define SCALAR_MUL_MAX_NUM_WINDOWS \ + DIV_AND_CEIL(SCALAR_MUL_MAX_SCALAR_BITS, SCALAR_MUL_WINDOW_SIZE) // Generate table of multiples of the input point P = (x_in, y_in, z_in): // table <-- [2i + 1]P for i in [0, SCALAR_MUL_TABLE_NUM_POINTS - 1]. @@ -636,3 +640,132 @@ void ec_nistp_scalar_mul_base(const ec_nistp_meth *ctx, cmovznz(y_out, ctx->felem_num_limbs, t, y_tmp, y_res); cmovznz(z_out, ctx->felem_num_limbs, t, z_tmp, z_res); } + +// Computes [g_scalar]G + [p_scalar]P, where G is the base point of the curve +// curve, and P is the given point (x_p, y_p, z_p). +// +// Both scalar products are computed by the same "textbook" wNAF method, +// with w = 5 for g_scalar and w = 5 for p_scalar. +// For the base point G product we use the first sub-table of the precomputed +// table, while for P we generate the table on-the-fly. The tables hold the +// first 16 odd multiples of G or P: +// g_pre_comp = {[1]G, [3]G, ..., [31]G}, +// p_pre_comp = {[1]P, [3]P, ..., [31]P}. +// Computing the negation of a point P = (x, y) is relatively easy: +// -P = (x, -y). +// So we may assume that we also have the negatives of the points in the tables. +// +// The scalars are recoded by the textbook wNAF method to digits, where a digit +// is either a zero or an odd integer in [-31, 31]. The method guarantees that +// each non-zero digit is followed by at least four zeroes. +// +// The result [g_scalar]G + [p_scalar]P is computed by the following algorithm: +// 1. Initialize the accumulator with the point-at-infinity. +// 2. For i starting from 521 down to 0: +// 3. Double the accumulator (doubling can be skipped while the +// accumulator is equal to the point-at-infinity). +// 4. Read from |p_pre_comp| the point corresponding to the i-th digit of +// p_scalar, negate it if the digit is negative, and add it to the +// accumulator. +// 5. Read from |g_pre_comp| the point corresponding to the i-th digit of +// g_scalar, negate it if the digit is negative, and add it to the +// accumulator. +// Note: this function is NOT constant-time. +void ec_nistp_scalar_mul_public(const ec_nistp_meth *ctx, + ec_nistp_felem_limb *x_out, + ec_nistp_felem_limb *y_out, + ec_nistp_felem_limb *z_out, + const EC_SCALAR *g_scalar, + const ec_nistp_felem_limb *x_p, + const ec_nistp_felem_limb *y_p, + const ec_nistp_felem_limb *z_p, + const EC_SCALAR *p_scalar) { + + const size_t felem_num_bytes = ctx->felem_num_limbs * sizeof(ec_nistp_felem_limb); + + // Table of multiples of P. + ec_nistp_felem_limb p_table[SCALAR_MUL_TABLE_MAX_NUM_FELEM_LIMBS]; + generate_table(ctx, p_table, x_p, y_p, z_p); + const size_t p_point_num_limbs = 3 * ctx->felem_num_limbs; // Projective. + + // Table of multiples of G. + const ec_nistp_felem_limb *g_table = ctx->scalar_mul_base_table; + const size_t g_point_num_limbs = 2 * ctx->felem_num_limbs; // Affine. + + // Recode the scalars. + int8_t p_wnaf[SCALAR_MUL_MAX_SCALAR_BITS + 1] = {0}; + int8_t g_wnaf[SCALAR_MUL_MAX_SCALAR_BITS + 1] = {0}; + ec_compute_wNAF(p_wnaf, p_scalar, ctx->felem_num_bits, SCALAR_MUL_WINDOW_SIZE); + ec_compute_wNAF(g_wnaf, g_scalar, ctx->felem_num_bits, SCALAR_MUL_WINDOW_SIZE); + + // In the beginning res is set to point-at-infinity, so we set the flag. + int16_t res_is_inf = 1; + int16_t d, is_neg, idx; + ec_nistp_felem ftmp; + + for (int i = ctx->felem_num_bits; i >= 0; i--) { + + // If |res| is point-at-infinity there is no point in doubling so skip it. + if (!res_is_inf) { + ctx->point_dbl(x_out, y_out, z_out, x_out, y_out, z_out); + } + + // Process the p_scalar digit. + d = p_wnaf[i]; + if (d != 0) { + is_neg = d < 0 ? 1 : 0; + idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; + + if (res_is_inf) { + // If |res| is point-at-infinity there is no need to add the new point, + // we can simply copy it. + const size_t table_idx = idx * p_point_num_limbs; + OPENSSL_memcpy(x_out, &p_table[table_idx], felem_num_bytes); + OPENSSL_memcpy(y_out, &p_table[table_idx + ctx->felem_num_limbs], felem_num_bytes); + OPENSSL_memcpy(z_out, &p_table[table_idx + ctx->felem_num_limbs * 2], felem_num_bytes); + res_is_inf = 0; + } else { + // Otherwise, add to the accumulator either the point at position idx + // in the table or its negation. + const ec_nistp_felem_limb *y_tmp; + y_tmp = &p_table[idx * p_point_num_limbs + ctx->felem_num_limbs]; + if (is_neg) { + ctx->felem_neg(ftmp, y_tmp); + y_tmp = ftmp; + } + ctx->point_add(x_out, y_out, z_out, x_out, y_out, z_out, 0, + &p_table[idx * p_point_num_limbs], + y_tmp, + &p_table[idx * p_point_num_limbs + ctx->felem_num_limbs * 2]); + } + } + + /* // Process the g_scalar digit. */ + d = g_wnaf[i]; + if (d != 0) { + is_neg = d < 0 ? 1 : 0; + idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; + + if (res_is_inf) { + // If |res| is point-at-infinity there is no need to add the new point, + // we can simply copy it. + const size_t table_idx = idx * g_point_num_limbs; + OPENSSL_memcpy(x_out, &g_table[table_idx], felem_num_bytes); + OPENSSL_memcpy(y_out, &g_table[table_idx + ctx->felem_num_limbs], felem_num_bytes); + OPENSSL_memcpy(z_out, ctx->felem_one, felem_num_bytes); + res_is_inf = 0; + } else { + // Otherwise, add to the accumulator either the point at position idx + // in the table or its negation. + const ec_nistp_felem_limb *y_tmp ; + y_tmp = &g_table[idx * g_point_num_limbs + ctx->felem_num_limbs]; + if (is_neg) { + ctx->felem_neg(ftmp, &g_table[idx * g_point_num_limbs + ctx->felem_num_limbs]); + y_tmp = ftmp; + } + ctx->point_add(x_out, y_out, z_out, x_out, y_out, z_out, 1, + &g_table[idx * g_point_num_limbs], y_tmp, ctx->felem_one); + } + } + } +} diff --git a/crypto/fipsmodule/ec/ec_nistp.h b/crypto/fipsmodule/ec/ec_nistp.h index 13e143a88c..107087dafa 100644 --- a/crypto/fipsmodule/ec/ec_nistp.h +++ b/crypto/fipsmodule/ec/ec_nistp.h @@ -114,5 +114,15 @@ void ec_nistp_scalar_mul_base(const ec_nistp_meth *ctx, ec_nistp_felem_limb *y_out, ec_nistp_felem_limb *z_out, const EC_SCALAR *scalar); + +void ec_nistp_scalar_mul_public(const ec_nistp_meth *ctx, + ec_nistp_felem_limb *x_out, + ec_nistp_felem_limb *y_out, + ec_nistp_felem_limb *z_out, + const EC_SCALAR *g_scalar, + const ec_nistp_felem_limb *x_p, + const ec_nistp_felem_limb *y_p, + const ec_nistp_felem_limb *z_p, + const EC_SCALAR *p_scalar); #endif // EC_NISTP_H diff --git a/crypto/fipsmodule/ec/internal.h b/crypto/fipsmodule/ec/internal.h index bc2d5897f1..8621b4dc39 100644 --- a/crypto/fipsmodule/ec/internal.h +++ b/crypto/fipsmodule/ec/internal.h @@ -697,8 +697,7 @@ void ec_GFp_mont_felem_exp(const EC_GROUP *group, EC_FELEM *out, // where at most one of any w+1 consecutive digits is non-zero // with the exception that the most significant digit may be only // w-1 zeros away from that next non-zero digit. -void ec_compute_wNAF(const EC_GROUP *group, int8_t *out, - const EC_SCALAR *scalar, size_t bits, int w); +void ec_compute_wNAF(int8_t *out, const EC_SCALAR *scalar, size_t bits, int w); int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r, const EC_SCALAR *g_scalar, diff --git a/crypto/fipsmodule/ec/p256.c b/crypto/fipsmodule/ec/p256.c index f8789ced96..4d4b877099 100644 --- a/crypto/fipsmodule/ec/p256.c +++ b/crypto/fipsmodule/ec/p256.c @@ -380,7 +380,7 @@ static void ec_GFp_nistp256_point_mul_public(const EC_GROUP *group, // Set up the coefficients for |p_scalar|. int8_t p_wNAF[257]; - ec_compute_wNAF(group, p_wNAF, p_scalar, 256, P256_WSIZE_PUBLIC); + ec_compute_wNAF(p_wNAF, p_scalar, 256, P256_WSIZE_PUBLIC); // Set |ret| to the point at infinity. int skip = 1; // Save some point operations. diff --git a/crypto/fipsmodule/ec/p384.c b/crypto/fipsmodule/ec/p384.c index e3e8063ab3..91ef79725e 100644 --- a/crypto/fipsmodule/ec/p384.c +++ b/crypto/fipsmodule/ec/p384.c @@ -84,13 +84,6 @@ static p384_limb_t p384_felem_nz(const p384_limb_t in1[P384_NLIMBS]) { #endif // EC_NISTP_USE_S2N_BIGNUM -static void p384_felem_copy(p384_limb_t out[P384_NLIMBS], - const p384_limb_t in1[P384_NLIMBS]) { - for (size_t i = 0; i < P384_NLIMBS; i++) { - out[i] = in1[i]; - } -} - static void p384_from_generic(p384_felem out, const EC_FELEM *in) { #ifdef OPENSSL_BIG_ENDIAN uint8_t tmp[P384_EC_FELEM_BYTES]; @@ -470,26 +463,6 @@ static int ec_GFp_nistp384_cmp_x_coordinate(const EC_GROUP *group, // // For detailed analysis of different window sizes see the bottom of this file. -// Constants for scalar encoding in the scalar multiplication functions. -#define P384_MUL_WSIZE (5) // window size w -// Assert the window size is 5 because the pre-computed table in |p384_table.h| -// is generated for window size 5. -OPENSSL_STATIC_ASSERT(P384_MUL_WSIZE == 5, - p384_scalar_mul_window_size_is_not_equal_to_five) - -#define P384_MUL_TWO_TO_WSIZE (1 << P384_MUL_WSIZE) - -// Number of |P384_MUL_WSIZE|-bit windows in a 384-bit value -#define P384_MUL_NWINDOWS ((384 + P384_MUL_WSIZE - 1)/P384_MUL_WSIZE) - -// For the public point in |ec_GFp_nistp384_point_mul_public| function -// we use window size w = 5. -#define P384_MUL_PUB_WSIZE (5) - -// We keep only odd multiples in tables, hence the table size is (2^w)/2 -#define P384_MUL_TABLE_SIZE (P384_MUL_TWO_TO_WSIZE >> 1) -#define P384_MUL_PUB_TABLE_SIZE (1 << (P384_MUL_PUB_WSIZE - 1)) - // Multiplication of an arbitrary point by a scalar, r = [scalar]P. static void ec_GFp_nistp384_point_mul(const EC_GROUP *group, EC_JACOBIAN *r, const EC_JACOBIAN *p, @@ -523,36 +496,6 @@ static void ec_GFp_nistp384_point_mul_base(const EC_GROUP *group, // Computes [g_scalar]G + [p_scalar]P, where G is the base point of the P-384 // curve, and P is the given point |p|. -// -// Both scalar products are computed by the same "textbook" wNAF method, -// with w = 5 for g_scalar and w = 5 for p_scalar. -// For the base point G product we use the first sub-table of the precomputed -// table |p384_g_pre_comp| from |p384_table.h| file, while for P we generate -// |p_pre_comp| table on-the-fly. The tables hold the first 16 odd multiples -// of G or P: -// g_pre_comp = {[1]G, [3]G, ..., [31]G}, -// p_pre_comp = {[1]P, [3]P, ..., [31]P}. -// Computing the negation of a point P = (x, y) is relatively easy: -// -P = (x, -y). -// So we may assume that we also have the negatives of the points in the tables. -// -// The 384-bit scalars are recoded by the textbook wNAF method to 385 digits, -// where a digit is either a zero or an odd integer in [-31, 31]. The method -// guarantees that each non-zero digit is followed by at least four -// zeroes. -// -// The result [g_scalar]G + [p_scalar]P is computed by the following algorithm: -// 1. Initialize the accumulator with the point-at-infinity. -// 2. For i starting from 384 down to 0: -// 3. Double the accumulator (doubling can be skipped while the -// accumulator is equal to the point-at-infinity). -// 4. Read from |p_pre_comp| the point corresponding to the i-th digit of -// p_scalar, negate it if the digit is negative, and add it to the -// accumulator. -// 5. Read from |g_pre_comp| the point corresponding to the i-th digit of -// g_scalar, negate it if the digit is negative, and add it to the -// accumulator. -// // Note: this function is NOT constant-time. static void ec_GFp_nistp384_point_mul_public(const EC_GROUP *group, EC_JACOBIAN *r, @@ -560,109 +503,14 @@ static void ec_GFp_nistp384_point_mul_public(const EC_GROUP *group, const EC_JACOBIAN *p, const EC_SCALAR *p_scalar) { - p384_felem res[3] = {{0}, {0}, {0}}, two_p[3] = {{0}, {0}, {0}}, ftmp; - - // Table of multiples of P: [2i + 1]P for i in [0, 15]. - p384_felem p_pre_comp[P384_MUL_PUB_TABLE_SIZE][3]; - - // Set the first point in the table to P. - p384_from_generic(p_pre_comp[0][0], &p->X); - p384_from_generic(p_pre_comp[0][1], &p->Y); - p384_from_generic(p_pre_comp[0][2], &p->Z); - - // Compute two_p = [2]P. - p384_point_double(two_p[0], two_p[1], two_p[2], - p_pre_comp[0][0], p_pre_comp[0][1], p_pre_comp[0][2]); - - // Generate the remaining 15 multiples of P. - for (size_t i = 1; i < P384_MUL_PUB_TABLE_SIZE; i++) { - p384_point_add(p_pre_comp[i][0], p_pre_comp[i][1], p_pre_comp[i][2], - two_p[0], two_p[1], two_p[2], 0 /* both Jacobian */, - p_pre_comp[i - 1][0], - p_pre_comp[i - 1][1], - p_pre_comp[i - 1][2]); - } - - // Recode the scalars. - int8_t p_wnaf[385] = {0}, g_wnaf[385] = {0}; - ec_compute_wNAF(group, p_wnaf, p_scalar, 384, P384_MUL_PUB_WSIZE); - ec_compute_wNAF(group, g_wnaf, g_scalar, 384, P384_MUL_WSIZE); - - // In the beginning res is set to point-at-infinity, so we set the flag. - int16_t res_is_inf = 1; - int16_t d, is_neg, idx; - - for (int i = 384; i >= 0; i--) { - - // If |res| is point-at-infinity there is no point in doubling so skip it. - if (!res_is_inf) { - p384_point_double(res[0], res[1], res[2], res[0], res[1], res[2]); - } + p384_felem res[3] = {{0}, {0}, {0}}, tmp[3] = {{0}, {0}, {0}}; - // Process the p_scalar digit. - d = p_wnaf[i]; - if (d != 0) { - is_neg = d < 0 ? 1 : 0; - idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; - - if (res_is_inf) { - // If |res| is point-at-infinity there is no need to add the new point, - // we can simply copy it. - p384_felem_copy(res[0], p_pre_comp[idx][0]); - p384_felem_copy(res[1], p_pre_comp[idx][1]); - p384_felem_copy(res[2], p_pre_comp[idx][2]); - res_is_inf = 0; - } else { - // Otherwise, add to the accumulator either the point at position idx - // in the table or its negation. - if (is_neg) { - p384_felem_opp(ftmp, p_pre_comp[idx][1]); - } else { - p384_felem_copy(ftmp, p_pre_comp[idx][1]); - } - p384_point_add(res[0], res[1], res[2], - res[0], res[1], res[2], - 0 /* both Jacobian */, - p_pre_comp[idx][0], ftmp, p_pre_comp[idx][2]); - } - } + p384_from_generic(tmp[0], &p->X); + p384_from_generic(tmp[1], &p->Y); + p384_from_generic(tmp[2], &p->Z); - // Process the g_scalar digit. - d = g_wnaf[i]; - if (d != 0) { - is_neg = d < 0 ? 1 : 0; - idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; - - if (res_is_inf) { - // If |res| is point-at-infinity there is no need to add the new point, - // we can simply copy it. - p384_felem_copy(res[0], p384_g_pre_comp[0][idx][0]); - p384_felem_copy(res[1], p384_g_pre_comp[0][idx][1]); - p384_felem_copy(res[2], p384_felem_one); - res_is_inf = 0; - } else { - // Otherwise, add to the accumulator either the point at position idx - // in the table or its negation. - if (is_neg) { - p384_felem_opp(ftmp, p384_g_pre_comp[0][idx][1]); - } else { - p384_felem_copy(ftmp, p384_g_pre_comp[0][idx][1]); - } - // Add the point to the accumulator |res|. - // Note that the points in the pre-computed table are given with affine - // coordinates. The point addition function computes a sum of two points, - // either both given in projective, or one in projective and one in - // affine coordinates. The |mixed| flag indicates the latter option, - // in which case we set the third coordinate of the second point to one. - p384_point_add(res[0], res[1], res[2], - res[0], res[1], res[2], - 1 /* mixed */, - p384_g_pre_comp[0][idx][0], ftmp, p384_felem_one); - } - } - } + ec_nistp_scalar_mul_public(p384_methods(), res[0], res[1], res[2], g_scalar, tmp[0], tmp[1], tmp[2], p_scalar); - // Copy the result to the output. p384_to_generic(&r->X, res[0]); p384_to_generic(&r->Y, res[1]); p384_to_generic(&r->Z, res[2]); diff --git a/crypto/fipsmodule/ec/p521.c b/crypto/fipsmodule/ec/p521.c index c35cde1d96..c8d8116ec2 100644 --- a/crypto/fipsmodule/ec/p521.c +++ b/crypto/fipsmodule/ec/p521.c @@ -147,13 +147,6 @@ static p521_limb_t p521_felem_nz(const p521_limb_t in1[P521_NLIMBS]) { #endif } -static void p521_felem_copy(p521_limb_t out[P521_NLIMBS], - const p521_limb_t in1[P521_NLIMBS]) { - for (size_t i = 0; i < P521_NLIMBS; i++) { - out[i] = in1[i]; - } -} - // NOTE: the input and output are in little-endian representation. static void p521_from_generic(p521_felem out, const EC_FELEM *in) { #ifdef OPENSSL_BIG_ENDIAN @@ -407,28 +400,6 @@ static void ec_GFp_nistp521_dbl(const EC_GROUP *group, EC_JACOBIAN *r, // The precomputed table of base point multiples is generated by the code in // |make_tables.go| script. -// Constants for scalar encoding in the scalar multiplication functions. -#define P521_MUL_WSIZE (5) // window size w -// Assert the window size is 5 because the pre-computed table in |p521_table.h| -// is generated for window size 5. -OPENSSL_STATIC_ASSERT(P521_MUL_WSIZE == 5, - p521_scalar_mul_window_size_is_not_equal_to_five) - -#define P521_MUL_TWO_TO_WSIZE (1 << P521_MUL_WSIZE) - -// Number of |P521_MUL_WSIZE|-bit windows in a 521-bit value -#define P521_MUL_NWINDOWS ((521 + P521_MUL_WSIZE - 1)/P521_MUL_WSIZE) - -// For the public point in |ec_GFp_nistp521_point_mul_public| function -// we use window size equal to 5. -#define P521_MUL_PUB_WSIZE (5) - -// We keep only odd multiples in tables, hence the table size is (2^w)/2 -#define P521_MUL_TABLE_SIZE (P521_MUL_TWO_TO_WSIZE >> 1) -#define P521_MUL_PUB_TABLE_SIZE (1 << (P521_MUL_PUB_WSIZE - 1)) - -// p521_select_point_affine selects the |idx|-th affine point from -// the given precomputed table and copies it to |out| in constant-time. // Multiplication of an arbitrary point by a scalar, r = [scalar]P. static void ec_GFp_nistp521_point_mul(const EC_GROUP *group, EC_JACOBIAN *r, const EC_JACOBIAN *p, @@ -462,36 +433,6 @@ static void ec_GFp_nistp521_point_mul_base(const EC_GROUP *group, // Computes [g_scalar]G + [p_scalar]P, where G is the base point of the P-521 // curve, and P is the given point |p|. -// -// Both scalar products are computed by the same "textbook" wNAF method, -// with w = 5 for g_scalar and w = 5 for p_scalar. -// For the base point G product we use the first sub-table of the precomputed -// table |p521_g_pre_comp| from |p521_table.h| file, while for P we generate -// |p_pre_comp| table on-the-fly. The tables hold the first 16 odd multiples -// of G or P: -// g_pre_comp = {[1]G, [3]G, ..., [31]G}, -// p_pre_comp = {[1]P, [3]P, ..., [31]P}. -// Computing the negation of a point P = (x, y) is relatively easy: -// -P = (x, -y). -// So we may assume that we also have the negatives of the points in the tables. -// -// The 521-bit scalars are recoded by the textbook wNAF method to 522 digits, -// where a digit is either a zero or an odd integer in [-31, 31]. The method -// guarantees that each non-zero digit is followed by at least four -// zeroes. -// -// The result [g_scalar]G + [p_scalar]P is computed by the following algorithm: -// 1. Initialize the accumulator with the point-at-infinity. -// 2. For i starting from 521 down to 0: -// 3. Double the accumulator (doubling can be skipped while the -// accumulator is equal to the point-at-infinity). -// 4. Read from |p_pre_comp| the point corresponding to the i-th digit of -// p_scalar, negate it if the digit is negative, and add it to the -// accumulator. -// 5. Read from |g_pre_comp| the point corresponding to the i-th digit of -// g_scalar, negate it if the digit is negative, and add it to the -// accumulator. -// // Note: this function is NOT constant-time. static void ec_GFp_nistp521_point_mul_public(const EC_GROUP *group, EC_JACOBIAN *r, @@ -499,107 +440,13 @@ static void ec_GFp_nistp521_point_mul_public(const EC_GROUP *group, const EC_JACOBIAN *p, const EC_SCALAR *p_scalar) { - p521_felem res[3] = {{0}, {0}, {0}}, two_p[3] = {{0}, {0}, {0}}, ftmp; - - // Table of multiples of P: [2i + 1]P for i in [0, 15]. - p521_felem p_pre_comp[P521_MUL_PUB_TABLE_SIZE][3]; - - // Set the first point in the table to P. - p521_from_generic(p_pre_comp[0][0], &p->X); - p521_from_generic(p_pre_comp[0][1], &p->Y); - p521_from_generic(p_pre_comp[0][2], &p->Z); - - // Compute two_p = [2]P. - p521_point_double(two_p[0], two_p[1], two_p[2], - p_pre_comp[0][0], p_pre_comp[0][1], p_pre_comp[0][2]); - - // Generate the remaining 15 multiples of P. - for (size_t i = 1; i < P521_MUL_PUB_TABLE_SIZE; i++) { - p521_point_add(p_pre_comp[i][0], p_pre_comp[i][1], p_pre_comp[i][2], - two_p[0], two_p[1], two_p[2], 0 /* both Jacobian */, - p_pre_comp[i - 1][0], - p_pre_comp[i - 1][1], - p_pre_comp[i - 1][2]); - } - - // Recode the scalars. - int8_t p_wnaf[522] = {0}, g_wnaf[522] = {0}; - ec_compute_wNAF(group, p_wnaf, p_scalar, 521, P521_MUL_PUB_WSIZE); - ec_compute_wNAF(group, g_wnaf, g_scalar, 521, P521_MUL_WSIZE); - - // In the beginning res is set to point-at-infinity, so we set the flag. - int16_t res_is_inf = 1; - int16_t d, is_neg, idx; - - for (int i = 521; i >= 0; i--) { - - // If |res| is point-at-infinity there is no point in doubling so skip it. - if (!res_is_inf) { - p521_point_double(res[0], res[1], res[2], res[0], res[1], res[2]); - } + p521_felem res[3] = {{0}, {0}, {0}}, tmp[3] = {{0}, {0}, {0}}; - // Process the p_scalar digit. - d = p_wnaf[i]; - if (d != 0) { - is_neg = d < 0 ? 1 : 0; - idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; - - if (res_is_inf) { - // If |res| is point-at-infinity there is no need to add the new point, - // we can simply copy it. - p521_felem_copy(res[0], p_pre_comp[idx][0]); - p521_felem_copy(res[1], p_pre_comp[idx][1]); - p521_felem_copy(res[2], p_pre_comp[idx][2]); - res_is_inf = 0; - } else { - // Otherwise, add to the accumulator either the point at position idx - // in the table or its negation. - if (is_neg) { - p521_felem_opp(ftmp, p_pre_comp[idx][1]); - } else { - p521_felem_copy(ftmp, p_pre_comp[idx][1]); - } - p521_point_add(res[0], res[1], res[2], - res[0], res[1], res[2], - 0 /* both Jacobian */, - p_pre_comp[idx][0], ftmp, p_pre_comp[idx][2]); - } - } + p521_from_generic(tmp[0], &p->X); + p521_from_generic(tmp[1], &p->Y); + p521_from_generic(tmp[2], &p->Z); - // Process the g_scalar digit. - d = g_wnaf[i]; - if (d != 0) { - is_neg = d < 0 ? 1 : 0; - idx = (is_neg) ? (-d - 1) >> 1 : (d - 1) >> 1; - - if (res_is_inf) { - // If |res| is point-at-infinity there is no need to add the new point, - // we can simply copy it. - p521_felem_copy(res[0], p521_g_pre_comp[0][idx][0]); - p521_felem_copy(res[1], p521_g_pre_comp[0][idx][1]); - p521_felem_copy(res[2], p521_felem_one); - res_is_inf = 0; - } else { - // Otherwise, add to the accumulator either the point at position idx - // in the table or its negation. - if (is_neg) { - p521_felem_opp(ftmp, p521_g_pre_comp[0][idx][1]); - } else { - p521_felem_copy(ftmp, p521_g_pre_comp[0][idx][1]); - } - // Add the point to the accumulator |res|. - // Note that the points in the pre-computed table are given with affine - // coordinates. The point addition function computes a sum of two points, - // either both given in projective, or one in projective and one in - // affine coordinates. The |mixed| flag indicates the latter option, - // in which case we set the third coordinate of the second point to one. - p521_point_add(res[0], res[1], res[2], - res[0], res[1], res[2], - 1 /* mixed */, - p521_g_pre_comp[0][idx][0], ftmp, p521_felem_one); - } - } - } + ec_nistp_scalar_mul_public(p521_methods(), res[0], res[1], res[2], g_scalar, tmp[0], tmp[1], tmp[2], p_scalar); // Copy the result to the output. p521_to_generic(&r->X, res[0]); diff --git a/crypto/fipsmodule/ec/wnaf.c b/crypto/fipsmodule/ec/wnaf.c index 225cdfe1d7..da334fe657 100644 --- a/crypto/fipsmodule/ec/wnaf.c +++ b/crypto/fipsmodule/ec/wnaf.c @@ -85,8 +85,7 @@ // http://link.springer.com/chapter/10.1007%2F3-540-45537-X_13 // http://www.bmoeller.de/pdf/TI-01-08.multiexp.pdf -void ec_compute_wNAF(const EC_GROUP *group, int8_t *out, - const EC_SCALAR *scalar, size_t bits, int w) { +void ec_compute_wNAF(int8_t *out, const EC_SCALAR *scalar, size_t bits, int w) { // 'int8_t' can represent integers with absolute values less than 2^7. assert(0 < w && w <= 7); assert(bits != 0); @@ -138,8 +137,9 @@ void ec_compute_wNAF(const EC_GROUP *group, int8_t *out, // we shift and add at most one copy of |bit|, this will continue to hold // afterwards. window_val >>= 1; - window_val += bit * bn_is_bit_set_words(scalar->words, group->order.N.width, - j + w + 1); + const size_t bits_per_word = sizeof(scalar->words[0]) * 8; + const size_t num_words = (bits + bits_per_word - 1) / bits_per_word; + window_val += bit * bn_is_bit_set_words(scalar->words, num_words, j + w + 1); assert(window_val <= next_bit); } @@ -211,13 +211,13 @@ int ec_GFp_mont_mul_public_batch(const EC_GROUP *group, EC_JACOBIAN *r, assert(wNAF_len <= OPENSSL_ARRAY_SIZE(g_wNAF)); const EC_JACOBIAN *g = &group->generator.raw; if (g_scalar != NULL) { - ec_compute_wNAF(group, g_wNAF, g_scalar, bits, EC_WNAF_WINDOW_BITS); + ec_compute_wNAF(g_wNAF, g_scalar, bits, EC_WNAF_WINDOW_BITS); compute_precomp(group, g_precomp, g, EC_WNAF_TABLE_SIZE); } for (size_t i = 0; i < num; i++) { assert(wNAF_len <= OPENSSL_ARRAY_SIZE(wNAF[i])); - ec_compute_wNAF(group, wNAF[i], &scalars[i], bits, EC_WNAF_WINDOW_BITS); + ec_compute_wNAF(wNAF[i], &scalars[i], bits, EC_WNAF_WINDOW_BITS); compute_precomp(group, precomp[i], &points[i], EC_WNAF_TABLE_SIZE); } diff --git a/crypto/ocsp/ocsp_integration_test.cc b/crypto/ocsp/ocsp_integration_test.cc index f1c3d69fc0..d48c5fe0e2 100644 --- a/crypto/ocsp/ocsp_integration_test.cc +++ b/crypto/ocsp/ocsp_integration_test.cc @@ -204,7 +204,7 @@ TEST_P(OCSPIntegrationTest, AmazonTrustServices) { // certificate chain the endpoint uses. int sock = -1; ASSERT_TRUE(InitSocketLibrary()); - ASSERT_TRUE(Connect(&sock, t.url_host)); + ASSERT_TRUE(Connect(&sock, t.url_host, false)); ASSERT_TRUE(SSL_library_init()); bssl::UniquePtr ssl_ctx(SSL_CTX_new(TLS_method())); ASSERT_TRUE(ssl_ctx); diff --git a/crypto/pkcs7/bio/bio_cipher_test.cc b/crypto/pkcs7/bio/bio_cipher_test.cc index d111d27476..c05ffcf04c 100644 --- a/crypto/pkcs7/bio/bio_cipher_test.cc +++ b/crypto/pkcs7/bio/bio_cipher_test.cc @@ -13,9 +13,6 @@ // NOTE: need to keep this in sync with sizeof(ctx->buf) cipher.c #define ENC_BLOCK_SIZE 1024 * 4 -#define BIO_get_cipher_status(bio) \ - BIO_ctrl(bio, BIO_C_GET_CIPHER_STATUS, 0, NULL) - struct CipherParams { const char name[40]; const EVP_CIPHER *(*cipher)(void); diff --git a/crypto/pkcs7/bio/cipher.c b/crypto/pkcs7/bio/cipher.c index 7d822a492a..ee5c95e7eb 100644 --- a/crypto/pkcs7/bio/cipher.c +++ b/crypto/pkcs7/bio/cipher.c @@ -193,7 +193,6 @@ static int enc_write(BIO *b, const char *in, int inl) { static long enc_ctrl(BIO *b, int cmd, long num, void *ptr) { GUARD_PTR(b); long ret = 1; - BIO_ENC_CTX *ctx = BIO_get_data(b); EVP_CIPHER_CTX **cipher_ctx; BIO *next = BIO_next(b); @@ -326,3 +325,7 @@ const BIO_METHOD *BIO_f_cipher(void) { return &methods_enc; } int BIO_get_cipher_ctx(BIO *b, EVP_CIPHER_CTX **ctx) { return BIO_ctrl(b, BIO_C_GET_CIPHER_CTX, 0, ctx); } + +int BIO_get_cipher_status(BIO *b) { + return BIO_ctrl(b, BIO_C_GET_CIPHER_STATUS, 0, NULL); +} diff --git a/crypto/pkcs7/internal.h b/crypto/pkcs7/internal.h index a59f01f3c2..a3b5bc433e 100644 --- a/crypto/pkcs7/internal.h +++ b/crypto/pkcs7/internal.h @@ -223,6 +223,12 @@ OPENSSL_EXPORT int BIO_set_cipher(BIO *b, const EVP_CIPHER *cipher, const unsigned char *key, const unsigned char *iv, int enc); +// BIO_get_cipher_status returns 1 if the cipher is in a healthy state or 0 +// otherwise. Unhealthy state could indicate decryption failure or other +// abnormalities. Data read from an unhealthy cipher should not be considered +// authentic. +OPENSSL_EXPORT int BIO_get_cipher_status(BIO *b); + #if defined(__cplusplus) } // extern C #endif diff --git a/crypto/pkcs7/pkcs7.c b/crypto/pkcs7/pkcs7.c index 984b6b56e9..4ff90e8280 100644 --- a/crypto/pkcs7/pkcs7.c +++ b/crypto/pkcs7/pkcs7.c @@ -662,8 +662,7 @@ static int pkcs7_encode_rinfo(PKCS7_RECIP_INFO *ri, unsigned char *key, int ret = 0; size_t eklen; - pkey = X509_get0_pubkey(ri->cert); - if (pkey == NULL) { + if ((pkey = X509_get0_pubkey(ri->cert)) == NULL) { goto err; } @@ -816,13 +815,9 @@ BIO *PKCS7_dataInit(PKCS7 *p7, BIO *bio) { goto err; } BIO_set_mem_eof_return(bio, /*eof_value*/ 0); - // clang-format off -OPENSSL_BEGIN_ALLOW_DEPRECATED - // clang-format on + OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7) && content && content->length > 0) { - // clang-format off -OPENSSL_END_ALLOW_DEPRECATED - // clang-format on + OPENSSL_END_ALLOW_DEPRECATED // |bio |needs a copy of |os->data| instead of a pointer because the data // will be used after |os |has been freed if (BIO_write(bio, content->data, content->length) != content->length) { @@ -843,13 +838,9 @@ OPENSSL_END_ALLOW_DEPRECATED return NULL; } -// clang-format off OPENSSL_BEGIN_ALLOW_DEPRECATED -// clang-format on int PKCS7_is_detached(PKCS7 *p7) { - // clang-format off -OPENSSL_END_ALLOW_DEPRECATED - // clang-format on + OPENSSL_END_ALLOW_DEPRECATED GUARD_PTR(p7); if (PKCS7_type_is_signed(p7)) { return (p7->d.sign == NULL || p7->d.sign->contents->d.ptr == NULL); @@ -858,7 +849,7 @@ OPENSSL_END_ALLOW_DEPRECATED } -static BIO *PKCS7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { +static BIO *pkcs7_find_digest(EVP_MD_CTX **pmd, BIO *bio, int nid) { GUARD_PTR(pmd); while (bio != NULL) { bio = BIO_find_type(bio, BIO_TYPE_MD); @@ -970,17 +961,9 @@ int PKCS7_dataFinal(PKCS7 *p7, BIO *bio) { si_sk = p7->d.sign->signer_info; // clang-format off OPENSSL_BEGIN_ALLOW_DEPRECATED - // clang-format on content = PKCS7_get_octet_string(p7->d.sign->contents); - // clang-format off -OPENSSL_END_ALLOW_DEPRECATED - // clang-format on // If detached data then the content is excluded - // clang-format off -OPENSSL_BEGIN_ALLOW_DEPRECATED - // clang-format on if (PKCS7_type_is_data(p7->d.sign->contents) && PKCS7_is_detached(p7)) { - // clang-format off OPENSSL_END_ALLOW_DEPRECATED // clang-format on ASN1_OCTET_STRING_free(content); @@ -992,13 +975,9 @@ OPENSSL_END_ALLOW_DEPRECATED case NID_pkcs7_digest: content = PKCS7_get_octet_string(p7->d.digest->contents); // If detached data, then the content is excluded - // clang-format off -OPENSSL_BEGIN_ALLOW_DEPRECATED - // clang-format on + OPENSSL_BEGIN_ALLOW_DEPRECATED if (PKCS7_type_is_data(p7->d.digest->contents) && PKCS7_is_detached(p7)) { - // clang-format off -OPENSSL_END_ALLOW_DEPRECATED - // clang-format on + OPENSSL_END_ALLOW_DEPRECATED ASN1_OCTET_STRING_free(content); content = NULL; p7->d.digest->contents->d.data = NULL; @@ -1017,7 +996,7 @@ OPENSSL_END_ALLOW_DEPRECATED continue; } int sign_nid = OBJ_obj2nid(si->digest_alg->algorithm); - bio_tmp = PKCS7_find_digest(&md_ctx, bio_tmp, sign_nid); + bio_tmp = pkcs7_find_digest(&md_ctx, bio_tmp, sign_nid); if (bio_tmp == NULL) { goto err; } @@ -1046,20 +1025,16 @@ OPENSSL_END_ALLOW_DEPRECATED } else if (OBJ_obj2nid(p7->type) == NID_pkcs7_digest) { unsigned char md_data[EVP_MAX_MD_SIZE]; unsigned int md_len; - if (!PKCS7_find_digest(&md_ctx, bio, EVP_MD_nid(p7->d.digest->md)) || + if (!pkcs7_find_digest(&md_ctx, bio, EVP_MD_nid(p7->d.digest->md)) || !EVP_DigestFinal_ex(md_ctx, md_data, &md_len) || !ASN1_OCTET_STRING_set(p7->d.digest->digest, md_data, md_len)) { goto err; } } - // clang-format off -OPENSSL_BEGIN_ALLOW_DEPRECATED - // clang-format on + OPENSSL_BEGIN_ALLOW_DEPRECATED if (!PKCS7_is_detached(p7)) { - // clang-format off -OPENSSL_END_ALLOW_DEPRECATED - // clang-format on + OPENSSL_END_ALLOW_DEPRECATED if (content == NULL) { goto err; } @@ -1085,3 +1060,352 @@ OPENSSL_END_ALLOW_DEPRECATED EVP_MD_CTX_free(md_ctx_tmp); return ret; } + +// pkcs7_bio_copy_content copies the contents of |src| into |dst|. Only full +// copies are considered successful. It returns 1 on success and 0 on failure. +static int pkcs7_bio_copy_content(BIO *src, BIO *dst) { + uint8_t buf[1024]; + int bytes_processed, ret = 0; + while ((bytes_processed = BIO_read(src, buf, sizeof(buf))) > 0) { + if (!BIO_write_all(dst, buf, bytes_processed)) { + goto err; + } + } + if (bytes_processed < 0) { + goto err; + } + ret = 1; +err: + OPENSSL_cleanse(buf, sizeof(buf)); + return ret; +} + +// PKCS7_final copies the contents of |data| into |p7| before finalizing |p7|. +static int pkcs7_final(PKCS7 *p7, BIO *data) { + BIO *p7bio; + int ret = 0; + + OPENSSL_BEGIN_ALLOW_DEPRECATED + if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) { + OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PKCS7_LIB); + return 0; + } + + if (!pkcs7_bio_copy_content(data, p7bio)) { + goto err; + } + + BIO_flush(p7bio); + OPENSSL_BEGIN_ALLOW_DEPRECATED + if (!PKCS7_dataFinal(p7, p7bio)) { + OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PKCS7_LIB); + goto err; + } + ret = 1; +err: + BIO_free_all(p7bio); + + return ret; +} + +PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, + int flags) { + GUARD_PTR(certs); + GUARD_PTR(in); + GUARD_PTR(cipher); + PKCS7 *p7; + X509 *x509; + + if ((p7 = PKCS7_new()) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PKCS7_LIB); + return NULL; + } + if (!PKCS7_set_type(p7, NID_pkcs7_enveloped)) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); + goto err; + } + if (!PKCS7_set_cipher(p7, cipher)) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_ERROR_SETTING_CIPHER); + goto err; + } + + for (size_t i = 0; i < sk_X509_num(certs); i++) { + x509 = sk_X509_value(certs, i); + OPENSSL_BEGIN_ALLOW_DEPRECATED + if (!PKCS7_add_recipient(p7, x509)) { + OPENSSL_END_ALLOW_DEPRECATED + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_ERROR_ADDING_RECIPIENT); + goto err; + } + } + + if (pkcs7_final(p7, in)) { + return p7; + } + +err: + PKCS7_free(p7); + return NULL; +} + +static int pkcs7_decrypt_rinfo(unsigned char **ek_out, PKCS7_RECIP_INFO *ri, + EVP_PKEY *pkey) { + GUARD_PTR(ri); + GUARD_PTR(ek_out); + unsigned char *ek = NULL; + int ret = 0; + + EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, /*engine*/ NULL); + if (ctx == NULL || !EVP_PKEY_decrypt_init(ctx)) { + goto err; + } + size_t len; + if (!EVP_PKEY_decrypt(ctx, NULL, &len, ri->enc_key->data, + ri->enc_key->length) || + (ek = OPENSSL_malloc(len)) == NULL) { + OPENSSL_PUT_ERROR(EVP, ERR_R_EVP_LIB); + goto err; + } + + int ok = + EVP_PKEY_decrypt(ctx, ek, &len, ri->enc_key->data, ri->enc_key->length); + // We return 0 any failure except for decryption failure. On decrypt failure, + // we still need to set |ek| to NULL to signal decryption failure to callers + // so they can use random bytes as content encryption key for MMA defense. + if (!ok) { + OPENSSL_free(ek); + ek = NULL; + } + + ret = 1; + *ek_out = ek; + +err: + EVP_PKEY_CTX_free(ctx); + return ret; +} + +// pkcs7_cmp_ri is a comparison function, so it returns 0 if |ri| and |pcert| +// match and 1 if they do not. +static int pkcs7_cmp_ri(PKCS7_RECIP_INFO *ri, X509 *pcert) { + if (ri == NULL || ri->issuer_and_serial == NULL || pcert == NULL) { + return 1; + } + int ret = + X509_NAME_cmp(ri->issuer_and_serial->issuer, X509_get_issuer_name(pcert)); + if (ret) { + return ret; + } + return ASN1_INTEGER_cmp(X509_get0_serialNumber(pcert), + ri->issuer_and_serial->serial); +} + +static BIO *pkcs7_data_decode(PKCS7 *p7, EVP_PKEY *pkey, X509 *pcert) { + GUARD_PTR(p7); + GUARD_PTR(pkey); + BIO *out = NULL, *cipher_bio = NULL, *data_bio = NULL; + ASN1_OCTET_STRING *data_body = NULL; + const EVP_CIPHER *cipher = NULL; + X509_ALGOR *enc_alg = NULL; + STACK_OF(PKCS7_RECIP_INFO) *rsk = NULL; + PKCS7_RECIP_INFO *ri = NULL; + uint8_t *cek = NULL, *dummy_key = NULL; // cek means "content encryption key" + + if (p7->d.ptr == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_CONTENT); + return NULL; + } + + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_enveloped: + rsk = p7->d.enveloped->recipientinfo; + enc_alg = p7->d.enveloped->enc_data->algorithm; + // |data_body| is NULL if the optional EncryptedContent is missing. + data_body = p7->d.enveloped->enc_data->enc_data; + cipher = EVP_get_cipherbynid(OBJ_obj2nid(enc_alg->algorithm)); + if (cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CIPHER_TYPE); + goto err; + } + break; + default: + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_UNSUPPORTED_CONTENT_TYPE); + goto err; + } + + if ((cipher_bio = BIO_new(BIO_f_cipher())) == NULL) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_BIO_LIB); + goto err; + } + + // RFC 3218 provides an overview of, and mitigations for, the "Million Message + // Attack" (MMA) on RSA encryption with PKCS-1 padding. Section 2.3 describes + // implementor countermeasures. We implement the following countermeasures, as + // does OpenSSL. + // + // 1. Do not branch on |cek| decryption failure when checking recip infos + // 2. Clear error state after |cek| decrypt is attempted + // 3. If no cek was decrypted, use same-size random bytes + // to output gibberish "plaintext" + // 4. Always pay same allocation costs, regardless of |cek| decrypt result + + // If |pcert| was specified, find the matching recipient info + if (pcert) { + for (size_t ii = 0; ii < sk_PKCS7_RECIP_INFO_num(rsk); ii++) { + ri = sk_PKCS7_RECIP_INFO_value(rsk, ii); + // No decryption operation here, so we can return early without divulging + // information that could be used in MMA. + if (!pkcs7_cmp_ri(ri, pcert)) { + break; + } + ri = NULL; + } + if (ri == NULL) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_NO_RECIPIENT_MATCHES_CERTIFICATE); + goto err; + } + // |pkcs7_decrypt_rinfo| will only return false on critical failure, not + // on decryption failure. Decryption check happens below, after we populate + // |dummy_key| with random bytes. + if (!pkcs7_decrypt_rinfo(&cek, ri, pkey)) { + goto err; + } + } else { + // Attempt to decrypt every recipient info. Don't exit early as + // countermeasure for MMA. + for (size_t ii = 0; ii < sk_PKCS7_RECIP_INFO_num(rsk); ii++) { + ri = sk_PKCS7_RECIP_INFO_value(rsk, ii); + uint8_t *tmp_cek; + // |pkcs7_decrypt_rinfo| will only return false on critical failure, not + // on decryption failure. Check whether |tmp_cek| is present after the + // call to determine if decryption succeeded. + if (!pkcs7_decrypt_rinfo(&tmp_cek, ri, pkey)) { + goto err; + } + // OpenSSL sets encryption key to last successfully decrypted key. Copy + // that behavior, but free previously allocated key memory. + if (tmp_cek) { + OPENSSL_free(cek); + cek = tmp_cek; + } + } + } + // Clear any decryption errors to minimize behavioral difference under MMA + ERR_clear_error(); + + EVP_CIPHER_CTX *evp_ctx = NULL; + if (!BIO_get_cipher_ctx(cipher_bio, &evp_ctx) || + !EVP_CipherInit_ex(evp_ctx, cipher, NULL, NULL, NULL, 0)) { + goto err; + } + uint8_t iv[EVP_MAX_IV_LENGTH]; + OPENSSL_memcpy(iv, enc_alg->parameter->value.octet_string->data, + enc_alg->parameter->value.octet_string->length); + const int expected_iv_len = EVP_CIPHER_CTX_iv_length(evp_ctx); + if (enc_alg->parameter->value.octet_string->length != expected_iv_len) { + OPENSSL_PUT_ERROR(PKCS7, ERR_R_PKCS7_LIB); + goto err; + } + if (!EVP_CipherInit_ex(evp_ctx, NULL, NULL, NULL, iv, 0)) { + goto err; + } + // Get the key length from cipher context so we don't condition on |cek_len| + int len = EVP_CIPHER_CTX_key_length(evp_ctx); + if (!len) { + goto err; + } + // Always generate random bytes for the dummy key, regardless of |cek| decrypt + dummy_key = OPENSSL_malloc(len); + RAND_bytes(dummy_key, len); + // At this point, null |cek| indicates that no content encryption key was + // successfully decrypted. We don't want to return early due to MMA. So, swap + // in the dummy key and proceed. Content decryption result will be gibberish. + if (cek == NULL) { + cek = dummy_key; + dummy_key = NULL; + } + + if (!EVP_CipherInit_ex(evp_ctx, NULL, NULL, cek, NULL, 0)) { + goto err; + } + + OPENSSL_free(cek); + OPENSSL_free(dummy_key); + out = cipher_bio; + + if (data_body && data_body->length > 0) { + data_bio = BIO_new_mem_buf(data_body->data, data_body->length); + } else { + data_bio = BIO_new(BIO_s_mem()); + if (data_bio == NULL || !BIO_set_mem_eof_return(data_bio, 0)) { + goto err; + } + } + if (data_bio == NULL) { + goto err; + } + BIO_push(out, data_bio); + return out; + +err: + OPENSSL_free(cek); + OPENSSL_free(dummy_key); + BIO_free_all(out); + BIO_free_all(cipher_bio); + BIO_free_all(data_bio); + return NULL; +} + +PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509) { + GUARD_PTR(p7); + GUARD_PTR(x509); + PKCS7_RECIP_INFO *ri; + if ((ri = PKCS7_RECIP_INFO_new()) == NULL || + !PKCS7_RECIP_INFO_set(ri, x509) || !PKCS7_add_recipient_info(p7, ri)) { + PKCS7_RECIP_INFO_free(ri); + return NULL; + } + return ri; +} + +int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags) { + GUARD_PTR(p7); + GUARD_PTR(pkey); + GUARD_PTR(data); + BIO *bio = NULL; + int ret = 0; + + switch (OBJ_obj2nid(p7->type)) { + case NID_pkcs7_enveloped: + case NID_pkcs7_signedAndEnveloped: + break; + default: + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_WRONG_CONTENT_TYPE); + goto err; + } + + if (cert && !X509_check_private_key(cert, pkey)) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_PRIVATE_KEY_DOES_NOT_MATCH_CERTIFICATE); + goto err; + } + + if ((bio = pkcs7_data_decode(p7, pkey, cert)) == NULL || + !pkcs7_bio_copy_content(bio, data)) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_DECRYPT_ERROR); + goto err; + } + + // Check whether content decryption was successful + if (1 != BIO_get_cipher_status(bio)) { + OPENSSL_PUT_ERROR(PKCS7, PKCS7_R_DECRYPT_ERROR); + goto err; + } + + ret = 1; + +err: + BIO_free_all(bio); + return ret; +} diff --git a/crypto/pkcs7/pkcs7_test.cc b/crypto/pkcs7/pkcs7_test.cc index a8199edc1b..b75408a1a3 100644 --- a/crypto/pkcs7/pkcs7_test.cc +++ b/crypto/pkcs7/pkcs7_test.cc @@ -1689,3 +1689,193 @@ TEST(PKCS7Test, DataInitFinal) { EXPECT_FALSE(bio); EXPECT_FALSE(PKCS7_dataFinal(p7.get(), bio.get())); } + +TEST(PKCS7Test, TestEnveloped) { + bssl::UniquePtr p7; + bssl::UniquePtr bio; + bssl::UniquePtr certs; + bssl::UniquePtr rsa_x509; + const size_t pt_len = 64; + // NOTE: we make |buf| larger than |pt_len| in case padding gets added. + // without the extra room, we sometimes overflow into the next variable on the + // stack. + uint8_t buf[pt_len + EVP_MAX_BLOCK_LENGTH], decrypted[pt_len]; + + OPENSSL_cleanse(buf, sizeof(buf)); + OPENSSL_memset(buf, 'A', pt_len); + + // parse a cert for use with recipient infos + bssl::UniquePtr rsa(RSA_new()); + ASSERT_TRUE(rsa); + ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr)); + bssl::UniquePtr rsa_pkey(EVP_PKEY_new()); + ASSERT_TRUE(rsa_pkey); + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get())); + certs.reset(sk_X509_new_null()); + bio.reset(BIO_new_mem_buf(kPEMCert, strlen(kPEMCert))); + ASSERT_TRUE(bio); + certs.reset(sk_X509_new_null()); + ASSERT_TRUE(certs); + ASSERT_TRUE(PKCS7_get_PEM_certificates(certs.get(), bio.get())); + ASSERT_EQ(1U, sk_X509_num(certs.get())); + rsa_x509.reset(sk_X509_value(certs.get(), 0)); + ASSERT_TRUE(X509_set_pubkey(rsa_x509.get(), rsa_pkey.get())); + X509_up_ref(rsa_x509.get()); + + // standard success case + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + EXPECT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + bio.reset(BIO_new(BIO_s_mem())); + EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(), bio.get(), + /*flags*/ 0)); + EXPECT_EQ(sizeof(decrypted), BIO_pending(bio.get())); + OPENSSL_cleanse(decrypted, sizeof(decrypted)); + ASSERT_EQ((int)sizeof(decrypted), + BIO_read(bio.get(), decrypted, sizeof(decrypted))); + EXPECT_EQ(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted))); + + // no certs provided for decryption + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + EXPECT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + bio.reset(BIO_new(BIO_s_mem())); + EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr, + bio.get(), + /*flags*/ 0)); + EXPECT_EQ(sizeof(decrypted), BIO_pending(bio.get())); + OPENSSL_cleanse(decrypted, sizeof(decrypted)); + ASSERT_EQ((int)sizeof(decrypted), + BIO_read(bio.get(), decrypted, sizeof(decrypted))); + EXPECT_EQ(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted))); + + // empty plaintext + bio.reset(BIO_new(BIO_s_mem())); + ASSERT_TRUE(BIO_set_mem_eof_return(bio.get(), 0)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + EXPECT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + bio.reset(BIO_new(BIO_s_mem())); + ASSERT_TRUE(BIO_set_mem_eof_return(bio.get(), 0)); + EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(), bio.get(), + /*flags*/ 0)); + EXPECT_EQ(0UL, BIO_pending(bio.get())); + EXPECT_EQ(0, BIO_read(bio.get(), decrypted, sizeof(decrypted))); + EXPECT_FALSE(BIO_should_retry(bio.get())); + + // unsupported content type, with and without content + p7.reset(PKCS7_new()); + ASSERT_TRUE(p7); + ASSERT_TRUE(PKCS7_set_type(p7.get(), NID_pkcs7_signed)); + EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), nullptr, bio.get(), 0)); + ASSERT_TRUE(PKCS7_content_new(p7.get(), NID_pkcs7_data)); + EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), nullptr, bio.get(), 0)); + + // test multiple recipients using the same recipient twice. elide |cert| to + // exercise iterative decryption attempt behavior with multiple (2) successful + // decryptions. + sk_X509_push(certs.get(), rsa_x509.get()); + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + ASSERT_TRUE(p7); + bio.reset(BIO_new(BIO_s_mem())); + // set |rsa_pkey| back to original RSA key + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get())); + EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*cert*/ nullptr, + bio.get(), + /*flags*/ 0)); + ASSERT_TRUE(sk_X509_pop(certs.get())); + ASSERT_EQ(1LU, sk_X509_num(certs.get())); + + // test "MMA" decrypt with mismatched cert pub key/pkey private key and block + // cipher used for content encryption + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + EXPECT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + bio.reset(BIO_new(BIO_s_mem())); + // set new RSA key, cert pub key and PKEY private key now mismatch + rsa.reset(RSA_new()); + ASSERT_TRUE(RSA_generate_key_fips(rsa.get(), 2048, nullptr)); + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa.get())); + // attempt decryption with the new, mismatched keypair. content key decryption + // should "succeed" and produce random, useless content decryption key. + // The content is "decrypted" with the useless key, so nonsense gets written + // to the output |bio|. The cipher ends up in an unhealthy state due to bad + // padding (what should be the final pad block is now just random bytes), so + // the overall |PKCS7_decrypt| operation fails. + int decrypt_ok = + PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr, bio.get(), + /*flags*/ 0); + EXPECT_LE(sizeof(decrypted), BIO_pending(bio.get())); + OPENSSL_cleanse(decrypted, sizeof(decrypted)); + // There's a fun edge case here for block ciphers using conventional PKCS#7 + // padding. In this padding scheme, the last byte of the padded plaintext + // determines how many bytes of padding have been appended and must be + // stripped, A random MMA-defense-garbled padded plaintext with last byte of + // 0x01 will trick the EVP API into thinking that byte is a valid padding + // byte, so it (and only it) will be stripped. This leaves the other + // block_size-1 bytes of the padding block in place, resulting in a larger + // "decrypted plaintext" than anticipated. However, this doesn't only apply to + // one byte of padding. With probability 16^-2, it applies to pad 0x02 0x02 + // and so on with increasingly small probabilities. So, we give slack up to + // 16^-4 which means this test will erroneously fail 0.001526% of the time in + // expectation. Ideally we'd find a way to access the padded plaintext and + // account for this deterministically by checking the random "padding" and + // adusting accordingly. + int max_decrypt = + sizeof(decrypted) + EVP_CIPHER_block_size(EVP_aes_128_cbc()); + int decrypted_len = BIO_read(bio.get(), decrypted, max_decrypt); + if (decrypted_len > (int)pt_len) { + EXPECT_LT(max_decrypt - 4, decrypted_len); + EXPECT_TRUE(decrypt_ok); + EXPECT_FALSE(ERR_GET_REASON(ERR_peek_error())); + } else { + EXPECT_EQ((int)sizeof(decrypted), decrypted_len); + EXPECT_FALSE(decrypt_ok); + EXPECT_EQ(CIPHER_R_BAD_DECRYPT, ERR_GET_REASON(ERR_peek_error())); + } + // Of course, plaintext shouldn't equal decrypted in any case here + EXPECT_NE(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted))); + + // test "MMA" decrypt as above, but with stream cipher. stream cipher has no + // padding, so content encryption should "succeed" but return nonsense because + // the content decryption key is just randomly generated bytes. + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_ctr(), /*flags*/ 0)); + EXPECT_TRUE(p7); + EXPECT_TRUE(PKCS7_type_is_enveloped(p7.get())); + bio.reset(BIO_new(BIO_s_mem())); + // content decryption "succeeds"... + EXPECT_TRUE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), /*certs*/ nullptr, + bio.get(), + /*flags*/ 0)); + EXPECT_EQ(sizeof(decrypted), BIO_pending(bio.get())); + OPENSSL_cleanse(decrypted, sizeof(decrypted)); + ASSERT_EQ((int)sizeof(decrypted), + BIO_read(bio.get(), decrypted, sizeof(decrypted))); + // ...but it produces pseudo-random nonsense + EXPECT_NE(Bytes(buf, pt_len), Bytes(decrypted, sizeof(decrypted))); + EXPECT_FALSE(ERR_GET_REASON(ERR_peek_error())); + + // mismatched cert + pkey on decrypt + bio.reset(BIO_new_mem_buf(buf, pt_len)); + p7.reset( + PKCS7_encrypt(certs.get(), bio.get(), EVP_aes_128_cbc(), /*flags*/ 0)); + bio.reset(BIO_new(BIO_s_mem())); + bssl::UniquePtr rsa2(RSA_new()); + ASSERT_TRUE(RSA_generate_key_fips(rsa2.get(), 2048, nullptr)); + ASSERT_TRUE(EVP_PKEY_set1_RSA(rsa_pkey.get(), rsa2.get())); + EXPECT_FALSE(PKCS7_decrypt(p7.get(), rsa_pkey.get(), rsa_x509.get(), + bio.get(), + /*flags*/ 0)); + EXPECT_EQ(X509_R_KEY_VALUES_MISMATCH, ERR_GET_REASON(ERR_peek_error())); +} diff --git a/include/openssl/pkcs7.h b/include/openssl/pkcs7.h index 4c0948a7cd..3562c22820 100644 --- a/include/openssl/pkcs7.h +++ b/include/openssl/pkcs7.h @@ -359,6 +359,26 @@ OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_set_digest(PKCS7 *p7, const EVP_MD * // |PKCS7_RECIP_INFO| or NULL if none are present. OPENSSL_EXPORT OPENSSL_DEPRECATED STACK_OF(PKCS7_RECIP_INFO) *PKCS7_get_recipient_info(PKCS7 *p7); +// PKCS7_add_recipient allocates a new |PCKS7_RECEPIENT_INFO|, adds |x509| to it +// and returns that |PCKS7_RECEPIENT_INFO|. +OPENSSL_EXPORT OPENSSL_DEPRECATED PKCS7_RECIP_INFO *PKCS7_add_recipient(PKCS7 *p7, X509 *x509); + +// PKCS7_encrypt encrypts the contents of |in| with |cipher| and adds |certs| as +// recipient infos and returns an encrypted |PKCS7| or NULL on failed +// encryption. |flags| is ignored. We only perform key encryption using RSA, so +// |certs| must use RSA public keys. +OPENSSL_EXPORT OPENSSL_DEPRECATED PKCS7 *PKCS7_encrypt(STACK_OF(X509) *certs, BIO *in, const EVP_CIPHER *cipher, int flags); + +// PKCS7_decrypt decrypts |p7| with |pkey| and writes the plaintext to |data|. +// If |cert| is present, it's public key is checked against |pkey| and |p7|'s +// recipient infos. 1 is returned on success and 0 on failure. |flags| is +// ignored. |pkey| must be an |EVP_PKEY_RSA|. +// +// NOTE: If |p7| was encrypted with a stream cipher, this operation may return 1 +// even on decryption failure. The reason for this is detailed in RFC 3218 and +// comments in the |PKCS7_decrypt| source. +OPENSSL_EXPORT OPENSSL_DEPRECATED int PKCS7_decrypt(PKCS7 *p7, EVP_PKEY *pkey, X509 *cert, BIO *data, int flags); + #if defined(__cplusplus) } // extern C @@ -405,5 +425,6 @@ BSSL_NAMESPACE_END #define PKCS7_R_PKCS7_ADD_SIGNER_ERROR 131 #define PKCS7_R_PKCS7_ADD_SIGNATURE_ERROR 132 #define PKCS7_R_NO_DEFAULT_DIGEST 133 +#define PKCS7_R_CERT_MUST_BE_RSA 134 #endif // OPENSSL_HEADER_PKCS7_H diff --git a/ssl/ssl_cert.cc b/ssl/ssl_cert.cc index cd09d847bc..932b4801cb 100644 --- a/ssl/ssl_cert.cc +++ b/ssl/ssl_cert.cc @@ -859,6 +859,16 @@ UniquePtr DC::Parse(CRYPTO_BUFFER *in, uint8_t *out_alert) { return nullptr; } + // RFC 9345 forbids algorithms that use the rsaEncryption OID. As the + // RSASSA-PSS OID is unusably complicated, this effectively means we will not + // support RSA delegated credentials. + if (SSL_get_signature_algorithm_key_type(dc->dc_cert_verify_algorithm) == + EVP_PKEY_RSA) { + OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SIGNATURE_ALGORITHM); + *out_alert = SSL_AD_ILLEGAL_PARAMETER; + return nullptr; + } + return dc; } diff --git a/ssl/test/runner/cert.pem b/ssl/test/runner/cert.pem deleted file mode 100644 index c360dc7317..0000000000 --- a/ssl/test/runner/cert.pem +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIJALW2IrlaBKUhMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTYwNzA5MDQzODA5WhcNMTYwODA4MDQzODA5WjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAugvahBkSAUF1fC49vb1bvlPrcl80kop1iLpiuYoz4Qptwy57+EWssZBc -HprZ5BkWf6PeGZ7F5AX1PyJbGHZLqvMCvViP6pd4MFox/igESISEHEixoiXCzepB -rhtp5UQSjHD4D4hKtgdMgVxX+LRtwgW3mnu/vBu7rzpr/DS8io99p3lqZ1Aky+aN -lcMj6MYy8U+YFEevb/V0lRY9oqwmW7BHnXikm/vi6sjIS350U8zb/mRzYeIs2R65 -LUduTL50+UMgat9ocewI2dv8aO9Dph+8NdGtg8LFYyTTHcUxJoMr1PTOgnmET19W -JH4PrFwk7ZE1QJQQ1L4iKmPeQistuQIDAQABo4GnMIGkMB0GA1UdDgQWBBT5m6Vv -zYjVYHG30iBE+j2XDhUE8jB1BgNVHSMEbjBsgBT5m6VvzYjVYHG30iBE+j2XDhUE -8qFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV -BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJALW2IrlaBKUhMAwGA1UdEwQF -MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAD7Jg68SArYWlcoHfZAB90Pmyrt5H6D8 -LRi+W2Ri1fBNxREELnezWJ2scjl4UMcsKYp4Pi950gVN+62IgrImcCNvtb5I1Cfy -/MNNur9ffas6X334D0hYVIQTePyFk3umI+2mJQrtZZyMPIKSY/sYGQHhGGX6wGK+ -GO/og0PQk/Vu6D+GU2XRnDV0YZg1lsAsHd21XryK6fDmNkEMwbIWrts4xc7scRrG -HWy+iMf6/7p/Ak/SIicM4XSwmlQ8pPxAZPr+E2LoVd9pMpWUwpW2UbtO5wsGTrY5 -sO45tFNN/y+jtUheB1C2ijObG/tXELaiyCdM+S/waeuv0MXtI4xnn1A= ------END CERTIFICATE----- diff --git a/ssl/test/runner/channel_id_key.pem b/ssl/test/runner/channel_id_key.pem index 604752bcda..83eb53a459 100644 --- a/ssl/test/runner/channel_id_key.pem +++ b/ssl/test/runner/channel_id_key.pem @@ -1,5 +1,5 @@ ------BEGIN EC PRIVATE KEY----- -MHcCAQEEIPwxu50c7LEhVNRYJFRWBUnoaz7JSos96T5hBp4rjyptoAoGCCqGSM49 -AwEHoUQDQgAEzFSVTE5guxJRQ0VbZ8dicPs5e/DT7xpW7Yc9hq0VOchv7cbXuI/T -CwadDjGWX/oaz0ftFqrVmfkwZu+C58ioWg== ------END EC PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg/DG7nRzssSFU1Fgk +VFYFSehrPslKiz3pPmEGniuPKm2hRANCAATMVJVMTmC7ElFDRVtnx2Jw+zl78NPv +Glbthz2GrRU5yG/txte4j9MLBp0OMZZf+hrPR+0WqtWZ+TBm74LnyKha +-----END PRIVATE KEY----- diff --git a/ssl/test/runner/cipher_suites.go b/ssl/test/runner/cipher_suites.go index 5db57498be..8bbde8e6e4 100644 --- a/ssl/test/runner/cipher_suites.go +++ b/ssl/test/runner/cipher_suites.go @@ -28,8 +28,8 @@ type keyAgreement interface { // In the case that the key agreement protocol doesn't use a // ServerKeyExchange message, generateServerKeyExchange can return nil, // nil. - generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg, uint16) (*serverKeyExchangeMsg, error) - processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) + generateServerKeyExchange(*Config, *CertificateChain, *clientHelloMsg, *serverHelloMsg, uint16) (*serverKeyExchangeMsg, error) + processClientKeyExchange(*Config, *CertificateChain, *clientKeyExchangeMsg, uint16) ([]byte, error) // On the client side, the next two methods are called in order. diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go index 024c921095..cd10e14641 100644 --- a/ssl/test/runner/common.go +++ b/ssl/test/runner/common.go @@ -10,9 +10,12 @@ import ( "crypto/ecdsa" "crypto/rand" "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" "fmt" "io" "math/big" + "os" "strings" "sync" "time" @@ -434,18 +437,18 @@ type Config struct { // If Time is nil, TLS uses time.Now. Time func() time.Time - // Certificates contains one or more certificate chains + // Chains contains one or more certificate chains // to present to the other side of the connection. // Server configurations must include at least one certificate. - Certificates []Certificate + Chains []CertificateChain - // NameToCertificate maps from a certificate name to an element of - // Certificates. Note that a certificate name can be of the form + // NameToChain maps from a certificate name to an element of + // Chains. Note that a certificate name can be of the form // '*.example.com' and so doesn't have to be a domain name as such. // See Config.BuildNameToCertificate - // The nil value causes the first element of Certificates to be used + // The nil value causes the first element of Chains to be used // for all connections. - NameToCertificate map[string]*Certificate + NameToChain map[string]*CertificateChain // RootCAs defines the set of root certificate authorities // that clients use when verifying server certificates. @@ -1842,7 +1845,7 @@ type ProtocolBugs struct { // RenegotiationCertificate, if not nil, is the certificate to use on // renegotiation handshakes. - RenegotiationCertificate *Certificate + RenegotiationCertificate *CertificateChain // ExpectNoCertificateAuthoritiesExtension, if true, causes the client to // reject CertificateRequest with the CertificateAuthorities extension. @@ -2126,12 +2129,12 @@ func (c *Config) supportedVersions(isDTLS, requireTLS13 bool) []uint16 { } // getCertificateForName returns the best certificate for the given name, -// defaulting to the first element of c.Certificates if there are no good +// defaulting to the first element of c.Chains if there are no good // options. -func (c *Config) getCertificateForName(name string) *Certificate { - if len(c.Certificates) == 1 || c.NameToCertificate == nil { +func (c *Config) getCertificateForName(name string) *CertificateChain { + if len(c.Chains) == 1 || c.NameToChain == nil { // There's only one choice, so no point doing any work. - return &c.Certificates[0] + return &c.Chains[0] } name = strings.ToLower(name) @@ -2139,7 +2142,7 @@ func (c *Config) getCertificateForName(name string) *Certificate { name = name[:len(name)-1] } - if cert, ok := c.NameToCertificate[name]; ok { + if cert, ok := c.NameToChain[name]; ok { return cert } @@ -2149,13 +2152,13 @@ func (c *Config) getCertificateForName(name string) *Certificate { for i := range labels { labels[i] = "*" candidate := strings.Join(labels, ".") - if cert, ok := c.NameToCertificate[candidate]; ok { + if cert, ok := c.NameToChain[candidate]; ok { return cert } } // If nothing matches, return the first certificate. - return &c.Certificates[0] + return &c.Chains[0] } func (c *Config) signSignatureAlgorithms() []signatureAlgorithm { @@ -2172,28 +2175,28 @@ func (c *Config) verifySignatureAlgorithms() []signatureAlgorithm { return supportedSignatureAlgorithms } -// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate +// BuildNameToCertificate parses c.Chains and builds c.NameToCertificate // from the CommonName and SubjectAlternateName fields of each of the leaf // certificates. func (c *Config) BuildNameToCertificate() { - c.NameToCertificate = make(map[string]*Certificate) - for i := range c.Certificates { - cert := &c.Certificates[i] + c.NameToChain = make(map[string]*CertificateChain) + for i := range c.Chains { + cert := &c.Chains[i] x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { continue } if len(x509Cert.Subject.CommonName) > 0 { - c.NameToCertificate[x509Cert.Subject.CommonName] = cert + c.NameToChain[x509Cert.Subject.CommonName] = cert } for _, san := range x509Cert.DNSNames { - c.NameToCertificate[san] = cert + c.NameToChain[san] = cert } } } -// A Certificate is a chain of one or more certificates, leaf first. -type Certificate struct { +// A CertificateChain is a chain of one or more certificates, leaf first. +type CertificateChain struct { Certificate [][]byte PrivateKey crypto.PrivateKey // supported types: *rsa.PrivateKey, *ecdsa.PrivateKey // OCSPStaple contains an optional OCSP response which will be served @@ -2208,6 +2211,15 @@ type Certificate struct { // processing for TLS clients doing client authentication. If nil, the // leaf certificate will be parsed as needed. Leaf *x509.Certificate + // ChainPath is the path to the temporary on disk copy of the certificate + // chain. + ChainPath string + // KeyPath is the path to the temporary on disk copy of the key. + KeyPath string + // RootPath is the path to the temporary on disk copy of the root of the + // certificate chain. If the chain only contains one certificate ChainPath + // and RootPath will be the same. + RootPath string } // A TLS record. @@ -2419,3 +2431,90 @@ func isAllZero(v []byte) bool { } return true } + +var baseCertTemplate = &x509.Certificate{ + SerialNumber: big.NewInt(57005), + Subject: pkix.Name{ + CommonName: "test cert", + Country: []string{"US"}, + Province: []string{"Some-State"}, + Organization: []string{"Internet Widgits Pty Ltd"}, + }, + NotBefore: time.Now().Add(-time.Hour), + NotAfter: time.Now().Add(time.Hour), + DNSNames: []string{"test"}, + IsCA: true, + BasicConstraintsValid: true, +} + +var tmpDir string + +func generateSingleCertChain(template *x509.Certificate, key crypto.Signer, ocspStaple, sctList []byte) CertificateChain { + cert := generateTestCert(template, nil, key, ocspStaple, sctList) + tmpCertPath, tmpKeyPath := writeTempCertFile([]*x509.Certificate{cert}), writeTempKeyFile(key) + return CertificateChain{ + Certificate: [][]byte{cert.Raw}, + PrivateKey: key, + OCSPStaple: ocspStaple, + SignedCertificateTimestampList: sctList, + Leaf: cert, + ChainPath: tmpCertPath, + KeyPath: tmpKeyPath, + RootPath: tmpCertPath, + } +} + +func writeTempCertFile(certs []*x509.Certificate) string { + f, err := os.CreateTemp(tmpDir, "test-cert") + if err != nil { + panic(fmt.Sprintf("failed to create temp file: %s", err)) + } + for _, cert := range certs { + if _, err := f.Write(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})); err != nil { + panic(fmt.Sprintf("failed to write test certificate: %s", err)) + } + } + tmpCertPath := f.Name() + if err := f.Close(); err != nil { + panic(fmt.Sprintf("failed to close test certificate temp file: %s", err)) + } + return tmpCertPath +} + +func writeTempKeyFile(privKey crypto.Signer) string { + f, err := os.CreateTemp(tmpDir, "test-key") + if err != nil { + panic(fmt.Sprintf("failed to create temp file: %s", err)) + } + keyDER, err := x509.MarshalPKCS8PrivateKey(privKey) + if err != nil { + panic(fmt.Sprintf("failed to marshal test key: %s", err)) + } + if _, err := f.Write(pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: keyDER})); err != nil { + panic(fmt.Sprintf("failed to write test key: %s", err)) + } + tmpKeyPath := f.Name() + if err := f.Close(); err != nil { + panic(fmt.Sprintf("failed to close test key temp file: %s", err)) + } + return tmpKeyPath +} + +func generateTestCert(template, issuer *x509.Certificate, key crypto.Signer, ocspStaple, sctList []byte) *x509.Certificate { + if template == nil { + template = baseCertTemplate + } + if issuer == nil { + issuer = template + } + der, err := x509.CreateCertificate(rand.Reader, template, issuer, key.Public(), key) + if err != nil { + panic(fmt.Sprintf("failed to create test certificate: %s", err)) + } + cert, err := x509.ParseCertificate(der) + if err != nil { + panic(fmt.Sprintf("failed to parse test certificate: %s", err)) + } + + return cert +} diff --git a/ssl/test/runner/ecdsa_p224_cert.pem b/ssl/test/runner/ecdsa_p224_cert.pem deleted file mode 100644 index 29246a2eac..0000000000 --- a/ssl/test/runner/ecdsa_p224_cert.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBvjCCAWygAwIBAgIJAPlkrPTq4HgnMAoGCCqGSM49BAMCMEUxCzAJBgNVBAYT -AkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn -aXRzIFB0eSBMdGQwHhcNMTcwMjI3MjAxOTIzWhcNMTkwMjI3MjAxOTIzWjBFMQsw -CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu -ZXQgV2lkZ2l0cyBQdHkgTHRkME4wEAYHKoZIzj0CAQYFK4EEACEDOgAE6dul6dL0 -+CyooFiKK4V+EYNYPbMZoLTxRcjRgrw3db6QzBAviDSxKADTVuyRmaVC74Mf6boB -HDmjUDBOMB0GA1UdDgQWBBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAfBgNVHSMEGDAW -gBSMtlkUJ7SCZ4zRqkjXMWvOebSgpTAMBgNVHRMEBTADAQH/MAoGCCqGSM49BAMC -A0AAMD0CHHolWPktSLbVMy9ukQUb2E7+Jb3hcNFqAXh47pYCHQC+jv2EE6oOEZ9F -tLkFLtap71+83P0NUEJX4Etu ------END CERTIFICATE----- diff --git a/ssl/test/runner/ecdsa_p256_cert.pem b/ssl/test/runner/ecdsa_p256_cert.pem deleted file mode 100644 index 50bcbf5bfd..0000000000 --- a/ssl/test/runner/ecdsa_p256_cert.pem +++ /dev/null @@ -1,12 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBzzCCAXagAwIBAgIJANlMBNpJfb/rMAkGByqGSM49BAEwRTELMAkGA1UEBhMC -QVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdp -dHMgUHR5IEx0ZDAeFw0xNDA0MjMyMzIxNTdaFw0xNDA1MjMyMzIxNTdaMEUxCzAJ -BgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5l -dCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmK2ni -v2Wfl74vHg2UikzVl2u3qR4NRvvdqakendy6WgHn1peoChj5w8SjHlbifINI2xYa -HPUdfvGULUvPciLBo1AwTjAdBgNVHQ4EFgQUq4TSrKuV8IJOFngHVVdf5CaNgtEw -HwYDVR0jBBgwFoAUq4TSrKuV8IJOFngHVVdf5CaNgtEwDAYDVR0TBAUwAwEB/zAJ -BgcqhkjOPQQBA0gAMEUCIQDyoDVeUTo2w4J5m+4nUIWOcAZ0lVfSKXQA9L4Vh13E -BwIgfB55FGohg/B6dGh5XxSZmmi08cueFV7mHzJSYV51yRQ= ------END CERTIFICATE----- diff --git a/ssl/test/runner/ecdsa_p384_cert.pem b/ssl/test/runner/ecdsa_p384_cert.pem deleted file mode 100644 index 1fd3fec63d..0000000000 --- a/ssl/test/runner/ecdsa_p384_cert.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIJAN+/LubpDwxNMAkGByqGSM49BAEwRTELMAkGA1UEBhMC -QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp -dHMgUHR5IEx0ZDAeFw0xNjA3MDkwMDAxMzJaFw0xNjA4MDgwMDAxMzJaMEUxCzAJ -BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l -dCBXaWRnaXRzIFB0eSBMdGQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQOdTJNqxiZ -+B68tCZV4GEJwDJ18jK9gFzvefcEAQluBijjrMjflL+RZAT64ExWzedRMp9PD9CW -Tz9hG/Kz4q/l952YsIhy7LTGXzwy7549WUOi+N3aW8psDjtwzWNZXqWjgacwgaQw -HQYDVR0OBBYEFKmYPjADcOlogOMU6D9wlftIWMj6MHUGA1UdIwRuMGyAFKmYPjAD -cOlogOMU6D9wlftIWMj6oUmkRzBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29t -ZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkggkA378u -5ukPDE0wDAYDVR0TBAUwAwEB/zAJBgcqhkjOPQQBA2kAMGYCMQDTfL0OkRGnS5Ze -tsxagAuZqM2Zyv5a2g7u6eFLCx2rpTuQndWOtEnmVo3wjTDtkDcCMQCg+05XSqEF -cqxdXMZJMhqj2jS+tWucdgDstp/1KzJkbsupSjBzIycjVBKLdRwtNg8= ------END CERTIFICATE----- diff --git a/ssl/test/runner/ecdsa_p521_cert.pem b/ssl/test/runner/ecdsa_p521_cert.pem deleted file mode 100644 index 8b9a1e8384..0000000000 --- a/ssl/test/runner/ecdsa_p521_cert.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICrzCCAhGgAwIBAgIJAMZT7oSqTg/lMAkGByqGSM49BAEwRTELMAkGA1UEBhMC -QVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdpZGdp -dHMgUHR5IEx0ZDAeFw0xNjA3MDkwMDAwNTBaFw0xNjA4MDgwMDAwNTBaMEUxCzAJ -BgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5l -dCBXaWRnaXRzIFB0eSBMdGQwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABAFD0TiZ -InCoCYDI66FvoaZ0tniUhaNk2YnjEPikfmYHDwstbqkTEqnGAq3pKF2y/MHTBXFd -E0KcFOPs5Ju8EgIcqwGvCkwHPmZtvvOrf+nJNHdm1gZfBUy09f3fVe/mHwfM2++H -dz54nHKxtQqvdafhmMV77R/rBuI24MLKbMihxRgQKaOBpzCBpDAdBgNVHQ4EFgQU -mLWm6ZtGfvih6iFx0+duYfHjGsYwdQYDVR0jBG4wbIAUmLWm6ZtGfvih6iFx0+du -YfHjGsahSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw -HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCCQDGU+6Eqk4P5TAMBgNV -HRMEBTADAQH/MAkGByqGSM49BAEDgYwAMIGIAkIBL/oEXMMQH9fefVd8onvgQbWI -/CJXYE+kLO15gO8satasGutVpXtYGeP8gZeuHrq+jWxzj7dGM7YzkW0pAu+wOAkC -QgFJSvKFcmbreLIjuwYik5aXeaUnTCvTQumG07cF0hZRgCf/kTxxmu2ffRoGCDTz -XoPqlxwaO7K+gaAS//CvR0E3lw== ------END CERTIFICATE----- diff --git a/ssl/test/runner/ed25519_cert.pem b/ssl/test/runner/ed25519_cert.pem deleted file mode 100644 index 308c2c9d28..0000000000 --- a/ssl/test/runner/ed25519_cert.pem +++ /dev/null @@ -1,11 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBkTCCAUOgAwIBAgIJAJwooam0UCDmMAUGAytlcDBFMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMB4XDTE0MDQyMzIzMjE1N1oXDTE0MDUyMzIzMjE1N1owRTELMAkGA1UE -BhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdp -ZGdpdHMgUHR5IEx0ZDAqMAUGAytlcAMhANdamAGCsQq31Uv+08lkBzoO4XLz2qYj -Ja8CGmj3B1Eao1AwTjAdBgNVHQ4EFgQUoux7eV+fJK2v3ah6QPU/lj1/+7UwHwYD -VR0jBBgwFoAUoux7eV+fJK2v3ah6QPU/lj1/+7UwDAYDVR0TBAUwAwEB/zAFBgMr -ZXADQQBuCzqji8VP9xU8mHEMjXGChX7YP5J664UyVKHKH9Z1u4wEbB8dJ3ScaWSL -r+VHVKUhsrvcdCelnXRrrSD7xWAL ------END CERTIFICATE----- diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go index cd23337e16..41840d7191 100644 --- a/ssl/test/runner/handshake_client.go +++ b/ssl/test/runner/handshake_client.go @@ -1183,7 +1183,7 @@ func (hs *clientHandshakeState) doTLS13Handshake(msg interface{}) error { return err } - var chainToSend *Certificate + var chainToSend *CertificateChain var certReq *certificateRequestMsg if c.didResume { // Copy over authentication from the session. @@ -1691,7 +1691,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { } } - var chainToSend *Certificate + var chainToSend *CertificateChain var certRequested bool certReq, ok := msg.(*certificateRequestMsg) if ok { @@ -1769,7 +1769,7 @@ func (hs *clientHandshakeState) doFullHandshake() error { } // Determine the hash to sign. - privKey := c.config.Certificates[0].PrivateKey + privKey := c.config.Chains[0].PrivateKey if certVerify.hasSignatureAlgorithm { certVerify.signatureAlgorithm, err = selectSignatureAlgorithm(c.vers, privKey, c.config, certReq.signatureAlgorithms) @@ -2403,18 +2403,18 @@ func (hs *clientHandshakeState) writeServerHash(msg []byte) { // selectClientCertificate selects a certificate for use with the given // certificate, or none if none match. It may return a particular certificate or // nil on success, or an error on internal error. -func selectClientCertificate(c *Conn, certReq *certificateRequestMsg) (*Certificate, error) { - if len(c.config.Certificates) == 0 { +func selectClientCertificate(c *Conn, certReq *certificateRequestMsg) (*CertificateChain, error) { + if len(c.config.Chains) == 0 { return nil, nil } // The test is assumed to have configured the certificate it meant to // send. - if len(c.config.Certificates) > 1 { + if len(c.config.Chains) > 1 { return nil, errors.New("tls: multiple certificates configured") } - return &c.config.Certificates[0], nil + return &c.config.Chains[0], nil } // clientSessionCacheKey returns a key used to cache sessionTickets that could diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go index 7c3b587ab3..3cae911706 100644 --- a/ssl/test/runner/handshake_server.go +++ b/ssl/test/runner/handshake_server.go @@ -36,7 +36,7 @@ type serverHandshakeState struct { finishedHash finishedHash masterSecret []byte certsFromClient [][]byte - cert *Certificate + cert *CertificateChain finishedBytes []byte echHPKEContext *hpke.Context echConfigID uint8 @@ -1579,11 +1579,11 @@ func (hs *serverHandshakeState) processClientExtensions(serverExtensions *server if len(hs.clientHello.serverName) > 0 { c.serverName = hs.clientHello.serverName } - if len(config.Certificates) == 0 { + if len(config.Chains) == 0 { c.sendAlert(alertInternalError) return errors.New("tls: no certificates configured") } - hs.cert = &config.Certificates[0] + hs.cert = &config.Chains[0] if len(hs.clientHello.serverName) > 0 { hs.cert = config.getCertificateForName(hs.clientHello.serverName) } diff --git a/ssl/test/runner/key_agreement.go b/ssl/test/runner/key_agreement.go index 1053e4f46e..94d2543057 100644 --- a/ssl/test/runner/key_agreement.go +++ b/ssl/test/runner/key_agreement.go @@ -38,7 +38,7 @@ type rsaKeyAgreement struct { exportKey *rsa.PrivateKey } -func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { +func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { // Save the client version for comparison later. ka.clientVersion = clientHello.vers @@ -95,7 +95,7 @@ func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi return skx, nil } -func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { +func (ka *rsaKeyAgreement) processClientKeyExchange(config *Config, cert *CertificateChain, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { preMasterSecret := make([]byte, 48) _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) if err != nil { @@ -362,7 +362,7 @@ func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) { // keyAgreementAuthentication is a helper interface that specifies how // to authenticate the ServerKeyExchange parameters. type keyAgreementAuthentication interface { - signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) + signParameters(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) verifyParameters(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, key crypto.PublicKey, params []byte, sig []byte) error } @@ -370,7 +370,7 @@ type keyAgreementAuthentication interface { // agreement parameters. type nilKeyAgreementAuthentication struct{} -func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { +func (ka *nilKeyAgreementAuthentication) signParameters(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { skx := new(serverKeyExchangeMsg) skx.key = params return skx, nil @@ -388,7 +388,7 @@ type signedKeyAgreement struct { peerSignatureAlgorithm signatureAlgorithm } -func (ka *signedKeyAgreement) signParameters(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { +func (ka *signedKeyAgreement) signParameters(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, params []byte) (*serverKeyExchangeMsg, error) { // The message to be signed is prepended by the randoms. var msg []byte msg = append(msg, clientHello.random...) @@ -494,7 +494,7 @@ type ecdheKeyAgreement struct { peerKey []byte } -func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { +func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { var curveid CurveID preferredCurves := config.curvePreferences() @@ -545,7 +545,7 @@ NextCandidate: return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams) } -func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { +func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *CertificateChain, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { return nil, errClientKeyExchange } @@ -612,11 +612,11 @@ func (ka *ecdheKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm { // exchange. type nilKeyAgreement struct{} -func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { +func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { return nil, nil } -func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { +func (ka *nilKeyAgreement) processClientKeyExchange(config *Config, cert *CertificateChain, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { if len(ckx.ciphertext) != 0 { return nil, errClientKeyExchange } @@ -664,7 +664,7 @@ type pskKeyAgreement struct { identityHint string } -func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { +func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *CertificateChain, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { // Assemble the identity hint. bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) @@ -691,7 +691,7 @@ func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi return skx, nil } -func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { +func (ka *pskKeyAgreement) processClientKeyExchange(config *Config, cert *CertificateChain, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { // First, process the PSK identity. if len(ckx.ciphertext) < 2 { return nil, errClientKeyExchange diff --git a/ssl/test/runner/rsa_1024_cert.pem b/ssl/test/runner/rsa_1024_cert.pem deleted file mode 100644 index 4de4f49a34..0000000000 --- a/ssl/test/runner/rsa_1024_cert.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICWDCCAcGgAwIBAgIJAPuwTC6rEJsMMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwHhcNMTQwNDIzMjA1MDQwWhcNMTcwNDIyMjA1MDQwWjBF -MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 -ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB -gQDYK8imMuRi/03z0K1Zi0WnvfFHvwlYeyK9Na6XJYaUoIDAtB92kWdGMdAQhLci -HnAjkXLI6W15OoV3gA/ElRZ1xUpxTMhjP6PyY5wqT5r6y8FxbiiFKKAnHmUcrgfV -W28tQ+0rkLGMryRtrukXOgXBv7gcrmU7G1jC2a7WqmeI8QIDAQABo1AwTjAdBgNV -HQ4EFgQUi3XVrMsIvg4fZbf6Vr5sp3Xaha8wHwYDVR0jBBgwFoAUi3XVrMsIvg4f -Zbf6Vr5sp3Xaha8wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQA76Hht -ldY9avcTGSwbwoiuIqv0jTL1fHFnzy3RHMLDh+Lpvolc5DSrSJHCP5WuK0eeJXhr -T5oQpHL9z/cCDLAKCKRa4uV0fhEdOWBqyR9p8y5jJtye72t6CuFUV5iqcpF4BH4f -j2VNHwsSrJwkD4QUGlUtH7vwnQmyCFxZMmWAJg== ------END CERTIFICATE----- diff --git a/ssl/test/runner/key.pem b/ssl/test/runner/rsa_2048_key.pem similarity index 100% rename from ssl/test/runner/key.pem rename to ssl/test/runner/rsa_2048_key.pem diff --git a/ssl/test/runner/rsa_chain_cert.pem b/ssl/test/runner/rsa_chain_cert.pem deleted file mode 100644 index 8eb6e60eda..0000000000 --- a/ssl/test/runner/rsa_chain_cert.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIC0jCCAbqgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwDzENMAsGA1UEAwwEQiBD -QTAeFw0xNjAyMjgyMDI3MDNaFw0yNjAyMjUyMDI3MDNaMBgxFjAUBgNVBAMMDUNs -aWVudCBDZXJ0IEEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDRvaz8 -CC/cshpCafJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/ -kLRcH89M/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3 -tHb+xs2PSs8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+c -IDs2rQ+lP7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1 -z7C8jU50Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9V -iLeXANgZi+Xx9KgfAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI -KwYBBQUHAwEGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQBFEVbmYl+2RtNw -rDftRDF1v2QUbcN2ouSnQDHxeDQdSgasLzT3ui8iYu0Rw2WWcZ0DV5e0ztGPhWq7 -AO0B120aFRMOY+4+bzu9Q2FFkQqc7/fKTvTDzIJI5wrMnFvUfzzvxh3OHWMYSs/w -giq33hTKeHEq6Jyk3btCny0Ycecyc3yGXH10sizUfiHlhviCkDuESk8mFDwDDzqW -ZF0IipzFbEDHoIxLlm3GQxpiLoEV4k8KYJp3R5KBLFyxM6UGPz8h72mIPCJp2RuK -MYgF91UDvVzvnYm6TfseM2+ewKirC00GOrZ7rEcFvtxnKSqYf4ckqfNdSU1Y+RRC -1ngWZ7Ih ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIICwjCCAaqgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwFDESMBAGA1UEAwwJQyBS -b290IENBMB4XDTE2MDIyODIwMjcwM1oXDTI2MDIyNTIwMjcwM1owDzENMAsGA1UE -AwwEQiBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALsSCYmDip2D -GkjFxw7ykz26JSjELkl6ArlYjFJ3aT/SCh8qbS4gln7RH8CPBd78oFdfhIKQrwtZ -3/q21ykD9BAS3qHe2YdcJfm8/kWAy5DvXk6NXU4qX334KofBAEpgdA/igEFq1P1l -HAuIfZCpMRfT+i5WohVsGi8f/NgpRvVaMONLNfgw57mz1lbtFeBEISmX0kbsuJxF -Qj/Bwhi5/0HAEXG8e7zN4cEx0yPRvmOATRdVb/8dW2pwOHRJq9R5M0NUkIsTSnL7 -6N/z8hRAHMsV3IudC5Yd7GXW1AGu9a+iKU+Q4xcZCoj0DC99tL4VKujrV1kAeqsM -cz5/dKzi6+cCAwEAAaMjMCEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQELBQADggEBAIIeZiEeNhWWQ8Y4D+AGDwqUUeG8NjCbKrXQ -BlHg5wZ8xftFaiP1Dp/UAezmx2LNazdmuwrYB8lm3FVTyaPDTKEGIPS4wJKHgqH1 -QPDhqNm85ey7TEtI9oYjsNim/Rb+iGkIAMXaxt58SzxbjvP0kMr1JfJIZbic9vye -NwIspMFIpP3FB8ywyu0T0hWtCQgL4J47nigCHpOu58deP88fS/Nyz/fyGVWOZ76b -WhWwgM3P3X95fQ3d7oFPR/bVh0YV+Cf861INwplokXgXQ3/TCQ+HNXeAMWn3JLWv -XFwk8owk9dq/kQGdndGgy3KTEW4ctPX5GNhf3LJ9Q7dLji4ReQ4= ------END CERTIFICATE----- diff --git a/ssl/test/runner/rsa_chain_key.pem b/ssl/test/runner/rsa_chain_key.pem deleted file mode 100644 index d94d704422..0000000000 --- a/ssl/test/runner/rsa_chain_key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDRvaz8CC/cshpC -afJo4jLkHEoBqDLhdgFelJoAiQUyIqyWl2O7YHPnpJH+TgR7oelzNzt/kLRcH89M -/TszB6zqyLTC4aqmvzKL0peD/jL2LWBucR0WXIvjA3zoRuF/x86+rYH3tHb+xs2P -Ss8EGL/Ev+ss+qTzTGEn26fuGNHkNw6tOwPpc+o8+wUtzf/kAthamo+cIDs2rQ+l -P7+aLZTLeU/q4gcLutlzcK5imex5xy2jPkweq48kijK0kIzl1cPlA5d1z7C8jU50 -Pj9X9sQDJTN32j7UYRisJeeYQF8GaaN8SbrDI6zHgKzrRLyxDt/KQa9ViLeXANgZ -i+Xx9KgfAgMBAAECggEBAK0VjSJzkyPaamcyTVSWjo7GdaBGcK60lk657RjR+lK0 -YJ7pkej4oM2hdsVZFsP8Cs4E33nXLa/0pDsRov/qrp0WQm2skwqGMC1I/bZ0WRPk -wHaDrBBfESWnJDX/AGpVtlyOjPmgmK6J2usMPihQUDkKdAYrVWJePrMIxt1q6BMe -iczs3qriMmtY3bUc4UyUwJ5fhDLjshHvfuIpYQyI6EXZM6dZksn9LylXJnigY6QJ -HxOYO0BDwOsZ8yQ8J8afLk88i0GizEkgE1z3REtQUwgWfxr1WV/ud+T6/ZhSAgH9 -042mQvSFZnIUSEsmCvjhWuAunfxHKCTcAoYISWfzWpkCgYEA7gpf3HHU5Tn+CgUn -1X5uGpG3DmcMgfeGgs2r2f/IIg/5Ac1dfYILiybL1tN9zbyLCJfcbFpWBc9hJL6f -CPc5hUiwWFJqBJewxQkC1Ae/HakHbip+IZ+Jr0842O4BAArvixk4Lb7/N2Ct9sTE -NJO6RtK9lbEZ5uK61DglHy8CS2UCgYEA4ZC1o36kPAMQBggajgnucb2yuUEelk0f -AEr+GI32MGE+93xMr7rAhBoqLg4AITyIfEnOSQ5HwagnIHonBbv1LV/Gf9ursx8Z -YOGbvT8zzzC+SU1bkDzdjAYnFQVGIjMtKOBJ3K07++ypwX1fr4QsQ8uKL8WSOWwt -Z3Bym6XiZzMCgYADnhy+2OwHX85AkLt+PyGlPbmuelpyTzS4IDAQbBa6jcuW/2wA -UE2km75VUXmD+u2R/9zVuLm99NzhFhSMqlUxdV1YukfqMfP5yp1EY6m/5aW7QuIP -2MDa7TVL9rIFMiVZ09RKvbBbQxjhuzPQKL6X/PPspnhiTefQ+dl2k9xREQKBgHDS -fMfGNEeAEKezrfSVqxphE9/tXms3L+ZpnCaT+yu/uEr5dTIAawKoQ6i9f/sf1/Sy -xedsqR+IB+oKrzIDDWMgoJybN4pkZ8E5lzhVQIjFjKgFdWLzzqyW9z1gYfABQPlN -FiS20WX0vgP1vcKAjdNrHzc9zyHBpgQzDmAj3NZZAoGBAI8vKCKdH7w3aL5CNkZQ -2buIeWNA2HZazVwAGG5F2TU/LmXfRKnG6dX5bkU+AkBZh56jNZy//hfFSewJB4Kk -buB7ERSdaNbO21zXt9FEA3+z0RfMd/Zv2vlIWOSB5nzl/7UKti3sribK6s9ZVLfi -SxpiPQ8d/hmSGwn4ksrWUsJD ------END PRIVATE KEY----- diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go index 22674bd67c..9d53ab6fbc 100644 --- a/ssl/test/runner/runner.go +++ b/ssl/test/runner/runner.go @@ -18,11 +18,13 @@ import ( "bytes" "crypto" "crypto/ecdsa" + "crypto/ed25519" "crypto/elliptic" "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" + _ "embed" "encoding/base64" "encoding/binary" "encoding/hex" @@ -36,7 +38,6 @@ import ( "net" "os" "os/exec" - "path" "path/filepath" "runtime" "strconv" @@ -69,7 +70,6 @@ var ( shimPath = flag.String("shim-path", "../../../build/ssl/test/bssl_shim", "The location of the shim binary.") shimExtraFlags = flag.String("shim-extra-flags", "", "Semicolon-separated extra flags to pass to the shim binary on each invocation.") handshakerPath = flag.String("handshaker-path", "../../../build/ssl/test/handshaker", "The location of the handshaker binary.") - resourceDir = flag.String("resource-dir", ".", "The directory in which to find certificate and key files.") fuzzer = flag.Bool("fuzzer", false, "If true, tests against a BoringSSL built in fuzzer mode.") transcriptDir = flag.String("transcript-dir", "", "The directory in which to write transcripts.") idleTimeout = flag.Duration("idle-timeout", 15*time.Second, "The number of seconds to wait for a read or write to bssl_shim.") @@ -117,110 +117,93 @@ var shimConfig ShimConfiguration = ShimConfiguration{ HalfRTTTickets: 2, } -type testCert int +//go:embed rsa_2048_key.pem +var rsa2048KeyPEM []byte -const ( - testCertRSA testCert = iota - testCertRSA1024 - testCertRSAChain - testCertECDSAP224 - testCertECDSAP256 - testCertECDSAP384 - testCertECDSAP521 - testCertEd25519 -) +//go:embed rsa_1024_key.pem +var rsa1024KeyPEM []byte -const ( - rsaCertificateFile = "cert.pem" - rsa1024CertificateFile = "rsa_1024_cert.pem" - rsaChainCertificateFile = "rsa_chain_cert.pem" - ecdsaP224CertificateFile = "ecdsa_p224_cert.pem" - ecdsaP256CertificateFile = "ecdsa_p256_cert.pem" - ecdsaP384CertificateFile = "ecdsa_p384_cert.pem" - ecdsaP521CertificateFile = "ecdsa_p521_cert.pem" - ed25519CertificateFile = "ed25519_cert.pem" -) +//go:embed ecdsa_p224_key.pem +var ecdsaP224KeyPEM []byte -const ( - rsaKeyFile = "key.pem" - rsa1024KeyFile = "rsa_1024_key.pem" - rsaChainKeyFile = "rsa_chain_key.pem" - ecdsaP224KeyFile = "ecdsa_p224_key.pem" - ecdsaP256KeyFile = "ecdsa_p256_key.pem" - ecdsaP384KeyFile = "ecdsa_p384_key.pem" - ecdsaP521KeyFile = "ecdsa_p521_key.pem" - ed25519KeyFile = "ed25519_key.pem" - channelIDKeyFile = "channel_id_key.pem" -) +//go:embed ecdsa_p256_key.pem +var ecdsaP256KeyPEM []byte + +//go:embed ecdsa_p384_key.pem +var ecdsaP384KeyPEM []byte + +//go:embed ecdsa_p521_key.pem +var ecdsaP521KeyPEM []byte + +//go:embed ed25519_key.pem +var ed25519KeyPEM []byte + +//go:embed channel_id_key.pem +var channelIDKeyPEM []byte var ( - rsaCertificate Certificate - rsa1024Certificate Certificate - rsaChainCertificate Certificate - ecdsaP224Certificate Certificate - ecdsaP256Certificate Certificate - ecdsaP384Certificate Certificate - ecdsaP521Certificate Certificate - ed25519Certificate Certificate - garbageCertificate Certificate + rsa1024Key rsa.PrivateKey + rsa2048Key rsa.PrivateKey + + ecdsaP224Key ecdsa.PrivateKey + ecdsaP256Key ecdsa.PrivateKey + ecdsaP384Key ecdsa.PrivateKey + ecdsaP521Key ecdsa.PrivateKey + + ed25519Key ed25519.PrivateKey + + channelIDKey ecdsa.PrivateKey ) -var testCerts = []struct { - id testCert - certFile, keyFile string - cert *Certificate -}{ - { - id: testCertRSA, - certFile: rsaCertificateFile, - keyFile: rsaKeyFile, - cert: &rsaCertificate, - }, - { - id: testCertRSA1024, - certFile: rsa1024CertificateFile, - keyFile: rsa1024KeyFile, - cert: &rsa1024Certificate, - }, - { - id: testCertRSAChain, - certFile: rsaChainCertificateFile, - keyFile: rsaChainKeyFile, - cert: &rsaChainCertificate, - }, - { - id: testCertECDSAP224, - certFile: ecdsaP224CertificateFile, - keyFile: ecdsaP224KeyFile, - cert: &ecdsaP224Certificate, - }, - { - id: testCertECDSAP256, - certFile: ecdsaP256CertificateFile, - keyFile: ecdsaP256KeyFile, - cert: &ecdsaP256Certificate, - }, - { - id: testCertECDSAP384, - certFile: ecdsaP384CertificateFile, - keyFile: ecdsaP384KeyFile, - cert: &ecdsaP384Certificate, - }, - { - id: testCertECDSAP521, - certFile: ecdsaP521CertificateFile, - keyFile: ecdsaP521KeyFile, - cert: &ecdsaP521Certificate, - }, - { - id: testCertEd25519, - certFile: ed25519CertificateFile, - keyFile: ed25519KeyFile, - cert: &ed25519Certificate, - }, +var channelIDKeyPath string + +func initKeys() { + // Since key generation is not particularly cheap (especially RSA), and the + // runner is intended to run on systems which may be resouece constrained, + // we load keys from disk instead of dynamically generating them. We treat + // key files the same as dynamically generated certificates, writing them + // out to temporary files before passing them to the shim. + + for _, k := range []struct { + pemBytes []byte + key *rsa.PrivateKey + }{ + {rsa1024KeyPEM, &rsa1024Key}, + {rsa2048KeyPEM, &rsa2048Key}, + } { + key, err := loadPEMKey(k.pemBytes) + if err != nil { + panic(fmt.Sprintf("failed to load RSA test key: %s", err)) + } + *k.key = *(key.(*rsa.PrivateKey)) + } + + for _, k := range []struct { + pemBytes []byte + key *ecdsa.PrivateKey + }{ + {ecdsaP224KeyPEM, &ecdsaP224Key}, + {ecdsaP256KeyPEM, &ecdsaP256Key}, + {ecdsaP384KeyPEM, &ecdsaP384Key}, + {ecdsaP521KeyPEM, &ecdsaP521Key}, + {channelIDKeyPEM, &channelIDKey}, + } { + key, err := loadPEMKey(k.pemBytes) + if err != nil { + panic(fmt.Sprintf("failed to load ECDSA test key: %s", err)) + } + *k.key = *(key.(*ecdsa.PrivateKey)) + } + + k, err := loadPEMKey(ed25519KeyPEM) + if err != nil { + panic(fmt.Sprintf("failed to load Ed25519 test key: %s", err)) + } + ed25519Key = k.(ed25519.PrivateKey) + + channelIDKeyPath = writeTempKeyFile(&channelIDKey) } -var channelIDKey *ecdsa.PrivateKey var channelIDBytes []byte var testOCSPResponse = []byte{1, 2, 3, 4} @@ -231,31 +214,32 @@ var testSCTList2 = []byte{0, 6, 0, 4, 1, 2, 3, 4} var testOCSPExtension = append([]byte{byte(extensionStatusRequest) >> 8, byte(extensionStatusRequest), 0, 8, statusTypeOCSP, 0, 0, 4}, testOCSPResponse...) var testSCTExtension = append([]byte{byte(extensionSignedCertificateTimestamp) >> 8, byte(extensionSignedCertificateTimestamp), 0, byte(len(testSCTList))}, testSCTList...) -func initCertificates() { - for i := range testCerts { - cert, err := LoadX509KeyPair(path.Join(*resourceDir, testCerts[i].certFile), path.Join(*resourceDir, testCerts[i].keyFile)) - if err != nil { - panic(err) - } - cert.OCSPStaple = testOCSPResponse - cert.SignedCertificateTimestampList = testSCTList - *testCerts[i].cert = cert - } +var ( + rsaCertificate CertificateChain + rsaChainCertificate CertificateChain + rsa1024Certificate CertificateChain + ecdsaP224Certificate CertificateChain + ecdsaP256Certificate CertificateChain + ecdsaP384Certificate CertificateChain + ecdsaP521Certificate CertificateChain + ed25519Certificate CertificateChain + garbageCertificate CertificateChain +) - channelIDPEMBlock, err := os.ReadFile(path.Join(*resourceDir, channelIDKeyFile)) - if err != nil { - panic(err) - } - channelIDDERBlock, _ := pem.Decode(channelIDPEMBlock) - if channelIDDERBlock.Type != "EC PRIVATE KEY" { - panic("bad key type") - } - channelIDKey, err = x509.ParseECPrivateKey(channelIDDERBlock.Bytes) - if err != nil { - panic(err) - } - if channelIDKey.Curve != elliptic.P256() { - panic("bad curve") +func initCertificates() { + for _, def := range []struct { + key crypto.Signer + out *CertificateChain + }{ + {&rsa1024Key, &rsa1024Certificate}, + {&rsa2048Key, &rsaCertificate}, + {&ecdsaP224Key, &ecdsaP224Certificate}, + {&ecdsaP256Key, &ecdsaP256Certificate}, + {&ecdsaP384Key, &ecdsaP384Certificate}, + {&ecdsaP521Key, &ecdsaP521Certificate}, + {ed25519Key, &ed25519Certificate}, + } { + *def.out = generateSingleCertChain(nil, def.key, testOCSPResponse, testSCTList) } channelIDBytes = make([]byte, 64) @@ -264,6 +248,31 @@ func initCertificates() { garbageCertificate.Certificate = [][]byte{[]byte("GARBAGE")} garbageCertificate.PrivateKey = rsaCertificate.PrivateKey + + // Build a basic three cert chain for testing chain specific things. + rootTmpl := *baseCertTemplate + rootTmpl.Subject.CommonName = "test root" + rootCert := generateTestCert(&rootTmpl, nil, &rsa2048Key, testOCSPResponse, testSCTList) + intermediateTmpl := *baseCertTemplate + intermediateTmpl.Subject.CommonName = "test inter" + intermediateCert := generateTestCert(&intermediateTmpl, rootCert, &rsa2048Key, testOCSPResponse, testSCTList) + leafTmpl := *baseCertTemplate + leafTmpl.IsCA, leafTmpl.BasicConstraintsValid = false, false + leafCert := generateTestCert(nil, intermediateCert, &rsa2048Key, testOCSPResponse, testSCTList) + + keyPath := writeTempKeyFile(&rsa2048Key) + rootCertPath, chainPath := writeTempCertFile([]*x509.Certificate{rootCert}), writeTempCertFile([]*x509.Certificate{leafCert, intermediateCert}) + + rsaChainCertificate = CertificateChain{ + Certificate: [][]byte{leafCert.Raw, intermediateCert.Raw}, + PrivateKey: &rsa2048Key, + OCSPStaple: testOCSPResponse, + SignedCertificateTimestampList: testSCTList, + Leaf: leafCert, + ChainPath: chainPath, + KeyPath: keyPath, + RootPath: rootCertPath, + } } func flagInts(flagName string, vals []int) []string { @@ -292,38 +301,27 @@ type delegatedCredentialConfig struct { // dcAlgo is the signature scheme that should be used with this delegated // credential. If zero, ECDSA with P-256 is assumed. dcAlgo signatureAlgorithm - // tlsVersion is the version of TLS that should be used with this delegated - // credential. If zero, TLS 1.3 is assumed. - tlsVersion uint16 // algo is the signature algorithm that the delegated credential itself is // signed with. Cannot be zero. algo signatureAlgorithm } -func loadRSAPrivateKey(filename string) (priv *rsa.PrivateKey, privPKCS8 []byte, err error) { - pemPath := path.Join(*resourceDir, filename) - pemBytes, err := os.ReadFile(pemPath) - if err != nil { - return nil, nil, err - } - +func loadPEMKey(pemBytes []byte) (crypto.PrivateKey, error) { block, _ := pem.Decode(pemBytes) if block == nil { - return nil, nil, fmt.Errorf("no PEM block found in %q", pemPath) + return nil, fmt.Errorf("no PEM block found") } - privPKCS8 = block.Bytes - parsed, err := x509.ParsePKCS8PrivateKey(privPKCS8) - if err != nil { - return nil, nil, fmt.Errorf("failed to parse PKCS#8 key from %q", pemPath) + if block.Type != "PRIVATE KEY" { + return nil, fmt.Errorf("unexpected PEM type (expected \"PRIVATE KEY\"): %s", block.Type) } - priv, ok := parsed.(*rsa.PrivateKey) - if !ok { - return nil, nil, fmt.Errorf("found %T in %q rather than an RSA private key", parsed, pemPath) + k, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + return nil, fmt.Errorf("failed to parse PKCS#8 key: %s", err) } - return priv, privPKCS8, nil + return k, nil } func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byte, parentPriv crypto.PrivateKey) (dc, privPKCS8 []uint8, err error) { @@ -336,14 +334,12 @@ func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byt switch dcAlgo { case signatureRSAPKCS1WithMD5, signatureRSAPKCS1WithSHA1, signatureRSAPKCS1WithSHA256, signatureRSAPKCS1WithSHA384, signatureRSAPKCS1WithSHA512, signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA384, signatureRSAPSSWithSHA512: - // RSA keys are expensive to generate so load from disk instead. - var priv *rsa.PrivateKey - if priv, privPKCS8, err = loadRSAPrivateKey(rsaKeyFile); err != nil { + pub = &rsa2048Key.PublicKey + privPKCS8, err = x509.MarshalPKCS8PrivateKey(&rsa2048Key) + if err != nil { return nil, nil, err } - pub = &priv.PublicKey - case signatureECDSAWithSHA1, signatureECDSAWithP256AndSHA256, signatureECDSAWithP384AndSHA384, signatureECDSAWithP521AndSHA512: var curve elliptic.Curve switch dcAlgo { @@ -380,14 +376,6 @@ func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byt if lifetimeSecs > 1<<32 { return nil, nil, fmt.Errorf("lifetime %s is too long to be expressed", lifetime) } - tlsVersion := config.tlsVersion - if tlsVersion == 0 { - tlsVersion = VersionTLS13 - } - - if tlsVersion < VersionTLS13 { - return nil, nil, fmt.Errorf("delegated credentials require TLS 1.3") - } // https://www.rfc-editor.org/rfc/rfc9345.html#section-4 dc = append(dc, byte(lifetimeSecs>>24), byte(lifetimeSecs>>16), byte(lifetimeSecs>>8), byte(lifetimeSecs)) @@ -402,12 +390,7 @@ func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byt dc = append(dc, pubBytes...) var dummyConfig Config - parentSigner, err := getSigner(tlsVersion, parentPriv, &dummyConfig, config.algo, false /* not for verification */) - if err != nil { - return nil, nil, err - } - - parentSignature, err := parentSigner.signMessage(parentPriv, &dummyConfig, delegatedCredentialSignedMessage(dc, config.algo, parentDER)) + parentSignature, err := signMessage(VersionTLS13, parentPriv, &dummyConfig, config.algo, delegatedCredentialSignedMessage(dc, config.algo, parentDER)) if err != nil { return nil, nil, err } @@ -419,33 +402,6 @@ func createDelegatedCredential(config delegatedCredentialConfig, parentDER []byt return dc, privPKCS8, nil } -func getRunnerCertificate(t testCert) Certificate { - for _, cert := range testCerts { - if cert.id == t { - return *cert.cert - } - } - panic("Unknown test certificate") -} - -func getShimCertificate(t testCert) string { - for _, cert := range testCerts { - if cert.id == t { - return cert.certFile - } - } - panic("Unknown test certificate") -} - -func getShimKey(t testCert) string { - for _, cert := range testCerts { - if cert.id == t { - return cert.keyFile - } - } - panic("Unknown test certificate") -} - // recordVersionToWire maps a record-layer protocol version to its wire // representation. func recordVersionToWire(vers uint16, protocol protocol) uint16 { @@ -569,7 +525,7 @@ type connectionExpectations struct { curveID CurveID // peerCertificate, if not nil, is the certificate chain the peer is // expected to send. - peerCertificate *Certificate + peerCertificate *CertificateChain // quicTransportParams contains the QUIC transport parameters that are to be // sent by the peer using codepoint 57. quicTransportParams []byte @@ -608,10 +564,6 @@ type testCase struct { messageLen int // messageCount is the number of test messages that will be sent. messageCount int - // certFile is the path to the certificate to use for the server. - certFile string - // keyFile is the path to the private key to use for the server. - keyFile string // resumeSession controls whether a second connection should be tested // which attempts to resume the first session. resumeSession bool @@ -733,6 +685,9 @@ type testCase struct { // skipVersionNameCheck, if true, will skip the consistency check between // test name and the versions. skipVersionNameCheck bool + // shimCertificate, if populated, is the certificate/chain which should be sent + // by the server/client (this populates the -cert-file and -key-file flags). + shimCertificate *CertificateChain } func (t *testCase) MarshalJSON() ([]byte, error) { @@ -805,17 +760,14 @@ func doExchange(test *testCase, config *Config, conn net.Conn, isResume bool, tr config.ServerSessionCache = NewLRUServerSessionCache(1) } } - if test.testType == clientTest { - if len(config.Certificates) == 0 { - config.Certificates = []Certificate{rsaCertificate} - } - } else { + if test.testType != clientTest { // Supply a ServerName to ensure a constant session cache key, // rather than falling back to net.Conn.RemoteAddr. if len(config.ServerName) == 0 { config.ServerName = "test" } } + if *fuzzer { config.Bugs.NullAllCiphers = true } @@ -1430,6 +1382,9 @@ func doExchanges(test *testCase, shim *shimProcess, resumeCount int, transcripts if test.resumeConfig != nil { resumeConfig = *test.resumeConfig resumeConfig.Rand = config.Rand + if resumeConfig.Chains == nil { + resumeConfig.Chains = config.Chains + } } else { resumeConfig = config } @@ -1503,20 +1458,14 @@ func runTest(dispatcher *shimDispatcher, statusChan chan statusMsg, test *testCa } if test.testType == serverTest { flags = append(flags, "-server") + } - flags = append(flags, "-key-file") - if test.keyFile == "" { - flags = append(flags, path.Join(*resourceDir, rsaKeyFile)) - } else { - flags = append(flags, path.Join(*resourceDir, test.keyFile)) - } - - flags = append(flags, "-cert-file") - if test.certFile == "" { - flags = append(flags, path.Join(*resourceDir, rsaCertificateFile)) - } else { - flags = append(flags, path.Join(*resourceDir, test.certFile)) - } + if test.shimCertificate != nil { + flags = append(flags, "-key-file", test.shimCertificate.KeyPath) + flags = append(flags, "-cert-file", test.shimCertificate.ChainPath) + } else if test.testType == serverTest { + flags = append(flags, "-key-file", rsaCertificate.KeyPath) + flags = append(flags, "-cert-file", rsaCertificate.ChainPath) } if test.protocol == dtls { @@ -1687,6 +1636,19 @@ func runTest(dispatcher *shimDispatcher, statusChan chan statusMsg, test *testCa flags = append(flags, "-write-settings", transcriptPrefix) } + if test.testType == clientTest { + if len(test.config.Chains) == 0 { + test.config.Chains = []CertificateChain{rsaCertificate} + } + + rootFiles := make([]string, 0, len(test.config.Chains)) + for _, c := range test.config.Chains { + rootFiles = append(rootFiles, c.RootPath) + } + + flags = append(flags, "-trust-cert", strings.Join(rootFiles, ",")) + } + flags = append(flags, test.flags...) var env []string @@ -2223,14 +2185,14 @@ read alert 1 0 testType: serverTest, name: "ServerSkipCertificateVerify", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaChainCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ SkipCertificateVerify: true, }, }, expectations: connectionExpectations{ - peerCertificate: &rsaChainCertificate, + peerCertificate: &rsaCertificate, }, flags: []string{ "-require-any-client-certificate", @@ -3753,14 +3715,14 @@ read alert 1 0 testCases = append(testCases, testCase{ name: "LargeMessage", config: Config{ - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, }, }) testCases = append(testCases, testCase{ protocol: dtls, name: "LargeMessage-DTLS", config: Config{ - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, }, }) @@ -3768,7 +3730,7 @@ read alert 1 0 testCases = append(testCases, testCase{ name: "LargeMessage-Reject", config: Config{ - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, }, flags: []string{"-max-cert-list", "16384"}, shouldFail: true, @@ -3778,7 +3740,7 @@ read alert 1 0 protocol: dtls, name: "LargeMessage-Reject-DTLS", config: Config{ - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, }, flags: []string{"-max-cert-list", "16384"}, shouldFail: true, @@ -3826,17 +3788,11 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto } prefix := protocol.String() + "-" - var cert Certificate - var certFile string - var keyFile string + var cert CertificateChain if hasComponent(suite.name, "ECDSA") { cert = ecdsaP256Certificate - certFile = ecdsaP256CertificateFile - keyFile = ecdsaP256KeyFile } else { cert = rsaCertificate - certFile = rsaCertificateFile - keyFile = rsaKeyFile } var flags []string @@ -3880,15 +3836,14 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto MinVersion: ver.version, MaxVersion: ver.version, CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, Bugs: ProtocolBugs{ AdvertiseAllConfiguredCiphers: true, }, }, - certFile: certFile, - keyFile: keyFile, + shimCertificate: &cert, flags: flags, resumeSession: true, shouldFail: shouldFail, @@ -3904,7 +3859,7 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto MinVersion: ver.version, MaxVersion: ver.version, CipherSuites: serverCipherSuites, - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, Bugs: ProtocolBugs{ @@ -3931,7 +3886,7 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto MinVersion: ver.version, MaxVersion: ver.version, CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, }, @@ -3958,7 +3913,7 @@ func addTestForCipherSuite(suite testCipherSuite, ver tlsVersion, protocol proto MinVersion: ver.version, MaxVersion: ver.version, CipherSuites: []uint16{suite.id}, - Certificates: []Certificate{cert}, + Chains: []CertificateChain{cert}, PreSharedKey: []byte(psk), PreSharedKeyIdentity: pskIdentity, }, @@ -4098,7 +4053,7 @@ func addCipherSuiteTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ SendCipherSuite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, }, @@ -4111,7 +4066,7 @@ func addCipherSuiteTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, Bugs: ProtocolBugs{ SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, }, @@ -4124,7 +4079,7 @@ func addCipherSuiteTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ed25519Certificate}, + Chains: []CertificateChain{ed25519Certificate}, Bugs: ProtocolBugs{ SendCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, }, @@ -4142,12 +4097,9 @@ func addCipherSuiteTests() { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - shouldFail: true, - expectedError: ":NO_SHARED_CIPHER:", + shimCertificate: &rsaCertificate, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", }) testCases = append(testCases, testCase{ testType: serverTest, @@ -4156,12 +4108,9 @@ func addCipherSuiteTests() { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, - shouldFail: true, - expectedError: ":NO_SHARED_CIPHER:", + shimCertificate: &ecdsaP256Certificate, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", }) testCases = append(testCases, testCase{ testType: serverTest, @@ -4170,12 +4119,9 @@ func addCipherSuiteTests() { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ed25519CertificateFile), - "-key-file", path.Join(*resourceDir, ed25519KeyFile), - }, - shouldFail: true, - expectedError: ":NO_SHARED_CIPHER:", + shimCertificate: &ed25519Certificate, + shouldFail: true, + expectedError: ":NO_SHARED_CIPHER:", }) // Test cipher suite negotiation works as expected. Configure a @@ -4299,7 +4245,7 @@ func addBadECDSASignatureTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, Bugs: ProtocolBugs{ BadECDSAR: badR, BadECDSAS: badS, @@ -4311,8 +4257,8 @@ func addBadECDSASignatureTests() { testCases = append(testCases, testCase{ name: fmt.Sprintf("BadECDSA-%d-%d-TLS13", badR, badS), config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{ecdsaP256Certificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{ecdsaP256Certificate}, Bugs: ProtocolBugs{ BadECDSAR: badR, BadECDSAS: badS, @@ -4419,7 +4365,7 @@ func addCBCSplittingTests() { func addClientAuthTests() { // Add a dummy cert pool to stress certificate authority parsing. certPool := x509.NewCertPool() - for _, cert := range []Certificate{rsaCertificate, rsa1024Certificate} { + for _, cert := range []CertificateChain{rsaCertificate, rsa1024Certificate} { cert, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { panic(err) @@ -4438,18 +4384,15 @@ func addClientAuthTests() { ClientAuth: RequireAnyClientCert, ClientCAs: certPool, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) testCases = append(testCases, testCase{ testType: serverTest, name: ver.name + "-Server-ClientAuth-RSA", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{"-require-any-client-certificate"}, }) @@ -4457,9 +4400,9 @@ func addClientAuthTests() { testType: serverTest, name: ver.name + "-Server-ClientAuth-ECDSA", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{ecdsaP256Certificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{ecdsaP256Certificate}, }, flags: []string{"-require-any-client-certificate"}, }) @@ -4472,10 +4415,7 @@ func addClientAuthTests() { ClientAuth: RequireAnyClientCert, ClientCAs: certPool, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, }) testCases = append(testCases, testCase{ @@ -4577,7 +4517,7 @@ func addClientAuthTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, expectations: connectionExpectations{ channelID: true, @@ -4592,9 +4532,9 @@ func addClientAuthTests() { testType: serverTest, name: ver.name + "-Server-CertReq-CA-List", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ ExpectCertificateReqNames: caNames, }, @@ -4609,15 +4549,14 @@ func addClientAuthTests() { testType: clientTest, name: ver.name + "-Client-CertReq-CA-List", config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, - ClientAuth: RequireAnyClientCert, - ClientCAs: certPool, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, + ClientAuth: RequireAnyClientCert, + ClientCAs: certPool, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-expect-client-ca-list", encodeDERValues(caNames), }, }) @@ -4633,9 +4572,8 @@ func addClientAuthTests() { PreSharedKey: []byte("secret"), ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-psk", "secret", }, shouldFail: true, @@ -4650,9 +4588,8 @@ func addClientAuthTests() { PreSharedKey: []byte("secret"), ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-psk", "secret", }, shouldFail: true, @@ -4665,8 +4602,8 @@ func addClientAuthTests() { testType: serverTest, name: "Null-Client-CA-List", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ ExpectCertificateReqNames: [][]byte{}, }, @@ -4682,8 +4619,8 @@ func addClientAuthTests() { testType: serverTest, name: "TLS13-Empty-Client-CA-List", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ ExpectNoCertificateAuthoritiesExtension: true, }, @@ -5197,10 +5134,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) } tests = append(tests, testCase{ @@ -5210,10 +5144,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) if config.protocol != quic { tests = append(tests, testCase{ @@ -5223,10 +5154,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, }) } tests = append(tests, testCase{ @@ -5236,10 +5164,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, }) if config.protocol != quic { tests = append(tests, testCase{ @@ -5269,9 +5194,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-use-old-client-cert-callback", }, }) @@ -5283,9 +5207,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-use-old-client-cert-callback", }, }) @@ -5294,8 +5217,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: serverTest, name: "ClientAuth-Server", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{"-require-any-client-certificate"}, }) @@ -5304,8 +5227,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: serverTest, name: "ClientAuth-Server-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{"-require-any-client-certificate"}, }) @@ -5319,10 +5242,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) tests = append(tests, testCase{ testType: serverTest, @@ -5331,10 +5251,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) tests = append(tests, testCase{ testType: serverTest, @@ -5343,10 +5260,7 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, }) tests = append(tests, testCase{ testType: serverTest, @@ -5355,9 +5269,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, }, + shimCertificate: &ed25519Certificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, ed25519CertificateFile), - "-key-file", path.Join(*resourceDir, ed25519KeyFile), "-verify-prefs", strconv.Itoa(int(signatureEd25519)), }, }) @@ -5440,8 +5353,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: clientTest, name: "ClientOCSPCallback-Pass-" + vers.name, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-enable-ocsp-stapling", @@ -5458,8 +5371,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: clientTest, name: "ClientOCSPCallback-Fail-" + vers.name, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-enable-ocsp-stapling", @@ -5478,8 +5391,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: clientTest, name: "ClientOCSPCallback-FailNoStaple-" + vers.name, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{certNoStaple}, + MaxVersion: vers.version, + Chains: []CertificateChain{certNoStaple}, }, flags: []string{ "-enable-ocsp-stapling", @@ -5588,8 +5501,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: testType, name: "CertificateVerificationSucceed" + suffix, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: append([]string{"-expect-verify-result"}, flags...), resumeSession: true, @@ -5598,8 +5511,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: testType, name: "CertificateVerificationFail" + suffix, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: append([]string{"-verify-fail"}, flags...), shouldFail: true, @@ -5611,8 +5524,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: testType, name: "CertificateVerificationDoesNotFailOnResume" + suffix, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: append([]string{"-on-resume-verify-fail"}, flags...), resumeSession: true, @@ -5622,8 +5535,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: testType, name: "CertificateVerificationFailsOnResume" + suffix, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: append([]string{ "-on-resume-verify-fail", @@ -5638,8 +5551,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: testType, name: "CertificateVerificationPassesOnResume" + suffix, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: append([]string{ "-reverify-on-resume", @@ -5769,8 +5682,8 @@ func addStateMachineCoverageTests(config stateMachineTestConfig) { testType: clientTest, name: "CertificateVerificationSoftFail-" + vers.name, config: Config{ - MaxVersion: vers.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: vers.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-verify-fail", @@ -5967,7 +5880,7 @@ read alert 1 0 NextProtos: []string{"foo"}, }, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, "-select-next-proto", "foo", }, resumeSession: true, @@ -5982,7 +5895,7 @@ read alert 1 0 name: "ChannelID-NPN-Server", config: Config{ MaxVersion: VersionTLS12, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, NextProtos: []string{"bar"}, }, flags: []string{ @@ -6023,7 +5936,7 @@ read alert 1 0 MaxVersion: ver.version, RequestChannelID: true, }, - flags: []string{"-send-channel-id", path.Join(*resourceDir, channelIDKeyFile)}, + flags: []string{"-send-channel-id", channelIDKeyPath}, resumeSession: true, expectations: connectionExpectations{ channelID: true, @@ -6036,7 +5949,7 @@ read alert 1 0 name: "ChannelID-Server-" + ver.name, config: Config{ MaxVersion: ver.version, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, flags: []string{ "-expect-channel-id", @@ -6053,7 +5966,7 @@ read alert 1 0 name: "InvalidChannelIDSignature-" + ver.name, config: Config{ MaxVersion: ver.version, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, Bugs: ProtocolBugs{ InvalidChannelIDSignature: true, }, @@ -6071,7 +5984,7 @@ read alert 1 0 config: Config{ MaxVersion: ver.version, CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, expectations: connectionExpectations{ channelID: false, @@ -6086,7 +5999,7 @@ read alert 1 0 config: Config{ MaxVersion: ver.version, CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, expectations: connectionExpectations{ channelID: false, @@ -8620,7 +8533,7 @@ func addExtensionTests() { resumeSession: true, }) - emptySCTListCert := *testCerts[0].cert + emptySCTListCert := rsaCertificate emptySCTListCert.SignedCertificateTimestampList = []byte{0, 0} // Test empty SCT list. @@ -8629,8 +8542,8 @@ func addExtensionTests() { name: "SignedCertificateTimestampListEmpty-Client-" + suffix, testType: clientTest, config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{emptySCTListCert}, + MaxVersion: ver.version, + Chains: []CertificateChain{emptySCTListCert}, }, flags: []string{ "-enable-signed-cert-timestamps", @@ -8639,7 +8552,7 @@ func addExtensionTests() { expectedError: ":ERROR_PARSING_EXTENSION:", }) - emptySCTCert := *testCerts[0].cert + emptySCTCert := rsaCertificate emptySCTCert.SignedCertificateTimestampList = []byte{0, 6, 0, 2, 1, 2, 0, 0} // Test empty SCT in non-empty list. @@ -8648,8 +8561,8 @@ func addExtensionTests() { name: "SignedCertificateTimestampListEmptySCT-Client-" + suffix, testType: clientTest, config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{emptySCTCert}, + MaxVersion: ver.version, + Chains: []CertificateChain{emptySCTCert}, }, flags: []string{ "-enable-signed-cert-timestamps", @@ -8881,8 +8794,8 @@ func addExtensionTests() { name: "SendExtensionOnClientCertificate-TLS13", testType: serverTest, config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ SendExtensionOnCertificate: testOCSPExtension, }, @@ -8911,8 +8824,8 @@ func addExtensionTests() { testCases = append(testCases, testCase{ name: "IgnoreExtensionsOnIntermediates-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaChainCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaChainCertificate}, Bugs: ProtocolBugs{ // Send different values on the intermediate. This tests // the intermediate's extensions do not override the @@ -8943,9 +8856,8 @@ func addExtensionTests() { ExpectNoExtensionsOnIntermediate: true, }, }, + shimCertificate: &rsaChainCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), - "-key-file", path.Join(*resourceDir, rsaChainKeyFile), "-ocsp-response", base64FlagValue(testOCSPResponse), "-signed-cert-timestamps", @@ -8960,9 +8872,8 @@ func addExtensionTests() { MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-ocsp-response", base64FlagValue(testOCSPResponse), "-signed-cert-timestamps", @@ -9975,8 +9886,8 @@ func addRenegotiationTests() { testCases = append(testCases, testCase{ name: "Renegotiation-CertificateChange", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ RenegotiationCertificate: &rsaChainCertificate, }, @@ -9989,8 +9900,8 @@ func addRenegotiationTests() { testCases = append(testCases, testCase{ name: "Renegotiation-CertificateChange-2", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ RenegotiationCertificate: &rsa1024Certificate, }, @@ -10099,30 +10010,30 @@ func addDTLSReplayTests() { var testSignatureAlgorithms = []struct { name string id signatureAlgorithm - cert testCert + cert *CertificateChain // If non-zero, the curve that must be supported in TLS 1.2 for cert to be // accepted. curve CurveID }{ - {"RSA_PKCS1_SHA1", signatureRSAPKCS1WithSHA1, testCertRSA, 0}, - {"RSA_PKCS1_SHA256", signatureRSAPKCS1WithSHA256, testCertRSA, 0}, - {"RSA_PKCS1_SHA384", signatureRSAPKCS1WithSHA384, testCertRSA, 0}, - {"RSA_PKCS1_SHA512", signatureRSAPKCS1WithSHA512, testCertRSA, 0}, - {"ECDSA_SHA1", signatureECDSAWithSHA1, testCertECDSAP256, CurveP256}, + {"RSA_PKCS1_SHA1", signatureRSAPKCS1WithSHA1, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA256", signatureRSAPKCS1WithSHA256, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA384", signatureRSAPKCS1WithSHA384, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA512", signatureRSAPKCS1WithSHA512, &rsaCertificate, 0}, + {"ECDSA_SHA1", signatureECDSAWithSHA1, &ecdsaP256Certificate, CurveP256}, // The “P256” in the following line is not a mistake. In TLS 1.2 the // hash function doesn't have to match the curve and so the same // signature algorithm works with P-224. - {"ECDSA_P224_SHA256", signatureECDSAWithP256AndSHA256, testCertECDSAP224, CurveP224}, - {"ECDSA_P256_SHA256", signatureECDSAWithP256AndSHA256, testCertECDSAP256, CurveP256}, - {"ECDSA_P384_SHA384", signatureECDSAWithP384AndSHA384, testCertECDSAP384, CurveP384}, - {"ECDSA_P521_SHA512", signatureECDSAWithP521AndSHA512, testCertECDSAP521, CurveP521}, - {"RSA_PSS_SHA256", signatureRSAPSSWithSHA256, testCertRSA, 0}, - {"RSA_PSS_SHA384", signatureRSAPSSWithSHA384, testCertRSA, 0}, - {"RSA_PSS_SHA512", signatureRSAPSSWithSHA512, testCertRSA, 0}, - {"Ed25519", signatureEd25519, testCertEd25519, 0}, + {"ECDSA_P224_SHA256", signatureECDSAWithP256AndSHA256, &ecdsaP224Certificate, CurveP224}, + {"ECDSA_P256_SHA256", signatureECDSAWithP256AndSHA256, &ecdsaP256Certificate, CurveP256}, + {"ECDSA_P384_SHA384", signatureECDSAWithP384AndSHA384, &ecdsaP384Certificate, CurveP384}, + {"ECDSA_P521_SHA512", signatureECDSAWithP521AndSHA512, &ecdsaP521Certificate, CurveP521}, + {"RSA_PSS_SHA256", signatureRSAPSSWithSHA256, &rsaCertificate, 0}, + {"RSA_PSS_SHA384", signatureRSAPSSWithSHA384, &rsaCertificate, 0}, + {"RSA_PSS_SHA512", signatureRSAPSSWithSHA512, &rsaCertificate, 0}, + {"Ed25519", signatureEd25519, &ed25519Certificate, 0}, // Tests for key types prior to TLS 1.2. - {"RSA", 0, testCertRSA, 0}, - {"ECDSA", 0, testCertECDSAP256, CurveP256}, + {"RSA", 0, &rsaCertificate, 0}, + {"ECDSA", 0, &ecdsaP256Certificate, CurveP256}, } const fakeSigAlg1 signatureAlgorithm = 0x2a01 @@ -10165,7 +10076,7 @@ func addSignatureAlgorithmTests() { } // SHA-224 has been removed from TLS 1.3 and, in 1.3, // the curve has to match the hash size. - if ver.version >= VersionTLS13 && alg.cert == testCertECDSAP224 { + if ver.version >= VersionTLS13 && alg.curve == CurveP224 { shouldFail = true } @@ -10215,13 +10126,8 @@ func addSignatureAlgorithmTests() { fakeSigAlg2, }, }, - flags: append( - []string{ - "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)), - "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)), - }, - curveFlags..., - ), + shimCertificate: alg.cert, + flags: curveFlags, shouldFail: shouldFail, expectedError: signError, expectedLocalError: signLocalError, @@ -10239,13 +10145,8 @@ func addSignatureAlgorithmTests() { MaxVersion: ver.version, VerifySignatureAlgorithms: allAlgorithms, }, - flags: append( - []string{ - "-cert-file", path.Join(*resourceDir, getShimCertificate(alg.cert)), - "-key-file", path.Join(*resourceDir, getShimKey(alg.cert)), - }, - curveFlags..., - ), + shimCertificate: alg.cert, + flags: curveFlags, expectations: connectionExpectations{ peerSignatureAlgorithm: alg.id, }, @@ -10273,8 +10174,8 @@ func addSignatureAlgorithmTests() { testType: testType, name: prefix + "Verify" + suffix, config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{getRunnerCertificate(alg.cert)}, + MaxVersion: ver.version, + Chains: []CertificateChain{*alg.cert}, SignSignatureAlgorithms: []signatureAlgorithm{ alg.id, }, @@ -10304,8 +10205,8 @@ func addSignatureAlgorithmTests() { testType: testType, name: prefix + "VerifyDefault" + suffix, config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{getRunnerCertificate(alg.cert)}, + MaxVersion: ver.version, + Chains: []CertificateChain{*alg.cert}, SignSignatureAlgorithms: []signatureAlgorithm{ alg.id, }, @@ -10333,8 +10234,8 @@ func addSignatureAlgorithmTests() { testType: testType, name: prefix + "InvalidSignature" + suffix, config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{getRunnerCertificate(alg.cert)}, + MaxVersion: ver.version, + Chains: []CertificateChain{*alg.cert}, SignSignatureAlgorithms: []signatureAlgorithm{ alg.id, }, @@ -10386,9 +10287,8 @@ func addSignatureAlgorithmTests() { signatureECDSAWithP256AndSHA256, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-expect-peer-verify-pref", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureEd25519)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)), @@ -10406,9 +10306,8 @@ func addSignatureAlgorithmTests() { signatureECDSAWithP256AndSHA256, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-expect-peer-verify-pref", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureEd25519)), "-expect-peer-verify-pref", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)), @@ -10429,10 +10328,7 @@ func addSignatureAlgorithmTests() { signatureECDSAWithSHA1, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA384, }, @@ -10450,10 +10346,7 @@ func addSignatureAlgorithmTests() { signatureECDSAWithSHA1, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPSSWithSHA384, }, @@ -10498,8 +10391,8 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "Verify-ClientAuth-SignatureType", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithSHA256, }, @@ -10518,8 +10411,8 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "Verify-ClientAuth-SignatureType-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, }, @@ -10579,10 +10472,7 @@ func addSignatureAlgorithmTests() { NoSignatureAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) testCases = append(testCases, testCase{ @@ -10597,10 +10487,7 @@ func addSignatureAlgorithmTests() { NoSignatureAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, }) testCases = append(testCases, testCase{ @@ -10634,10 +10521,7 @@ func addSignatureAlgorithmTests() { NoSignatureAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", @@ -10655,10 +10539,7 @@ func addSignatureAlgorithmTests() { NoSignatureAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", @@ -10676,10 +10557,7 @@ func addSignatureAlgorithmTests() { NoSignatureAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: error decoding message", @@ -10691,8 +10569,8 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "ClientAuth-Enforced", config: Config{ - MaxVersion: VersionTLS12, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithMD5, }, @@ -10724,8 +10602,8 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "ClientAuth-Enforced-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPKCS1WithMD5, }, @@ -10767,9 +10645,8 @@ func addSignatureAlgorithmTests() { signatureRSAPKCS1WithSHA1, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)), }, shouldFail: true, @@ -10785,9 +10662,8 @@ func addSignatureAlgorithmTests() { signatureRSAPSSWithSHA384, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA256)), }, shouldFail: true, @@ -10803,9 +10679,8 @@ func addSignatureAlgorithmTests() { signatureRSAPKCS1WithSHA256, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA1)), }, @@ -10822,9 +10697,8 @@ func addSignatureAlgorithmTests() { signatureRSAPKCS1WithSHA1, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA512)), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA1)), @@ -10845,10 +10719,7 @@ func addSignatureAlgorithmTests() { signatureECDSAWithSHA1, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureRSAPKCS1WithSHA256, }, @@ -10865,9 +10736,8 @@ func addSignatureAlgorithmTests() { signatureRSAPKCS1WithSHA256, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureECDSAWithP256AndSHA256)), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithSHA256)), }, @@ -10883,7 +10753,7 @@ func addSignatureAlgorithmTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, }, flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, shouldFail: true, @@ -10894,8 +10764,8 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "CheckLeafCurve-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{ecdsaP256Certificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{ecdsaP256Certificate}, }, flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, }) @@ -10906,7 +10776,7 @@ func addSignatureAlgorithmTests() { config: Config{ MaxVersion: VersionTLS12, CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP384AndSHA384, }, @@ -10917,8 +10787,8 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "ECDSACurveMismatch-Verify-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{ecdsaP256Certificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{ecdsaP256Certificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureECDSAWithP384AndSHA384, }, @@ -10942,10 +10812,7 @@ func addSignatureAlgorithmTests() { signatureECDSAWithP256AndSHA256, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), - "-key-file", path.Join(*resourceDir, ecdsaP256KeyFile), - }, + shimCertificate: &ecdsaP256Certificate, expectations: connectionExpectations{ peerSignatureAlgorithm: signatureECDSAWithP256AndSHA256, }, @@ -10962,12 +10829,9 @@ func addSignatureAlgorithmTests() { signatureRSAPSSWithSHA512, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsa1024CertificateFile), - "-key-file", path.Join(*resourceDir, rsa1024KeyFile), - }, - shouldFail: true, - expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", + shimCertificate: &rsa1024Certificate, + shouldFail: true, + expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) // Test that RSA-PSS is enabled by default for TLS 1.2. @@ -11001,8 +10865,8 @@ func addSignatureAlgorithmTests() { testType: clientTest, name: "NoEd25519-TLS11-ServerAuth-Verify", config: Config{ - MaxVersion: VersionTLS11, - Certificates: []Certificate{ed25519Certificate}, + MaxVersion: VersionTLS11, + Chains: []CertificateChain{ed25519Certificate}, Bugs: ProtocolBugs{ // Sign with Ed25519 even though it is TLS 1.1. SigningAlgorithmForLegacyVersions: signatureEd25519, @@ -11019,8 +10883,8 @@ func addSignatureAlgorithmTests() { MaxVersion: VersionTLS11, }, flags: []string{ - "-cert-file", path.Join(*resourceDir, ed25519CertificateFile), - "-key-file", path.Join(*resourceDir, ed25519KeyFile), + "-cert-file", ed25519Certificate.ChainPath, + "-key-file", ed25519Certificate.KeyPath, }, shouldFail: true, expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", @@ -11029,8 +10893,8 @@ func addSignatureAlgorithmTests() { testType: serverTest, name: "NoEd25519-TLS11-ClientAuth-Verify", config: Config{ - MaxVersion: VersionTLS11, - Certificates: []Certificate{ed25519Certificate}, + MaxVersion: VersionTLS11, + Chains: []CertificateChain{ed25519Certificate}, Bugs: ProtocolBugs{ // Sign with Ed25519 even though it is TLS 1.1. SigningAlgorithmForLegacyVersions: signatureEd25519, @@ -11050,12 +10914,9 @@ func addSignatureAlgorithmTests() { MaxVersion: VersionTLS11, ClientAuth: RequireAnyClientCert, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, ed25519CertificateFile), - "-key-file", path.Join(*resourceDir, ed25519KeyFile), - }, - shouldFail: true, - expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", + shimCertificate: &ed25519Certificate, + shouldFail: true, + expectedError: ":NO_COMMON_SIGNATURE_ALGORITHMS:", }) // Test Ed25519 is not advertised by default. @@ -11063,7 +10924,7 @@ func addSignatureAlgorithmTests() { testType: clientTest, name: "Ed25519DefaultDisable-NoAdvertise", config: Config{ - Certificates: []Certificate{ed25519Certificate}, + Chains: []CertificateChain{ed25519Certificate}, }, shouldFail: true, expectedLocalError: "tls: no common signature algorithms", @@ -11075,7 +10936,7 @@ func addSignatureAlgorithmTests() { testType: clientTest, name: "Ed25519DefaultDisable-NoAccept", config: Config{ - Certificates: []Certificate{ed25519Certificate}, + Chains: []CertificateChain{ed25519Certificate}, Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, }, @@ -11090,7 +10951,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "VerifyPreferences-Advertised", config: Config{ - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA384, @@ -11108,7 +10969,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "VerifyPreferences-NoCommonAlgorithms", config: Config{ - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA512, @@ -11125,7 +10986,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "VerifyPreferences-Enforced", config: Config{ - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, SignSignatureAlgorithms: []signatureAlgorithm{ signatureRSAPSSWithSHA256, signatureRSAPSSWithSHA512, @@ -11147,7 +11008,7 @@ func addSignatureAlgorithmTests() { testCases = append(testCases, testCase{ name: "VerifyPreferences-Ed25519", config: Config{ - Certificates: []Certificate{ed25519Certificate}, + Chains: []CertificateChain{ed25519Certificate}, }, flags: []string{ "-verify-prefs", strconv.Itoa(int(signatureEd25519)), @@ -11176,9 +11037,8 @@ func addSignatureAlgorithmTests() { ClientAuth: RequireAnyClientCert, VerifySignatureAlgorithms: []signatureAlgorithm{signatureRSAPKCS1WithMD5AndSHA1}, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-signing-prefs", strconv.Itoa(int(signatureRSAPKCS1WithMD5AndSHA1)), // Include a valid algorithm as well, to avoid an empty list // if filtered out. @@ -11194,17 +11054,16 @@ func addSignatureAlgorithmTests() { testType: testType, name: prefix + "NoVerify-RSA_PKCS1_MD5_SHA1", config: Config{ - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, Bugs: ProtocolBugs{ IgnorePeerSignatureAlgorithmPreferences: true, AlwaysSignAsLegacyVersion: true, SendSignatureAlgorithm: signatureRSAPKCS1WithMD5AndSHA1, }, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-verify-prefs", strconv.Itoa(int(signatureRSAPKCS1WithMD5AndSHA1)), // Include a valid algorithm as well, to avoid an empty list // if filtered out. @@ -13495,8 +13354,8 @@ func makePerMessageTests() []perMessageTest { protocol: protocol, name: "ClientCertificate" + suffix, config: Config{ - Certificates: []Certificate{rsaCertificate}, - MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, + MaxVersion: VersionTLS12, }, flags: []string{"-require-any-client-certificate"}, }, @@ -13509,8 +13368,8 @@ func makePerMessageTests() []perMessageTest { protocol: protocol, name: "CertificateVerify" + suffix, config: Config{ - Certificates: []Certificate{rsaCertificate}, - MaxVersion: VersionTLS12, + Chains: []CertificateChain{rsaCertificate}, + MaxVersion: VersionTLS12, }, flags: []string{"-require-any-client-certificate"}, }, @@ -13551,7 +13410,7 @@ func makePerMessageTests() []perMessageTest { name: "ChannelID" + suffix, config: Config{ MaxVersion: VersionTLS12, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, flags: []string{ "-expect-channel-id", @@ -13685,8 +13544,8 @@ func makePerMessageTests() []perMessageTest { protocol: protocol, name: "TLS13-ClientCertificate" + suffix, config: Config{ - Certificates: []Certificate{rsaCertificate}, - MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, + MaxVersion: VersionTLS13, }, flags: []string{"-require-any-client-certificate"}, }, @@ -13699,8 +13558,8 @@ func makePerMessageTests() []perMessageTest { protocol: protocol, name: "TLS13-ClientCertificateVerify" + suffix, config: Config{ - Certificates: []Certificate{rsaCertificate}, - MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, + MaxVersion: VersionTLS13, }, flags: []string{"-require-any-client-certificate"}, }, @@ -14595,12 +14454,9 @@ func addTLS13HandshakeTests() { SendRequestContext: []byte("request context"), }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - shouldFail: true, - expectedError: ":DECODE_ERROR:", + shimCertificate: &rsaCertificate, + shouldFail: true, + expectedError: ":DECODE_ERROR:", }) testCases = append(testCases, testCase{ @@ -14613,10 +14469,7 @@ func addTLS13HandshakeTests() { SendCustomCertificateRequest: 0x1212, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, + shimCertificate: &rsaCertificate, }) testCases = append(testCases, testCase{ @@ -14629,12 +14482,9 @@ func addTLS13HandshakeTests() { OmitCertificateRequestAlgorithms: true, }, }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), - }, - shouldFail: true, - expectedError: ":DECODE_ERROR:", + shimCertificate: &rsaCertificate, + shouldFail: true, + expectedError: ":DECODE_ERROR:", }) testCases = append(testCases, testCase{ @@ -14705,12 +14555,12 @@ func addTLS13HandshakeTests() { testType: clientTest, name: "EarlyData-RejectTicket-Client-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, SessionTicketsDisabled: true, }, resumeSession: true, @@ -14721,9 +14571,9 @@ func addTLS13HandshakeTests() { "-on-retry-expect-early-data-reason", "session_not_resumed", // Test the peer certificate is reported correctly in each of the // three logical connections. - "-on-initial-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-on-resume-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-on-retry-expect-peer-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), + "-on-initial-expect-peer-cert-file", rsaCertificate.ChainPath, + "-on-resume-expect-peer-cert-file", rsaCertificate.ChainPath, + "-on-retry-expect-peer-cert-file", ecdsaP256Certificate.ChainPath, // Session tickets are disabled, so the runner will not send a ticket. "-on-retry-expect-no-session", }, @@ -14800,12 +14650,12 @@ func addTLS13HandshakeTests() { testType: clientTest, name: "EarlyData-HRR-RejectTicket-Client-TLS13", config: Config{ - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, }, resumeConfig: &Config{ MaxVersion: VersionTLS13, - Certificates: []Certificate{ecdsaP256Certificate}, + Chains: []CertificateChain{ecdsaP256Certificate}, SessionTicketsDisabled: true, Bugs: ProtocolBugs{ SendHelloRetryRequestCookie: []byte{1, 2, 3, 4}, @@ -14821,9 +14671,9 @@ func addTLS13HandshakeTests() { "-on-retry-expect-early-data-reason", "hello_retry_request", // Test the peer certificate is reported correctly in each of the // three logical connections. - "-on-initial-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-on-resume-expect-peer-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-on-retry-expect-peer-cert-file", path.Join(*resourceDir, ecdsaP256CertificateFile), + "-on-initial-expect-peer-cert-file", rsaCertificate.ChainPath, + "-on-resume-expect-peer-cert-file", rsaCertificate.ChainPath, + "-on-retry-expect-peer-cert-file", ecdsaP256Certificate.ChainPath, // Session tickets are disabled, so the runner will not send a ticket. "-on-retry-expect-no-session", }, @@ -15255,7 +15105,7 @@ func addTLS13HandshakeTests() { expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:", expectedLocalError: "remote error: illegal parameter", flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, }, }) @@ -15278,7 +15128,7 @@ func addTLS13HandshakeTests() { channelID: true, }, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, // The client never learns the reason was Channel ID. "-on-retry-expect-early-data-reason", "peer_declined", }, @@ -15295,7 +15145,7 @@ func addTLS13HandshakeTests() { resumeSession: true, earlyData: true, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, }, }) @@ -15306,7 +15156,7 @@ func addTLS13HandshakeTests() { name: "EarlyDataChannelID-OfferBoth-Server-TLS13", config: Config{ MaxVersion: VersionTLS13, - ChannelID: channelIDKey, + ChannelID: &channelIDKey, }, resumeSession: true, earlyData: true, @@ -15455,19 +15305,18 @@ func addTLS13HandshakeTests() { testType: serverTest, name: "ServerSkipCertificateVerify-TLS13", config: Config{ - MinVersion: VersionTLS13, - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaChainCertificate}, + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaChainCertificate}, Bugs: ProtocolBugs{ SkipCertificateVerify: true, }, }, expectations: connectionExpectations{ - peerCertificate: &rsaChainCertificate, + peerCertificate: &rsaCertificate, }, + shimCertificate: &rsaCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), - "-key-file", path.Join(*resourceDir, rsaChainKeyFile), "-require-any-client-certificate", }, shouldFail: true, @@ -15478,20 +15327,17 @@ func addTLS13HandshakeTests() { testType: clientTest, name: "ClientSkipCertificateVerify-TLS13", config: Config{ - MinVersion: VersionTLS13, - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaChainCertificate}, + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaChainCertificate}, Bugs: ProtocolBugs{ SkipCertificateVerify: true, }, }, expectations: connectionExpectations{ - peerCertificate: &rsaChainCertificate, - }, - flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), - "-key-file", path.Join(*resourceDir, rsaChainKeyFile), + peerCertificate: &rsaCertificate, }, + shimCertificate: &rsaCertificate, shouldFail: true, expectedError: ":UNEXPECTED_MESSAGE:", expectedLocalError: "remote error: unexpected message", @@ -15995,18 +15841,17 @@ func addCertificateTests() { testType: clientTest, name: "SendReceiveIntermediate-Client-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaChainCertificate}, - ClientAuth: RequireAnyClientCert, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaChainCertificate}, + ClientAuth: RequireAnyClientCert, }, expectations: connectionExpectations{ peerCertificate: &rsaChainCertificate, }, + shimCertificate: &rsaChainCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), - "-key-file", path.Join(*resourceDir, rsaChainKeyFile), - "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), + "-expect-peer-cert-file", rsaChainCertificate.ChainPath, }, }) @@ -16014,18 +15859,17 @@ func addCertificateTests() { testType: serverTest, name: "SendReceiveIntermediate-Server-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaChainCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaChainCertificate}, }, expectations: connectionExpectations{ peerCertificate: &rsaChainCertificate, }, + shimCertificate: &rsaChainCertificate, flags: []string{ - "-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), - "-key-file", path.Join(*resourceDir, rsaChainKeyFile), "-require-any-client-certificate", - "-expect-peer-cert-file", path.Join(*resourceDir, rsaChainCertificateFile), + "-expect-peer-cert-file", rsaChainCertificate.ChainPath, }, }) @@ -16034,9 +15878,9 @@ func addCertificateTests() { testType: clientTest, name: "GarbageCertificate-Client-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{garbageCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{garbageCertificate}, }, shouldFail: true, expectedError: ":CANNOT_PARSE_LEAF_CERT:", @@ -16047,9 +15891,9 @@ func addCertificateTests() { testType: serverTest, name: "GarbageCertificate-Server-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{garbageCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{garbageCertificate}, }, flags: []string{"-require-any-client-certificate"}, shouldFail: true, @@ -16084,9 +15928,9 @@ func addRetainOnlySHA256ClientCertTests() { testType: serverTest, name: "RetainOnlySHA256-Cert-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-verify-peer", @@ -16105,9 +15949,9 @@ func addRetainOnlySHA256ClientCertTests() { testType: serverTest, name: "RetainOnlySHA256-OnOff-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-verify-peer", @@ -16125,9 +15969,9 @@ func addRetainOnlySHA256ClientCertTests() { testType: serverTest, name: "RetainOnlySHA256-OffOn-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{rsaCertificate}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-verify-peer", @@ -16141,19 +15985,13 @@ func addRetainOnlySHA256ClientCertTests() { } func addECDSAKeyUsageTests() { - p256 := elliptic.P256() - priv, err := ecdsa.GenerateKey(p256, rand.Reader) - if err != nil { - panic(err) - } - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { panic(err) } - template := x509.Certificate{ + template := &x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Acme Co"}, @@ -16168,15 +16006,7 @@ func addECDSAKeyUsageTests() { BasicConstraintsValid: true, } - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) - if err != nil { - panic(err) - } - - cert := Certificate{ - Certificate: [][]byte{derBytes}, - PrivateKey: priv, - } + cert := generateSingleCertChain(template, &ecdsaP256Key, nil, nil) for _, ver := range tlsVersions { if ver.version < VersionTLS12 { @@ -16187,9 +16017,9 @@ func addECDSAKeyUsageTests() { testType: clientTest, name: "ECDSAKeyUsage-Client-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{cert}, }, shouldFail: true, expectedError: ":KEY_USAGE_BIT_INCORRECT:", @@ -16199,9 +16029,9 @@ func addECDSAKeyUsageTests() { testType: serverTest, name: "ECDSAKeyUsage-Server-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{cert}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{cert}, }, flags: []string{"-require-any-client-certificate"}, shouldFail: true, @@ -16243,25 +16073,9 @@ func addRSAKeyUsageTests() { BasicConstraintsValid: true, } - dsDerBytes, err := x509.CreateCertificate(rand.Reader, &dsTemplate, &dsTemplate, &priv.PublicKey, priv) - if err != nil { - panic(err) - } + dsCert := generateSingleCertChain(&dsTemplate, priv, nil, nil) - encDerBytes, err := x509.CreateCertificate(rand.Reader, &encTemplate, &encTemplate, &priv.PublicKey, priv) - if err != nil { - panic(err) - } - - dsCert := Certificate{ - Certificate: [][]byte{dsDerBytes}, - PrivateKey: priv, - } - - encCert := Certificate{ - Certificate: [][]byte{encDerBytes}, - PrivateKey: priv, - } + encCert := generateSingleCertChain(&encTemplate, priv, nil, nil) dsSuites := []uint16{ TLS_AES_128_GCM_SHA256, @@ -16280,7 +16094,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{encCert}, + Chains: []CertificateChain{encCert}, CipherSuites: dsSuites, }, shouldFail: true, @@ -16296,7 +16110,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{dsCert}, + Chains: []CertificateChain{dsCert}, CipherSuites: dsSuites, }, flags: []string{ @@ -16312,7 +16126,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{encCert}, + Chains: []CertificateChain{encCert}, CipherSuites: encSuites, }, flags: []string{ @@ -16326,7 +16140,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{dsCert}, + Chains: []CertificateChain{dsCert}, CipherSuites: encSuites, }, shouldFail: true, @@ -16343,7 +16157,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{dsCert}, + Chains: []CertificateChain{dsCert}, CipherSuites: encSuites, }, flags: []string{"-expect-key-usage-invalid"}, @@ -16355,7 +16169,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{encCert}, + Chains: []CertificateChain{encCert}, CipherSuites: dsSuites, }, flags: []string{"-expect-key-usage-invalid"}, @@ -16370,7 +16184,7 @@ func addRSAKeyUsageTests() { config: Config{ MinVersion: ver.version, MaxVersion: ver.version, - Certificates: []Certificate{encCert}, + Chains: []CertificateChain{encCert}, CipherSuites: dsSuites, }, shouldFail: true, @@ -16383,9 +16197,9 @@ func addRSAKeyUsageTests() { testType: serverTest, name: "RSAKeyUsage-Server-WantSignature-GotEncipherment-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{encCert}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{encCert}, }, shouldFail: true, expectedError: ":KEY_USAGE_BIT_INCORRECT:", @@ -16396,9 +16210,9 @@ func addRSAKeyUsageTests() { testType: serverTest, name: "RSAKeyUsage-Server-WantSignature-GotSignature-" + ver.name, config: Config{ - MinVersion: ver.version, - MaxVersion: ver.version, - Certificates: []Certificate{dsCert}, + MinVersion: ver.version, + MaxVersion: ver.version, + Chains: []CertificateChain{dsCert}, }, flags: []string{"-require-any-client-certificate"}, }) @@ -17062,26 +16876,9 @@ func addJDK11WorkaroundTests() { } func addDelegatedCredentialTests() { - certPath := path.Join(*resourceDir, rsaCertificateFile) - pemBytes, err := os.ReadFile(certPath) - if err != nil { - panic(err) - } - - block, _ := pem.Decode(pemBytes) - if block == nil { - panic(fmt.Sprintf("no PEM block found in %q", certPath)) - } - parentDER := block.Bytes - - rsaPriv, _, err := loadRSAPrivateKey(rsaKeyFile) - if err != nil { - panic(err) - } - ecdsaDC, ecdsaPKCS8, err := createDelegatedCredential(delegatedCredentialConfig{ algo: signatureRSAPSSWithSHA256, - }, parentDER, rsaPriv) + }, rsaCertificate.Leaf.Raw, rsaCertificate.PrivateKey) if err != nil { panic(err) } @@ -17137,32 +16934,42 @@ func addDelegatedCredentialTests() { }, }) - // This flag value has mismatched public and private keys which should cause a - // configuration error in the shim. - _, badTLSVersionPKCS8, err := createDelegatedCredential(delegatedCredentialConfig{ - algo: signatureRSAPSSWithSHA256, - tlsVersion: 0x1234, - }, parentDER, rsaPriv) + // Generate another delegated credential, so we can get the keys out of sync. + _, ecdsaPKCS8Wrong, err := createDelegatedCredential(delegatedCredentialConfig{ + algo: signatureRSAPSSWithSHA256, + }, rsaCertificate.Leaf.Raw, rsaCertificate.PrivateKey) if err != nil { panic(err) } - mismatchFlagValue := fmt.Sprintf("%x,%x", ecdsaDC, badTLSVersionPKCS8) + mismatchFlagValue := fmt.Sprintf("%x,%x", ecdsaDC, ecdsaPKCS8Wrong) testCases = append(testCases, testCase{ testType: serverTest, name: "DelegatedCredentials-KeyMismatch", - config: Config{ - MinVersion: VersionTLS13, - MaxVersion: VersionTLS13, - Bugs: ProtocolBugs{ - FailIfDelegatedCredentials: true, - }, - }, flags: []string{ "-delegated-credential", mismatchFlagValue, }, shouldFail: true, expectedError: ":KEY_VALUES_MISMATCH:", }) + + // RSA delegated credentials should be rejected at configuration time. + rsaDC, rsaPKCS8, err := createDelegatedCredential(delegatedCredentialConfig{ + algo: signatureRSAPSSWithSHA256, + dcAlgo: signatureRSAPSSWithSHA256, + }, rsaCertificate.Leaf.Raw, rsaCertificate.PrivateKey) + if err != nil { + panic(err) + } + rsaFlagValue := fmt.Sprintf("%x,%x", rsaDC, rsaPKCS8) + testCases = append(testCases, testCase{ + testType: serverTest, + name: "DelegatedCredentials-NoRSA", + flags: []string{ + "-delegated-credential", rsaFlagValue, + }, + shouldFail: true, + expectedError: ":INVALID_SIGNATURE_ALGORITHM:", + }) } type echCipher struct { @@ -17950,7 +17757,7 @@ write hs 4 protocol: protocol, name: prefix + "ECH-Server-ClientAuth", config: Config{ - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, ClientECHConfig: echConfig.ECHConfig, }, flags: []string{ @@ -17969,7 +17776,7 @@ write hs 4 protocol: protocol, name: prefix + "ECH-Server-Decline-ClientAuth", config: Config{ - Certificates: []Certificate{rsaCertificate}, + Chains: []CertificateChain{rsaCertificate}, ClientECHConfig: echConfig.ECHConfig, Bugs: ProtocolBugs{ ExpectECHRetryConfigs: CreateECHConfigList(echConfig1.ECHConfig.Raw), @@ -19091,9 +18898,8 @@ write hs 4 ServerECHConfigs: []ServerECHConfig{echConfig}, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: append([]string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), "-expect-ech-accept", }, flags...), @@ -19111,9 +18917,8 @@ write hs 4 MaxVersion: VersionTLS13, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: append([]string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), }, flags...), shouldFail: true, @@ -19129,9 +18934,8 @@ write hs 4 MaxVersion: VersionTLS12, ClientAuth: RequireAnyClientCert, }, + shimCertificate: &rsaCertificate, flags: append([]string{ - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), }, flags...), shouldFail: true, @@ -19150,7 +18954,7 @@ write hs 4 RequestChannelID: true, }, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), "-expect-ech-accept", }, @@ -19174,7 +18978,7 @@ write hs 4 }, }, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), }, shouldFail: true, @@ -19194,7 +18998,7 @@ write hs 4 }, }, flags: []string{ - "-send-channel-id", path.Join(*resourceDir, channelIDKeyFile), + "-send-channel-id", channelIDKeyPath, "-ech-config-list", base64FlagValue(CreateECHConfigList(echConfig.ECHConfig.Raw)), }, shouldFail: true, @@ -19550,10 +19354,9 @@ func addHintMismatchTests() { signatureRSAPSSWithSHA384, }, }, + shimCertificate: &rsaCertificate, flags: []string{ "-allow-hint-mismatch", - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-on-shim-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-on-handshaker-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)), }, @@ -19575,10 +19378,9 @@ func addHintMismatchTests() { signatureRSAPSSWithSHA384, }, }, + shimCertificate: &rsaCertificate, flags: []string{ "-allow-hint-mismatch", - "-cert-file", path.Join(*resourceDir, rsaCertificateFile), - "-key-file", path.Join(*resourceDir, rsaKeyFile), "-on-shim-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA256)), "-on-handshaker-signing-prefs", strconv.Itoa(int(signatureRSAPSSWithSHA384)), }, @@ -19664,9 +19466,9 @@ func addHintMismatchTests() { protocol: protocol, skipSplitHandshake: true, config: Config{ - MinVersion: VersionTLS13, - MaxVersion: VersionTLS13, - Certificates: []Certificate{rsaCertificate}, + MinVersion: VersionTLS13, + MaxVersion: VersionTLS13, + Chains: []CertificateChain{rsaCertificate}, }, flags: []string{ "-allow-hint-mismatch", @@ -19860,28 +19662,28 @@ var testMultipleCertSlotsAlgorithms = []struct { name string cipher uint16 id signatureAlgorithm - cert testCert + cert *CertificateChain // If non-zero, the curve that must be supported in TLS 1.2 for cert to be // accepted. curve CurveID }{ - {"RSA_PKCS1_SHA1", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA1, testCertRSA, 0}, - {"RSA_PKCS1_SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA256, testCertRSA, 0}, - {"RSA_PKCS1_SHA384", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA384, testCertRSA, 0}, - {"RSA_PKCS1_SHA512", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA512, testCertRSA, 0}, - {"ECDSA_SHA1", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithSHA1, testCertECDSAP256, CurveP256}, + {"RSA_PKCS1_SHA1", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA1, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA256, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA384", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA384, &rsaCertificate, 0}, + {"RSA_PKCS1_SHA512", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPKCS1WithSHA512, &rsaCertificate, 0}, + {"ECDSA_SHA1", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithSHA1, &ecdsaP256Certificate, CurveP256}, // The “P256” in the following line is not a mistake. In TLS 1.2 the // hash function doesn't have to match the curve and so the same // signature algorithm works with P-224. - {"ECDSA_P224_SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithP256AndSHA256, testCertECDSAP224, CurveP224}, - {"ECDSA_P256_SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithP256AndSHA256, testCertECDSAP256, CurveP256}, - {"RSA_PSS_SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA256, testCertRSA, 0}, - {"RSA_PSS_SHA384", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA384, testCertRSA, 0}, - {"RSA_PSS_SHA512", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA512, testCertRSA, 0}, - {"Ed25519", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, signatureEd25519, testCertEd25519, 0}, + {"ECDSA_P224_SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithP256AndSHA256, &ecdsaP224Certificate, CurveP224}, + {"ECDSA_P256_SHA256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, signatureECDSAWithP256AndSHA256, &ecdsaP256Certificate, CurveP256}, + {"RSA_PSS_SHA256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA256, &rsaCertificate, 0}, + {"RSA_PSS_SHA384", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA384, &rsaCertificate, 0}, + {"RSA_PSS_SHA512", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, signatureRSAPSSWithSHA512, &rsaCertificate, 0}, + {"Ed25519", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, signatureEd25519, &ed25519Certificate, 0}, // Tests for key types prior to TLS 1.2. - {"RSA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0, testCertRSA, 0}, - {"ECDSA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 0, testCertECDSAP256, CurveP256}, + {"RSA", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 0, &rsaCertificate, 0}, + {"ECDSA", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 0, &ecdsaP256Certificate, CurveP256}, } func addMultipleCertSlotTests() { @@ -19893,13 +19695,13 @@ func addMultipleCertSlotTests() { } multipleCertsFlag := "-multiple-certs-slot" rsaCertSlot := []string{ - multipleCertsFlag, path.Join(*resourceDir, getShimCertificate(testCertRSA)) + "," + path.Join(*resourceDir, getShimKey(testCertRSA)), + multipleCertsFlag, rsaCertificate.ChainPath + "," + rsaCertificate.KeyPath, } ecdsaCertSlot := []string{ - multipleCertsFlag, path.Join(*resourceDir, getShimCertificate(testCertECDSAP256)) + "," + path.Join(*resourceDir, getShimKey(testCertECDSAP256)), + multipleCertsFlag, ecdsaP256Certificate.ChainPath + "," + ecdsaP256Certificate.KeyPath, } ed25519CertSlot := []string{ - multipleCertsFlag, path.Join(*resourceDir, getShimCertificate(testCertEd25519)) + "," + path.Join(*resourceDir, getShimKey(testCertEd25519)), + multipleCertsFlag, ed25519Certificate.ChainPath + "," + ed25519Certificate.KeyPath, } certificateSlotFlags := append([]string{}, rsaCertSlot...) certificateSlotFlags = append(certificateSlotFlags, ecdsaCertSlot...) @@ -19927,7 +19729,7 @@ func addMultipleCertSlotTests() { } // SHA-224 has been removed from TLS 1.3 and, in 1.3, // the curve has to match the hash size. - if ver.version >= VersionTLS13 && alg.cert == testCertECDSAP224 { + if ver.version >= VersionTLS13 && alg.cert == &ecdsaP224Certificate { shouldFail = true } @@ -19985,7 +19787,7 @@ func addMultipleCertSlotTests() { MaxVersion: ver.version, VerifySignatureAlgorithms: []signatureAlgorithm{alg.id}, ClientAuth: RequireAnyClientCert, - Certificates: []Certificate{rsaCertificate, ecdsaP256Certificate, ed25519Certificate}, + Chains: []CertificateChain{rsaCertificate, ecdsaP256Certificate, ed25519Certificate}, }, flags: func() []string { flags := append([]string{}, certificateSlotFlags...) @@ -20360,7 +20162,13 @@ var sslTransferHelper *ssl_transfer.TestHelper func main() { flag.Parse() - *resourceDir = path.Clean(*resourceDir) + var err error + if tmpDir, err = os.MkdirTemp("", "testing-certs"); err != nil { + fmt.Fprintf(os.Stderr, "failed to make temporary directory: %s", err) + os.Exit(1) + } + defer os.RemoveAll(tmpDir) + initKeys() initCertificates() if len(*shimConfigFile) != 0 { diff --git a/ssl/test/runner/tls.go b/ssl/test/runner/tls.go index 6e57d18197..bd94275ce2 100644 --- a/ssl/test/runner/tls.go +++ b/ssl/test/runner/tls.go @@ -73,7 +73,7 @@ func NewListener(inner net.Listener, config *Config) net.Listener { // The configuration config must be non-nil and must have // at least one certificate. func Listen(network, laddr string, config *Config) (net.Listener, error) { - if config == nil || len(config.Certificates) == 0 { + if config == nil || len(config.Chains) == 0 { return nil, errors.New("tls.Listen: no certificates in configuration") } l, err := net.Listen(network, laddr) @@ -173,7 +173,7 @@ func Dial(network, addr string, config *Config) (*Conn, error) { // LoadX509KeyPair reads and parses a public/private key pair from a pair of // files. The files must contain PEM encoded data. -func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) { +func LoadX509KeyPair(certFile, keyFile string) (cert CertificateChain, err error) { certPEMBlock, err := os.ReadFile(certFile) if err != nil { return @@ -187,7 +187,7 @@ func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) { // X509KeyPair parses a public/private key pair from a pair of // PEM encoded data. -func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) { +func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert CertificateChain, err error) { var certDERBlock *pem.Block for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) diff --git a/ssl/test/test_config.cc b/ssl/test/test_config.cc index 8e3a0a2520..c73be95297 100644 --- a/ssl/test/test_config.cc +++ b/ssl/test/test_config.cc @@ -218,6 +218,7 @@ std::vector SortedFlags() { IntVectorFlag("-curves", &TestConfig::curves), StringFlag("-key-file", &TestConfig::key_file), StringFlag("-cert-file", &TestConfig::cert_file), + StringFlag("-trust-cert", &TestConfig::trust_cert), StringFlag("-expect-server-name", &TestConfig::expect_server_name), BoolFlag("-enable-ech-grease", &TestConfig::enable_ech_grease), Base64VectorFlag("-ech-server-config", &TestConfig::ech_server_configs), diff --git a/ssl/test/test_config.h b/ssl/test/test_config.h index 05f73b3ed7..fbf1c60c8d 100644 --- a/ssl/test/test_config.h +++ b/ssl/test/test_config.h @@ -40,6 +40,7 @@ struct TestConfig { std::vector curves; std::string key_file; std::string cert_file; + std::string trust_cert; std::string expect_server_name; bool enable_ech_grease = false; std::vector ech_server_configs; diff --git a/tool-openssl/CMakeLists.txt b/tool-openssl/CMakeLists.txt index d9a7c6a72c..c31fbc4de1 100644 --- a/tool-openssl/CMakeLists.txt +++ b/tool-openssl/CMakeLists.txt @@ -4,6 +4,8 @@ add_executable( ../tool/args.cc ../tool/file.cc ../tool/fd.cc + ../tool/client.cc + ../tool/transport_common.cc dgst.cc rsa.cc @@ -11,6 +13,7 @@ add_executable( x509.cc crl.cc version.cc + s_client.cc ) target_include_directories(openssl PUBLIC ${PROJECT_SOURCE_DIR}/include) @@ -53,6 +56,8 @@ if(BUILD_TESTING) ../tool/file.cc ../tool/fd.cc ../crypto/test/test_util.cc + ../tool/client.cc + ../tool/transport_common.cc dgst.cc dgst_test.cc @@ -60,6 +65,7 @@ if(BUILD_TESTING) rsa_test.cc x509.cc x509_test.cc + s_client.cc crl.cc crl_test.cc ) diff --git a/tool-openssl/internal.h b/tool-openssl/internal.h index 3364f4639f..c640bb4539 100644 --- a/tool-openssl/internal.h +++ b/tool-openssl/internal.h @@ -34,5 +34,6 @@ bool rsaTool(const args_list_t &args); bool X509Tool(const args_list_t &args); bool CRLTool(const args_list_t &args); bool VersionTool(const args_list_t &args); +bool SClientTool(const args_list_t &args); #endif //INTERNAL_H diff --git a/tool-openssl/s_client.cc b/tool-openssl/s_client.cc new file mode 100644 index 0000000000..eb15c3d959 --- /dev/null +++ b/tool-openssl/s_client.cc @@ -0,0 +1,46 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include +#include "internal.h" +#include "../tool/internal.h" + +static const argument_t kArguments[] = { + { "-help", kBooleanArgument, "Display option summary" }, + { "-connect", kRequiredArgument, + "The hostname and port of the server to connect to, e.g. foo.com:443" }, + { "-CAfile", kOptionalArgument, + "A file containing trusted certificates to use during server authentication " + "and to use when attempting to build the client certificate chain. " }, + { "-CApath", kOptionalArgument, + "The directory to use for server certificate verification. " }, + { "-showcerts", kBooleanArgument, + "Displays the server certificate list as sent by the server: it only " + "consists of certificates the server has sent (in the order the server " + "has sent them). It is not a verified chain. " }, + { "-verify", kOptionalArgument, + "The verify depth to use. This specifies the maximum length of the server " + "certificate chain and turns on server certificate verification. " + "Currently the verify operation continues after errors so all the problems " + "with a certificate chain can be seen. As a side effect the connection will " + "never fail due to a server certificate verify failure." }, + { "", kOptionalArgument, "" }, +}; + +bool SClientTool(const args_list_t &args) { + std::map args_map; + + if (!ParseKeyValueArguments(&args_map, args, kArguments)) { + PrintUsage(kArguments); + return false; + } + + if(args_map.count("help")) { + fprintf(stderr, "Usage: s_client [options] [host:port]\n"); + PrintUsage(kArguments); + return false; + } + + return DoClient(args_map, true); +} diff --git a/tool-openssl/s_client_test.cc b/tool-openssl/s_client_test.cc new file mode 100644 index 0000000000..205509e6ad --- /dev/null +++ b/tool-openssl/s_client_test.cc @@ -0,0 +1,35 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include +#include "internal.h" +#include + +// Test -connect +TEST(SClientTest, SClientConnect) { + args_list_t args = {"-connect", "amazon.com:443"}; + bool result = SClientTool(args); + ASSERT_TRUE(result); +} + +// Test without connect but with help +TEST(SClientTest, SClientNoConnect) { + args_list_t args = {}; + bool result = SClientTool(args); + ASSERT_FALSE(result); +} + +// Test -help +TEST(SClientTest, SClientHelp) { + args_list_t args = {"-help"}; + bool result = SClientTool(args); + ASSERT_FALSE(result); +} + +// Test -connect, -verify, -showcerts +TEST(SClientTest, SClientConnectVerifyShowcerts) { + args_list_t args = {"-connect", "amazon.com:443", "-verify", "99"}; + bool result = SClientTool(args); + ASSERT_TRUE(result); +} + diff --git a/tool-openssl/tool.cc b/tool-openssl/tool.cc index ae42679eca..09c61b6f2c 100644 --- a/tool-openssl/tool.cc +++ b/tool-openssl/tool.cc @@ -15,13 +15,14 @@ #include "./internal.h" -static const std::array kTools = {{ +static const std::array kTools = {{ + {"crl", CRLTool}, {"dgst", dgstTool}, {"md5", md5Tool}, {"rsa", rsaTool}, + {"s_client", SClientTool}, + {"version", VersionTool}, {"x509", X509Tool}, - {"crl", CRLTool}, - {"version", VersionTool} }}; static void usage(const std::string &name) { diff --git a/tool/client.cc b/tool/client.cc index b3efe63b3e..57f2b24237 100644 --- a/tool/client.cc +++ b/tool/client.cc @@ -245,19 +245,92 @@ static bool WaitForSession(SSL *ssl, int sock) { return true; } +static void print_verify_details(SSL *s) { + long verify_err = SSL_get_verify_result(s); + + if (verify_err == X509_V_OK) { + fprintf(stdout, "Verification: OK\n"); + } else { + const char *reason = X509_verify_cert_error_string(verify_err); + fprintf(stdout, "Verification error: %s\n", reason); + } +} + +static void PrintOpenSSLConnectionInfo(SSL *ssl, bool show_certs) { + STACK_OF(X509) *sk; + + sk = SSL_get_peer_cert_chain(ssl); + if (sk != NULL) { + fprintf(stdout, "---\nCertificate chain\n"); + for (size_t i = 0; i < sk_X509_num(sk); i++) { + fprintf(stdout, "%2zu s:", i); + if (X509_NAME_print_ex_fp(stdout, X509_get_subject_name(sk_X509_value(sk, i)), + 0, XN_FLAG_ONELINE) < 0) { + fprintf(stderr, "Error: Printing subject name failed"); + } + fprintf(stdout, "\n i:"); + if (X509_NAME_print_ex_fp(stdout, X509_get_issuer_name(sk_X509_value(sk, i)), + 0, XN_FLAG_ONELINE) < 0) { + fprintf(stderr, "Error: Printing issuer name failed"); + } + fprintf(stdout, "\n"); + if (show_certs) { + PEM_write_X509(stdout, sk_X509_value(sk, i)); + } + } + } + + fprintf(stdout, "---\n"); + bssl::UniquePtr peer(SSL_get_peer_certificate(ssl)); + if (peer) { + fprintf(stdout, "Server certificate\n"); + PEM_write_X509(stdout, peer.get()); + fprintf(stdout, "subject="); + if (X509_NAME_print_ex_fp(stdout, X509_get_subject_name(peer.get()), + 0, XN_FLAG_ONELINE) < 0) { + fprintf(stderr, "Error: Printing subject name failed"); + } + fprintf(stdout, "\n\nissuer="); + if (X509_NAME_print_ex_fp(stdout, X509_get_issuer_name(peer.get()), + 0, XN_FLAG_ONELINE) < 0) { + fprintf(stderr, "Error: Printing issuer name failed"); + } + fprintf(stdout, "\n\n---\n"); + } else { + fprintf(stdout, "no peer certificate available\n"); + } + + // TODO (aws-lc): we are missing some functions needed to print the following data + // print_ca_names(bio, s); + // ssl_print_sigalgs(bio, s); + // ssl_print_tmp_key(bio, s); + + fprintf(stdout, + "---\nSSL handshake has read %d bytes " + "and written %d bytes\n", + (int)BIO_number_read(SSL_get_rbio(ssl)), + (int)BIO_number_written(SSL_get_wbio(ssl))); + print_verify_details(ssl); +} + static bool DoConnection(SSL_CTX *ctx, std::map args_map, - bool (*cb)(SSL *ssl, int sock)) { + bool (*cb)(SSL *ssl, int sock), bool is_openssl_s_client) { int sock = -1; if (args_map.count("-http-tunnel") != 0) { - if (!Connect(&sock, args_map["-http-tunnel"]) || + if (!Connect(&sock, args_map["-http-tunnel"], is_openssl_s_client) || !DoHTTPTunnel(sock, args_map["-connect"])) { return false; } - } else if (!Connect(&sock, args_map["-connect"])) { + } else if (!Connect(&sock, args_map["-connect"], is_openssl_s_client)) { return false; } + // print for openssl tool + if (is_openssl_s_client) { + fprintf(stdout, "CONNECTED(%08d)\n", sock); + } + if (args_map.count("-starttls") != 0) { const std::string& starttls = args_map["-starttls"]; if (starttls == "smtp") { @@ -357,9 +430,14 @@ static bool DoConnection(SSL_CTX *ctx, } } - fprintf(stderr, "Connected.\n"); - bssl::UniquePtr bio_stderr(BIO_new_fp(stderr, BIO_NOCLOSE)); - PrintConnectionInfo(bio_stderr.get(), ssl.get()); + // print for bssl + if (!is_openssl_s_client) { + fprintf(stderr, "Connected.\n"); + bssl::UniquePtr bio_stderr(BIO_new_fp(stderr, BIO_NOCLOSE)); + PrintConnectionInfo(bio_stderr.get(), ssl.get()); + } else { // print for openssl + PrintOpenSSLConnectionInfo(ssl.get(), args_map.count("-showcerts")); + } return cb(ssl.get(), sock); } @@ -378,11 +456,67 @@ static void InfoCallback(const SSL *ssl, int type, int value) { } } -bool Client(const std::vector &args) { - if (!InitSocketLibrary()) { - return false; +static int verify_cb(int ok, X509_STORE_CTX *ctx) +{ + X509 *err_cert = X509_STORE_CTX_get_current_cert(ctx); + int err = X509_STORE_CTX_get_error(ctx); + int depth = X509_STORE_CTX_get_error_depth(ctx); + bssl::UniquePtr bio_err(BIO_new_fp(stderr, BIO_CLOSE)); + + BIO_printf(bio_err.get(), "depth=%d ", depth); + if (err_cert != NULL) { + X509_NAME_print_ex(bio_err.get(), + X509_get_subject_name(err_cert), + 0, XN_FLAG_ONELINE); + BIO_puts(bio_err.get(), "\n"); + } else { + BIO_puts(bio_err.get(), "\n"); + } + + if (!ok) { + BIO_printf(bio_err.get(), "verify error:num=%d:%s\n", err, + X509_verify_cert_error_string(err)); + ok = 1; + } + + switch (err) { + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + if (err_cert != NULL) { + BIO_puts(bio_err.get(), "issuer= "); + X509_NAME_print_ex(bio_err.get(), X509_get_issuer_name(err_cert), + 0, XN_FLAG_ONELINE); + BIO_puts(bio_err.get(), "\n"); + } + ok = 1; + break; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + if (err_cert != NULL) { + BIO_printf(bio_err.get(), "notBefore="); + ASN1_TIME_print(bio_err.get(), X509_get0_notBefore(err_cert)); + BIO_printf(bio_err.get(), "\n"); + } + ok = 1; + break; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + if (err_cert != NULL) { + BIO_printf(bio_err.get(), "notAfter="); + ASN1_TIME_print(bio_err.get(), X509_get0_notAfter(err_cert)); + BIO_printf(bio_err.get(), "\n"); + } + ok = 1; + break; + case X509_V_ERR_NO_EXPLICIT_POLICY: + ok = 1; + break; } + BIO_printf(bio_err.get(), "verify return:%d\n", ok); + return ok; +} + +bool Client(const std::vector &args) { std::map args_map; if (!ParseKeyValueArguments(&args_map, args, kArguments)) { @@ -390,6 +524,14 @@ bool Client(const std::vector &args) { return false; } + return DoClient(args_map, false); +} + +bool DoClient(std::map args_map, bool is_openssl_s_client) { + if (!InitSocketLibrary()) { + return false; + } + bssl::UniquePtr ctx(SSL_CTX_new(TLS_method())); const char *keylog_file = getenv("SSLKEYLOGFILE"); @@ -540,24 +682,58 @@ bool Client(const std::vector &args) { SSL_CTX_set_permute_extensions(ctx.get(), 1); } + std::string certPathFlag; + int verify = SSL_VERIFY_NONE; if (args_map.count("-root-certs") != 0) { + certPathFlag = "-root-certs"; + verify = SSL_VERIFY_PEER; + } + // For the OpenSSL tool, simply specifying -CAfile does not imply verification + if (args_map.count("-CAfile") != 0) { + certPathFlag = "-CAfile"; + } + if (!certPathFlag.empty()) { if (!SSL_CTX_load_verify_locations( - ctx.get(), args_map["-root-certs"].c_str(), nullptr)) { + ctx.get(), args_map[certPathFlag].c_str(), nullptr)) { fprintf(stderr, "Failed to load root certificates.\n"); ERR_print_errors_fp(stderr); return false; } - SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, nullptr); } + certPathFlag = ""; if (args_map.count("-root-cert-dir") != 0) { + certPathFlag = "-root-cert-dir"; + verify = SSL_VERIFY_PEER; + } + // For the OpenSSL tool, simply specifying -CApath does not imply verification + if (args_map.count("-CApath") != 0) { + certPathFlag = "-CApath"; + } + + if (!certPathFlag.empty()) { if (!SSL_CTX_load_verify_locations( - ctx.get(), nullptr, args_map["-root-cert-dir"].c_str())) { + ctx.get(), nullptr, args_map[certPathFlag].c_str())) { fprintf(stderr, "Failed to load root certificates.\n"); ERR_print_errors_fp(stderr); return false; } - SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, nullptr); + } + + if (args_map.count("-verify") != 0) { + unsigned int depth; + if (!GetUnsigned(&depth, "-verify", 0, args_map)) { + fprintf(stderr, "s_client: Can't parse \"%s\" as a number\n", args_map.find("-verify")->second.c_str()); + return false; + } + fprintf(stdout, "verify depth is %d\n", (int)depth); + verify = SSL_VERIFY_PEER; + } + + if (is_openssl_s_client) { // openssl tool + SSL_CTX_set_verify(ctx.get(), verify, verify_cb); + } else { + SSL_CTX_set_verify(ctx.get(), verify, nullptr); } if (args_map.count("-early-data") != 0) { @@ -575,10 +751,10 @@ bool Client(const std::vector &args) { return false; } - if (!DoConnection(ctx.get(), args_map, &WaitForSession)) { + if (!DoConnection(ctx.get(), args_map, &WaitForSession, is_openssl_s_client)) { return false; } } - return DoConnection(ctx.get(), args_map, &TransferData); + return DoConnection(ctx.get(), args_map, &TransferData, is_openssl_s_client); } diff --git a/tool/internal.h b/tool/internal.h index 18414b65aa..ddf919642b 100644 --- a/tool/internal.h +++ b/tool/internal.h @@ -135,6 +135,12 @@ bool GetBoolArgument(bool *out, const std::string &arg_name, const args_map_t &a bool ReadAll(std::vector *out, FILE *in); bool WriteToFile(const std::string &path, const uint8_t *in, size_t in_len); +// DoClient is a common function used to support the s_client option in both +// bssl and openssl tools. It takes an additional parameter |tool| to indicate +// which tool's s_client is being invoked. A value of true indicates openssl +// and false indicates the internal bssl tool. +bool DoClient(std::map args_map, bool is_openssl_s_client); + bool Ciphers(const std::vector &args); bool Client(const std::vector &args); bool DoPKCS12(const std::vector &args); diff --git a/tool/transport_common.cc b/tool/transport_common.cc index cd43f9906b..80c8d91030 100644 --- a/tool/transport_common.cc +++ b/tool/transport_common.cc @@ -137,7 +137,7 @@ static void PrintSocketError(const char *function) { // Connect sets |*out_sock| to be a socket connected to the destination given // in |hostname_and_port|, which should be of the form "www.example.com:123". // It returns true on success and false otherwise. -bool Connect(int *out_sock, const std::string &hostname_and_port) { +bool Connect(int *out_sock, const std::string &hostname_and_port, bool quiet) { std::string hostname, port; SplitHostPort(&hostname, &port, hostname_and_port); @@ -153,7 +153,7 @@ bool Connect(int *out_sock, const std::string &hostname_and_port) { hint.ai_socktype = SOCK_STREAM; int ret = getaddrinfo(hostname.c_str(), port.c_str(), &hint, &result); - if (ret != 0) { + if (ret != 0 && !quiet) { #if defined(OPENSSL_WINDOWS) const char *error = gai_strerrorA(ret); #else @@ -173,22 +173,24 @@ bool Connect(int *out_sock, const std::string &hostname_and_port) { goto out; } - switch (result->ai_family) { - case AF_INET: { - struct sockaddr_in *sin = - reinterpret_cast(result->ai_addr); - fprintf(stderr, "Connecting to %s:%d\n", - inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)), - ntohs(sin->sin_port)); - break; - } - case AF_INET6: { - struct sockaddr_in6 *sin6 = - reinterpret_cast(result->ai_addr); - fprintf(stderr, "Connecting to [%s]:%d\n", - inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)), - ntohs(sin6->sin6_port)); - break; + if(!quiet) { + switch (result->ai_family) { + case AF_INET: { + struct sockaddr_in *sin = + reinterpret_cast(result->ai_addr); + fprintf(stderr, "Connecting to %s:%d\n", + inet_ntop(result->ai_family, &sin->sin_addr, buf, sizeof(buf)), + ntohs(sin->sin_port)); + break; + } + case AF_INET6: { + struct sockaddr_in6 *sin6 = + reinterpret_cast(result->ai_addr); + fprintf(stderr, "Connecting to [%s]:%d\n", + inet_ntop(result->ai_family, &sin6->sin6_addr, buf, sizeof(buf)), + ntohs(sin6->sin6_port)); + break; + } } } diff --git a/tool/transport_common.h b/tool/transport_common.h index 7d45d1c707..c23e856e50 100644 --- a/tool/transport_common.h +++ b/tool/transport_common.h @@ -25,8 +25,10 @@ bool InitSocketLibrary(); // Connect sets |*out_sock| to be a socket connected to the destination given // in |hostname_and_port|, which should be of the form "www.example.com:123". +// |quiet| when set to true suppresses any output to stdout or stderr from this +// function. // It returns true on success and false otherwise. -bool Connect(int *out_sock, const std::string &hostname_and_port); +bool Connect(int *out_sock, const std::string &hostname_and_port, bool quiet); class Listener { public: diff --git a/util/run_android_tests.go b/util/run_android_tests.go index 752b8ab4b4..0f02776fe7 100644 --- a/util/run_android_tests.go +++ b/util/run_android_tests.go @@ -338,28 +338,6 @@ func main() { if enableSSLTests() { binaries = append(binaries, "ssl/test/bssl_shim") - files = append(files, - "BUILDING.md", - "ssl/test/runner/cert.pem", - "ssl/test/runner/channel_id_key.pem", - "ssl/test/runner/ecdsa_p224_cert.pem", - "ssl/test/runner/ecdsa_p224_key.pem", - "ssl/test/runner/ecdsa_p256_cert.pem", - "ssl/test/runner/ecdsa_p256_key.pem", - "ssl/test/runner/ecdsa_p384_cert.pem", - "ssl/test/runner/ecdsa_p384_key.pem", - "ssl/test/runner/ecdsa_p521_cert.pem", - "ssl/test/runner/ecdsa_p521_key.pem", - "ssl/test/runner/ed25519_cert.pem", - "ssl/test/runner/ed25519_key.pem", - "ssl/test/runner/key.pem", - "ssl/test/runner/rsa_1024_cert.pem", - "ssl/test/runner/rsa_1024_key.pem", - "ssl/test/runner/rsa_chain_cert.pem", - "ssl/test/runner/rsa_chain_key.pem", - "util/all_tests.json", - ) - fmt.Printf("Building runner...\n") if err := goTool("test", "-c", "-o", filepath.Join(tmpDir, "ssl/test/runner/runner"), "./ssl/test/runner/"); err != nil { fmt.Printf("Error building runner: %s\n", err)