diff options
author | robot-contrib <robot-contrib@yandex-team.com> | 2022-07-09 10:40:08 +0300 |
---|---|---|
committer | robot-contrib <robot-contrib@yandex-team.com> | 2022-07-09 10:40:08 +0300 |
commit | 22acf19be42357b6bb0e7d601b0dc28695191463 (patch) | |
tree | a35a222fffb28fcf8a82dd7efe67f2276bfd1858 | |
parent | 7a7d303e197aa7e4f43c61cc289d8652df38ab43 (diff) | |
download | ydb-22acf19be42357b6bb0e7d601b0dc28695191463.tar.gz |
Update contrib/restricted/aws/s2n to 1.3.16
36 files changed, 663 insertions, 151 deletions
diff --git a/contrib/restricted/aws/s2n/CMakeLists.darwin.txt b/contrib/restricted/aws/s2n/CMakeLists.darwin.txt index 979301a5d6..4c0756bee7 100644 --- a/contrib/restricted/aws/s2n/CMakeLists.darwin.txt +++ b/contrib/restricted/aws/s2n/CMakeLists.darwin.txt @@ -52,11 +52,11 @@ target_sources(restricted-aws-s2n PRIVATE ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/bike_r3/gf2x_mul_avx512.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/bike_r3/sampling_avx512.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/bike_r3/gf2x_mul_base_vpclmul.c + ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_basemul_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_fq_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_invntt_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_ntt_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_shuffle_avx2.S - ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_basemul_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c diff --git a/contrib/restricted/aws/s2n/CMakeLists.linux.txt b/contrib/restricted/aws/s2n/CMakeLists.linux.txt index a431e0ec07..40323364f9 100644 --- a/contrib/restricted/aws/s2n/CMakeLists.linux.txt +++ b/contrib/restricted/aws/s2n/CMakeLists.linux.txt @@ -55,11 +55,11 @@ target_sources(restricted-aws-s2n PRIVATE ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/bike_r3/sampling_avx512.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/bike_r3/gf2x_mul_base_vpclmul.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fp_x64_asm.S + ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_basemul_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_fq_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_invntt_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_ntt_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_shuffle_avx2.S - ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/pq-crypto/kyber_r3/kyber512r3_basemul_avx2.S ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_aes_gcm.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_aead_cipher_chacha20_poly1305.c ${CMAKE_SOURCE_DIR}/contrib/restricted/aws/s2n/crypto/s2n_cbc_cipher_3des.c diff --git a/contrib/restricted/aws/s2n/README.md b/contrib/restricted/aws/s2n/README.md index 6456d973d5..c7be8baa46 100644 --- a/contrib/restricted/aws/s2n/README.md +++ b/contrib/restricted/aws/s2n/README.md @@ -52,7 +52,7 @@ CTEST_PARALLEL_LEVEL=$(nproc) ninja -C build test ### Amazonlinux2 -Install dependancies with `./codebuild/bin/install_al2_dependencies.sh` after cloning. +Install dependencies with `./codebuild/bin/install_al2_dependencies.sh` after cloning. ```sh git clone https://github.com/${YOUR_GITHUB_ACCOUNT_NAME}/s2n-tls.git @@ -62,12 +62,19 @@ cmake --build ./build -j $(nproc) CTEST_PARALLEL_LEVEL=$(nproc) make -C build test ``` - ## Have a Question? If you have any questions about Submitting PR's, Opening Issues, s2n-tls API usage, or something similar, we have a public chatroom available here to answer your questions: https://gitter.im/awslabs/s2n Otherwise, if you think you might have found a security impacting issue, please instead follow [our Security Notification Process.](#security-issue-notifications) +## Documentation + +s2n-tls uses [Doxygen](https://doxygen.nl/index.html) to document its public API. The latest s2n-tls documentation can be found on [GitHub pages](https://aws.github.io/s2n-tls/doxygen/). + +Documentation for older versions or branches of s2n-tls can be generated locally. To generate the documentation, install doxygen and run `doxygen docs/doxygen/Doxyfile`. The doxygen documentation can now be found at `docs/doxygen/output/html/index.html`. + +Doxygen installation instructions are available at the [Doxygen](https://doxygen.nl/download.html) webpage. + ## Using s2n-tls The s2n-tls I/O APIs are designed to be intuitive to developers familiar with the widely-used POSIX I/O APIs, and s2n-tls supports blocking, non-blocking, and full-duplex I/O. Additionally there are no locks or mutexes within s2n-tls. @@ -95,7 +102,7 @@ int bytes_written; bytes_written = s2n_send(conn, "Hello World", sizeof("Hello World"), &blocked); ``` -For details on building the s2n-tls library and how to use s2n-tls in an application you are developing, see the [API Reference](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md). +For details on building the s2n-tls library and how to use s2n-tls in an application you are developing, see the [usage guide](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md). ## s2n-tls features diff --git a/contrib/restricted/aws/s2n/api/s2n.h b/contrib/restricted/aws/s2n/api/s2n.h index adc970386c..f1395151db 100644 --- a/contrib/restricted/aws/s2n/api/s2n.h +++ b/contrib/restricted/aws/s2n/api/s2n.h @@ -136,16 +136,32 @@ extern int *s2n_errno_location(void); * * This enum is optimized for use in C switch statements. Each value in the enum represents * an error "category". + * + * s2n-tls organizes errors into different "types" to allow applications to handle error + * values without catching all possibilities. Applications using non-blocking I/O should check + * the error type to determine if the I/O operation failed because it would block or for some other + * error. To retrieve the type for a given error use `s2n_error_get_type()`. Applications should + * perform any error handling logic using these high level types. + * + * See the [Error Handling](https://github.com/aws/s2n-tls/blob/main/docs/USAGE-GUIDE.md#error-handling) section for how the errors should be interpreted. */ typedef enum { - S2N_ERR_T_OK=0, - S2N_ERR_T_IO, - S2N_ERR_T_CLOSED, - S2N_ERR_T_BLOCKED, - S2N_ERR_T_ALERT, - S2N_ERR_T_PROTO, - S2N_ERR_T_INTERNAL, - S2N_ERR_T_USAGE + /** No error */ + S2N_ERR_T_OK=0, + /** Underlying I/O operation failed, check system errno */ + S2N_ERR_T_IO, + /** EOF */ + S2N_ERR_T_CLOSED, + /** Underlying I/O operation would block */ + S2N_ERR_T_BLOCKED, + /** Incoming Alert */ + S2N_ERR_T_ALERT, + /** Failure in some part of the TLS protocol. Ex: CBC verification failure */ + S2N_ERR_T_PROTO, + /** Error internal to s2n-tls. A precondition could have failed. */ + S2N_ERR_T_INTERNAL, + /** User input error. Ex: Providing an invalid cipher preference version */ + S2N_ERR_T_USAGE } s2n_error_type; /** @@ -176,6 +192,13 @@ struct s2n_connection; * prior to 1.1.x. This allows applications or languages that also init OpenSSL to interoperate * with S2N. * + * @warning This function must be called BEFORE s2n_init() to have any effect. It will return an error + * if s2n is already initialized. + * + * @note If you disable this and are using a version of OpenSSL/libcrypto < 1.1.x, you will + * be responsible for library init and cleanup (specifically `OPENSSL_add_all_algorithms()` + * or `OPENSSL_crypto_init()`, and EVP_* APIs will not be usable unless the library is initialized. + * * @returns S2N_SUCCESS on success. S2N_FAILURE on failure */ S2N_API @@ -185,6 +208,12 @@ extern int s2n_crypto_disable_init(void); * Prevents S2N from installing an atexit handler, which allows safe shutdown of S2N from within a * re-entrant shared library * + * @warning This function must be called BEFORE s2n_init() to have any effect. It will return an error + * if s2n is already initialized. + * + * @note This will cause `s2n_cleanup` to do complete cleanup of s2n-tls when called from the main + * thread (the thread `s2n_init` was called from). + * * @returns S2N_SUCCESS on success. S2N_FAILURE on failure */ S2N_API diff --git a/contrib/restricted/aws/s2n/crypto/s2n_composite_cipher_aes_sha.c b/contrib/restricted/aws/s2n/crypto/s2n_composite_cipher_aes_sha.c index 3be8de854f..353c841f87 100644 --- a/contrib/restricted/aws/s2n/crypto/s2n_composite_cipher_aes_sha.c +++ b/contrib/restricted/aws/s2n/crypto/s2n_composite_cipher_aes_sha.c @@ -26,16 +26,19 @@ #include "utils/s2n_safety.h" #include "utils/s2n_blob.h" -/* LibreSSL, BoringSSL and AWS-LC support the cipher, but the interface is different from Openssl's. We - * should define a separate s2n_cipher struct for LibreSSL, BoringSSL and AWS-LC. +/* LibreSSL and BoringSSL support the cipher, but the interface is different from Openssl's. We + * should define a separate s2n_cipher struct for LibreSSL and BoringSSL. */ -#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#if !defined(LIBRESSL_VERSION_NUMBER) && !defined(OPENSSL_IS_BORINGSSL) /* Symbols for AES-SHA1-CBC composite ciphers were added in Openssl 1.0.1 * These composite ciphers exhibit erratic behavior in LibreSSL releases. */ -#if S2N_OPENSSL_VERSION_AT_LEAST(1,0,1) +#if S2N_OPENSSL_VERSION_AT_LEAST(1,0,1) #define S2N_AES_SHA1_COMPOSITE_AVAILABLE #endif +#if defined(AWSLC_API_VERSION) && (AWSLC_API_VERSION <= 17) +#undef S2N_AES_SHA1_COMPOSITE_AVAILABLE +#endif /* Symbols for AES-SHA256-CBC composite ciphers were added in Openssl 1.0.2 * See https://www.openssl.org/news/cl102.txt * These composite ciphers exhibit erratic behavior in LibreSSL releases. @@ -43,7 +46,9 @@ #if S2N_OPENSSL_VERSION_AT_LEAST(1,0,2) #define S2N_AES_SHA256_COMPOSITE_AVAILABLE #endif - +#if defined(AWSLC_API_VERSION) && (AWSLC_API_VERSION <= 17) +#undef S2N_AES_SHA256_COMPOSITE_AVAILABLE +#endif #endif /* Silly accessors, but we avoid using version macro guards in multiple places */ @@ -125,11 +130,11 @@ static uint8_t s2n_composite_cipher_aes256_sha256_available(void) static int s2n_composite_cipher_aes_sha_initial_hmac(struct s2n_session_key *key, uint8_t *sequence_number, uint8_t content_type, uint16_t protocol_version, uint16_t payload_and_eiv_len, int *extra) { - /* BoringSSL and AWS-LC do not support these composite ciphers with the existing EVP API, and they took out the - * constants used below. This method should never be called with BoringSSL or AWS-LC because the isAvaliable checked - * will fail. Instead of defining a possibly dangerous default or hard coding this to 0x16 error out with BoringSSL and AWS-LC. + /* BoringSSL and AWS-LC(AWSLC_API_VERSION <= 17) do not support these composite ciphers with the existing EVP API, and they took out the + * constants used below. This method should never be called with BoringSSL or AWS-LC(AWSLC_API_VERSION <= 17) because the isAvaliable checked + * will fail. Instead of defining a possibly dangerous default or hard coding this to 0x16 error out with BoringSSL and AWS-LC(AWSLC_API_VERSION <= 17). */ -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#if defined(OPENSSL_IS_BORINGSSL) || (defined(AWSLC_API_VERSION) && (AWSLC_API_VERSION <= 17)) POSIX_BAIL(S2N_ERR_NO_SUPPORTED_LIBCRYPTO_API); #else uint8_t ctrl_buf[S2N_TLS12_AAD_LEN]; diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/ec_isogeny_r1.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/ec_isogeny_r1.c index b83e7a3ae3..50dfd68373 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/ec_isogeny_r1.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/ec_isogeny_r1.c @@ -31,11 +31,10 @@ void xDBLe(const point_proj_t P, point_proj_t Q, const f2elm_t *A24plus, const f { // Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A+2C and 4C. // Output: projective Montgomery x-coordinates Q <- (2^e)*P. - int i; copy_words((const digit_t*)P, (digit_t*)Q, 2*2*NWORDS_FIELD); - for (i = 0; i < e; i++) { + for (int i = 0; i < e; i++) { xDBL(Q, Q, A24plus, C24); } } @@ -121,11 +120,10 @@ void xTPLe(const point_proj_t P, point_proj_t Q, const f2elm_t *A24minus, const { // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A24plus = A+2C and A24minus = A-2C. // Output: projective Montgomery x-coordinates Q <- (3^e)*P. - int i; copy_words((const digit_t*)P, (digit_t*)Q, 2*2*NWORDS_FIELD); - for (i = 0; i < e; i++) { + for (int i = 0; i < e; i++) { xTPL(Q, Q, A24minus, A24plus); } } @@ -344,3 +342,47 @@ static void LADDER3PT(const f2elm_t *xP, const f2elm_t *xQ, const f2elm_t *xPQ, fp2mul_mont(&R2->X, &R->Z, &R2->X); } } + +void xTPL_fast(const point_proj_t P, point_proj_t Q, const f2elm_t *A2) +{ // Montgomery curve (E: y^2 = x^3 + A*x^2 + x) x-only tripling at a cost of 5M + 6S + 11A. + // Input : projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constant A/2. + // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3). + f2elm_t _t1, _t2, _t3, _t4; + f2elm_t *t1=&_t1, *t2=&_t2, *t3=&_t3, *t4=&_t4; + + fp2sqr_mont(&P->X, t1); // t1 = x^2 + fp2sqr_mont(&P->Z, t2); // t2 = z^2 + fp2add(t1, t2, t3); // t3 = t1 + t2 + fp2add(&P->X, &P->Z, t4); // t4 = x + z + fp2sqr_mont(t4, t4); // t4 = t4^2 + fp2sub(t4, t3, t4); // t4 = t4 - t3 + fp2mul_mont(A2, t4, t4); // t4 = t4*A2 + fp2add(t3, t4, t4); // t4 = t4 + t3 + fp2sub(t1, t2, t3); // t3 = t1 - t2 + fp2sqr_mont(t3, t3); // t3 = t3^2 + fp2mul_mont(t1, t4, t1); // t1 = t1*t4 + fp2add(t1, t1, t1); // t1 = 2*t1 + fp2add(t1, t1, t1); // t1 = 4*t1 + fp2sub(t1, t3, t1); // t1 = t1 - t3 + fp2sqr_mont(t1, t1); // t1 = t1^2 + fp2mul_mont(t2, t4, t2); // t2 = t2*t4 + fp2add(t2, t2, t2); // t2 = 2*t2 + fp2add(t2, t2, t2); // t2 = 4*t2 + fp2sub(t2, t3, t2); // t2 = t2 - t3 + fp2sqr_mont(t2, t2); // t2 = t2^2 + fp2mul_mont(&P->X, t2, &Q->X); // x = x*t2 + fp2mul_mont(&P->Z, t1, &Q->Z); // z = z*t1 +} + + +void xTPLe_fast(point_proj_t P, point_proj_t Q, const f2elm_t *A2, int e) +{ // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings. e triplings in E costs e*(5M + 6S + 11A) + // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z, Montgomery curve constant A2 = A/2 and the number of triplings e. + // Output: projective Montgomery x-coordinates Q <- [3^e]P. + + copy_words((digit_t*)P, (digit_t*)Q, 2 * 2 * NWORDS_FIELD); + + for (int i = 0; i < e; i++) { + xTPL_fast(Q, Q, A2); + } +} diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/fpx_r1.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/fpx_r1.c index 9661567985..82ae6cfceb 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/fpx_r1.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/fpx_r1.c @@ -333,6 +333,17 @@ void from_fp2mont(const f2elm_t *ma, f2elm_t *c) from_mont(ma->e[1], c->e[1]); } +unsigned int is_felm_zero(const felm_t x) +{ // Is x = 0? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise. + // SECURITY NOTE: This function does not run in constant-time. + + for (unsigned int i = 0; i < NWORDS_FIELD; i++) { + if (x[i] != 0) { + return 0; + } + } + return 1; +} unsigned int mp_add(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) { // Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit. diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sidh_r1.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sidh_r1.c index bdf2834121..3f49fa1461 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sidh_r1.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sidh_r1.c @@ -268,6 +268,49 @@ int EphemeralSecretAgreement_A(const digit_t* PrivateKeyA, const unsigned char* return S2N_SUCCESS; } +int sike_p503_r1_publickey_validation(const f2elm_t *PKB, const f2elm_t *A) +{ // Public key validation + point_proj_t P = { 0 }, Q = { 0 }; + f2elm_t _A2={0}, _tmp1={0}, _tmp2={0}; + f2elm_t *A2=&_A2, *tmp1=&_tmp1, *tmp2=&_tmp2; + + // Verify that P and Q generate E_A[3^e_3] by checking that [3^(e_3-1)]P != [+-3^(e_3-1)]Q + fp2div2(A, A2); + fp2copy(&PKB[0], &P->X); + fpcopy((const digit_t*)&Montgomery_one, (digit_t*)&P->Z); + fp2copy(&PKB[1], &Q->X); + fpcopy((const digit_t*)&Montgomery_one, (digit_t*)&Q->Z); + + xTPLe_fast(P, P, A2, MAX_Bob - 1); + xTPLe_fast(Q, Q, A2, MAX_Bob - 1); + fp2correction(&P->Z); + fp2correction(&Q->Z); + + if ((is_felm_zero((P->Z.e)[0]) && is_felm_zero((P->Z.e)[1])) || (is_felm_zero((Q->Z.e)[0]) && is_felm_zero((Q->Z.e)[1]))) { + return 1; + } + + fp2mul_mont(&P->X, &Q->Z, tmp1); + fp2mul_mont(&P->Z, &Q->X, tmp2); + fp2correction(tmp1); + fp2correction(tmp2); + + if (memcmp((uint8_t*)tmp1, (uint8_t*)tmp2, FP2_ENCODED_BYTES) == 0) { + return 1; + } + + // Check that Ord(P) = Ord(Q) = 3^(e_3) + xTPL_fast(P, P, A2); + xTPL_fast(Q, Q, A2); + fp2correction(&P->Z); + fp2correction(&Q->Z); + + if (!is_felm_zero((P->Z.e)[0]) || !is_felm_zero((P->Z.e)[1]) || !is_felm_zero((Q->Z.e)[0]) || !is_felm_zero((Q->Z.e)[1])) { + return 1; + } + + return 0; +} int EphemeralSecretAgreement_B(const digit_t* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB) { // Bob's ephemeral shared secret computation @@ -292,6 +335,11 @@ int EphemeralSecretAgreement_B(const digit_t* PrivateKeyB, const unsigned char* fp2add(A, A24minus, A24plus); fp2sub(A, A24minus, A24minus); + // Always perform public key validation before using peer's public key + if (sike_p503_r1_publickey_validation(PKB, A) == 1) { + return 1; + } + // Retrieve kernel point LADDER3PT(&PKB[0], &PKB[1], &PKB[2], PrivateKeyB, BOB, R, A); diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_kem.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_kem.c index ee905ca74a..973640e156 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_kem.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_kem.c @@ -96,13 +96,16 @@ int SIKE_P503_r1_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, cons unsigned char c0_[SIKE_P503_R1_PUBLIC_KEY_BYTES]; unsigned char temp[SIKE_P503_R1_CIPHERTEXT_BYTES+MSG_BYTES]; unsigned int i; + bool dont_copy = 1; digit_t _sk[SECRETKEY_B_BYTES/sizeof(digit_t)]; memcpy(_sk, sk + MSG_BYTES, SECRETKEY_B_BYTES); // Decrypt - EphemeralSecretAgreement_B(_sk, ct, jinvariant_); + if (!(EphemeralSecretAgreement_B(_sk, ct, jinvariant_) == 0)) { + goto S2N_SIKE_P503_R1_HASHING; + } cshake256_simple(h_, MSG_BYTES, P, jinvariant_, FP2_ENCODED_BYTES); for (i = 0; i < MSG_BYTES; i++) temp[i] = ct[i + SIKE_P503_R1_PUBLIC_KEY_BYTES] ^ h_[i]; @@ -120,7 +123,8 @@ int SIKE_P503_r1_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, cons // Note: This step deviates from the NIST supplied code by using constant time operations. // We only want to copy the data if c0_ and ct are different - bool dont_copy = s2n_constant_time_equals(c0_, ct, SIKE_P503_R1_PUBLIC_KEY_BYTES); + dont_copy = s2n_constant_time_equals(c0_, ct, SIKE_P503_R1_PUBLIC_KEY_BYTES); +S2N_SIKE_P503_R1_HASHING: // The last argument to s2n_constant_time_copy_or_dont is dont and thus prevents the copy when non-zero/true s2n_constant_time_copy_or_dont(temp, sk, MSG_BYTES, dont_copy); diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_namespace.h b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_namespace.h index 68d9b40c4b..b3e37982fa 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_namespace.h +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r1/sike_r1_namespace.h @@ -20,6 +20,8 @@ #define xDBLADD xDBLADD_r1 #define swap_points swap_points_r1 #define LADDER3PT LADDER3PT_r1 +#define xTPL_fast xTPL_fast_r1 +#define xTPLe_fast xTPLe_fast_r1 #define load64 load64_r1 #define store64 store64_r1 #define KeccakF1600_StatePermute KeccakF1600_StatePermute_r1 @@ -39,6 +41,7 @@ #define mp_subfast mp_subfast_r1 #define to_fp2mont to_fp2mont_r1 #define from_fp2mont from_fp2mont_r1 +#define is_felm_zero is_felm_zero_r1 #define mp_add mp_add_r1 #define mp_shiftr1 mp_shiftr1_r1 #define Alice_order Alice_order_r1 diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.c index e5ae4e7c7e..a2e3dd969b 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.c @@ -33,11 +33,9 @@ void xDBL(const point_proj_t P, point_proj_t Q, const f2elm_t *A24plus, const f2 * Output: projective Montgomery x-coordinates Q <- (2^e)*P. */ void xDBLe(const point_proj_t P, point_proj_t Q, const f2elm_t *A24plus, const f2elm_t *C24, const int e) { - int i; - copy_words((const digit_t*)P, (digit_t*)Q, 2*2*S2N_SIKE_P434_R3_NWORDS_FIELD); - for (i = 0; i < e; i++) { + for (int i = 0; i < e; i++) { xDBL(Q, Q, A24plus, C24); } } @@ -121,11 +119,9 @@ void xTPL(const point_proj_t P, point_proj_t Q, const f2elm_t *A24minus, const f * Output: projective Montgomery x-coordinates Q <- (3^e)*P. */ void xTPLe(const point_proj_t P, point_proj_t Q, const f2elm_t *A24minus, const f2elm_t *A24plus, const int e) { - int i; - copy_words((const digit_t*)P, (digit_t*)Q, 2*2*S2N_SIKE_P434_R3_NWORDS_FIELD); - for (i = 0; i < e; i++) { + for (int i = 0; i < e; i++) { xTPL(Q, Q, A24minus, A24plus); } } @@ -346,3 +342,47 @@ void LADDER3PT(const f2elm_t *xP, const f2elm_t *xQ, const f2elm_t *xPQ, const d mask = 0 - (digit_t)swap; swap_points(R, R2, mask); } + +void xTPL_fast(const point_proj_t P, point_proj_t Q, const f2elm_t *A2) +{ // Montgomery curve (E: y^2 = x^3 + A*x^2 + x) x-only tripling at a cost of 5M + 6S + 11A. + // Input : projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constant A/2. + // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3). + f2elm_t _t1, _t2, _t3, _t4; + f2elm_t *t1=&_t1, *t2=&_t2, *t3=&_t3, *t4=&_t4; + + fp2sqr_mont(&P->X, t1); // t1 = x^2 + fp2sqr_mont(&P->Z, t2); // t2 = z^2 + fp2add(t1, t2, t3); // t3 = t1 + t2 + fp2add(&P->X, &P->Z, t4); // t4 = x + z + fp2sqr_mont(t4, t4); // t4 = t4^2 + fp2sub(t4, t3, t4); // t4 = t4 - t3 + fp2mul_mont(A2, t4, t4); // t4 = t4*A2 + fp2add(t3, t4, t4); // t4 = t4 + t3 + fp2sub(t1, t2, t3); // t3 = t1 - t2 + fp2sqr_mont(t3, t3); // t3 = t3^2 + fp2mul_mont(t1, t4, t1); // t1 = t1*t4 + fp2add(t1, t1, t1); // t1 = 2*t1 + fp2add(t1, t1, t1); // t1 = 4*t1 + fp2sub(t1, t3, t1); // t1 = t1 - t3 + fp2sqr_mont(t1, t1); // t1 = t1^2 + fp2mul_mont(t2, t4, t2); // t2 = t2*t4 + fp2add(t2, t2, t2); // t2 = 2*t2 + fp2add(t2, t2, t2); // t2 = 4*t2 + fp2sub(t2, t3, t2); // t2 = t2 - t3 + fp2sqr_mont(t2, t2); // t2 = t2^2 + fp2mul_mont(&P->X, t2, &Q->X); // x = x*t2 + fp2mul_mont(&P->Z, t1, &Q->Z); // z = z*t1 +} + + +void xTPLe_fast(point_proj_t P, point_proj_t Q, const f2elm_t *A2, int e) +{ // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings. e triplings in E costs e*(5M + 6S + 11A) + // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z, Montgomery curve constant A2 = A/2 and the number of triplings e. + // Output: projective Montgomery x-coordinates Q <- [3^e]P. + + copy_words((digit_t*)P, (digit_t*)Q, 2 * 2 * S2N_SIKE_P434_R3_NWORDS_FIELD); + + for (int i = 0; i < e; i++) { + xTPL_fast(Q, Q, A2); + } +} diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.h b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.h index 44245ec726..c09111e9d0 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.h +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_ec_isogeny.h @@ -44,3 +44,9 @@ void j_inv(const f2elm_t *A, const f2elm_t *C, f2elm_t *jinv); #define LADDER3PT S2N_SIKE_P434_R3_NAMESPACE(LADDER3PT) void LADDER3PT(const f2elm_t *xP, const f2elm_t *xQ, const f2elm_t *xPQ, const digit_t *m, const unsigned int AliceOrBob, point_proj_t R, const f2elm_t *A); + +#define xTPL_fast S2N_SIKE_P434_R3_NAMESPACE(xTPL_fast) +void xTPL_fast(const point_proj_t P, point_proj_t Q, const f2elm_t *A2); + +#define xTPLe_fast S2N_SIKE_P434_R3_NAMESPACE(xTPLe_fast) +void xTPLe_fast(point_proj_t P, point_proj_t Q, const f2elm_t *A2, int e); diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.c index 40c61144e4..d9cb686edf 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.c @@ -122,6 +122,28 @@ void fp2div2(const f2elm_t *a, f2elm_t *c) fpdiv2_434(a->e[1], c->e[1]); } +void fpcorrection(digit_t* a) +{ // Modular correction to reduce field element a in [0, 2*p434-1] to [0, p434-1]. + unsigned int i, borrow = 0; + digit_t mask; + + for (i = 0; i < S2N_SIKE_P434_R3_NWORDS_FIELD; i++) { + S2N_SIKE_P434_R3_SUBC(borrow, a[i], ((const digit_t*)p434)[i], borrow, a[i]); + } + mask = 0 - (digit_t)borrow; + + borrow = 0; + for (i = 0; i < S2N_SIKE_P434_R3_NWORDS_FIELD; i++) { + S2N_SIKE_P434_R3_ADDC(borrow, a[i], ((const digit_t*)p434)[i] & mask, borrow, a[i]); + } +} + +void fp2correction(f2elm_t *a) +{ // Modular correction, a = a in GF(p^2). + fpcorrection(a->e[0]); + fpcorrection(a->e[1]); +} + /* Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit. */ unsigned int mp_add(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords) { @@ -411,6 +433,18 @@ void mp_shiftr1(digit_t* x, const unsigned int nwords) x[nwords-1] >>= 1; } +unsigned int is_felm_zero(const felm_t x) +{ // Is x = 0? return 1 (TRUE) if condition is true, 0 (FALSE) otherwise. + // SECURITY NOTE: This function does not run in constant-time. + + for (unsigned int i = 0; i < S2N_SIKE_P434_R3_NWORDS_FIELD; i++) { + if (x[i] != 0) { + return 0; + } + } + return 1; +} + void decode_to_digits(const unsigned char* x, digit_t* dec, int nbytes, int ndigits) { dec[ndigits - 1] = 0; diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.h b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.h index bce1849ce1..c6d8e8dc94 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.h +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_fpx.h @@ -25,6 +25,9 @@ void fp2copy(const f2elm_t *a, f2elm_t *c); #define fp2div2 S2N_SIKE_P434_R3_NAMESPACE(fp2div2) void fp2div2(const f2elm_t *a, f2elm_t *c); +#define fp2correction S2N_SIKE_P434_R3_NAMESPACE(fp2correction) +void fp2correction(f2elm_t *a); + #define mp_add S2N_SIKE_P434_R3_NAMESPACE(mp_add) unsigned int mp_add(const digit_t* a, const digit_t* b, digit_t* c, const unsigned int nwords); @@ -40,6 +43,9 @@ void fp2inv_mont(f2elm_t *a); #define mp_shiftr1 S2N_SIKE_P434_R3_NAMESPACE(mp_shiftr1) void mp_shiftr1(digit_t* x, const unsigned int nwords); +#define is_felm_zero S2N_SIKE_P434_R3_NAMESPACE(is_felm_zero) +unsigned int is_felm_zero(const felm_t x); + #define decode_to_digits S2N_SIKE_P434_R3_NAMESPACE(decode_to_digits) void decode_to_digits(const unsigned char* x, digit_t* dec, int nbytes, int ndigits); diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_kem.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_kem.c index b32add7723..9ce254fbf1 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_kem.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_kem.c @@ -81,9 +81,13 @@ int s2n_sike_p434_r3_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, unsigned char h_[S2N_SIKE_P434_R3_MSG_BYTES]; unsigned char c0_[S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES]; unsigned char temp[S2N_SIKE_P434_R3_CIPHERTEXT_BYTES+S2N_SIKE_P434_R3_MSG_BYTES]; + bool dont_copy = 1; /* Decrypt */ - EphemeralSecretAgreement_B(sk + S2N_SIKE_P434_R3_MSG_BYTES, ct, jinvariant_); + if (!(EphemeralSecretAgreement_B(sk + S2N_SIKE_P434_R3_MSG_BYTES, ct, jinvariant_) == 0)) { + goto S2N_SIKE_P434_R3_HASHING; + } + shake256(h_, S2N_SIKE_P434_R3_MSG_BYTES, jinvariant_, S2N_SIKE_P434_R3_FP2_ENCODED_BYTES); for (int i = 0; i < S2N_SIKE_P434_R3_MSG_BYTES; i++) { temp[i] = ct[i + S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES] ^ h_[i]; @@ -103,7 +107,8 @@ int s2n_sike_p434_r3_crypto_kem_dec(unsigned char *ss, const unsigned char *ct, * * If c0_ and ct are equal, then decaps succeeded and we skip the overwrite and output * the actual shared secret: ss = H(m||ct) (dont_copy = true). */ - bool dont_copy = s2n_constant_time_equals(c0_, ct, S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES); + dont_copy = s2n_constant_time_equals(c0_, ct, S2N_SIKE_P434_R3_PUBLIC_KEY_BYTES); +S2N_SIKE_P434_R3_HASHING: POSIX_GUARD(s2n_constant_time_copy_or_dont(temp, sk, S2N_SIKE_P434_R3_MSG_BYTES, dont_copy)); memcpy(&temp[S2N_SIKE_P434_R3_MSG_BYTES], ct, S2N_SIKE_P434_R3_CIPHERTEXT_BYTES); shake256(ss, S2N_SIKE_P434_R3_SHARED_SECRET_BYTES, temp, S2N_SIKE_P434_R3_CIPHERTEXT_BYTES+S2N_SIKE_P434_R3_MSG_BYTES); diff --git a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_sidh.c b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_sidh.c index f570e27e32..8bd5124b41 100644 --- a/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_sidh.c +++ b/contrib/restricted/aws/s2n/pq-crypto/sike_r3/sikep434r3_sidh.c @@ -245,15 +245,57 @@ int EphemeralSecretAgreement_A(const unsigned char* PrivateKeyA, const unsigned return 0; } +int sike_p434_r3_publickey_validation(const f2elm_t *PKB, const f2elm_t *A) +{ // Public key validation + point_proj_t P = { 0 }, Q = { 0 }; + f2elm_t _A2={0}, _tmp1={0}, _tmp2={0}; + f2elm_t *A2=&_A2, *tmp1=&_tmp1, *tmp2=&_tmp2; + + // Verify that P and Q generate E_A[3^e_3] by checking that [3^(e_3-1)]P != [+-3^(e_3-1)]Q + fp2div2(A, A2); + fp2copy(&PKB[0], &P->X); + fpcopy((const digit_t*)&Montgomery_one, (digit_t*)&P->Z); + fp2copy(&PKB[1], &Q->X); + fpcopy((const digit_t*)&Montgomery_one, (digit_t*)&Q->Z); + + xTPLe_fast(P, P, A2, S2N_SIKE_P434_R3_MAX_BOB - 1); + xTPLe_fast(Q, Q, A2, S2N_SIKE_P434_R3_MAX_BOB - 1); + fp2correction(&P->Z); + fp2correction(&Q->Z); + + if ((is_felm_zero((P->Z.e)[0]) && is_felm_zero((P->Z.e)[1])) || (is_felm_zero((Q->Z.e)[0]) && is_felm_zero((Q->Z.e)[1]))) { + return 1; + } + + fp2mul_mont(&P->X, &Q->Z, tmp1); + fp2mul_mont(&P->Z, &Q->X, tmp2); + fp2correction(tmp1); + fp2correction(tmp2); + + if (memcmp((uint8_t*)tmp1, (uint8_t*)tmp2, S2N_SIKE_P434_R3_FP2_ENCODED_BYTES) == 0) { + return 1; + } + + // Check that Ord(P) = Ord(Q) = 3^(e_3) + xTPL_fast(P, P, A2); + xTPL_fast(Q, Q, A2); + fp2correction(&P->Z); + fp2correction(&Q->Z); + + if (!is_felm_zero((P->Z.e)[0]) || !is_felm_zero((P->Z.e)[1]) || !is_felm_zero((Q->Z.e)[0]) || !is_felm_zero((Q->Z.e)[1])) { + return 1; + } + + return 0; +} + /* Bob's ephemeral shared secret computation * It produces a shared secret key SharedSecretB using his secret key PrivateKeyB and Alice's public key PublicKeyA * Inputs: Bob's PrivateKeyB is an integer in the range [0, 2^Floor(Log(2,oB)) - 1]. * Alice's PublicKeyA consists of 3 elements in GF(p^2) encoded by removing leading 0 bytes. * Output: a shared secret SharedSecretB that consists of one element in GF(p^2) encoded * by removing leading 0 bytes. */ -int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, - unsigned char* SharedSecretB) -{ +int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned char* PublicKeyA, unsigned char* SharedSecretB) { point_proj_t R, pts[S2N_SIKE_P434_R3_MAX_INT_POINTS_BOB]; f2elm_t coeff[3], PKB[3], _jinv; f2elm_t _A24plus = {0}, _A24minus = {0}, _A = {0}; @@ -272,6 +314,11 @@ int EphemeralSecretAgreement_B(const unsigned char* PrivateKeyB, const unsigned mp2_add(A, A24minus, A24plus); mp2_sub_p2(A, A24minus, A24minus); + // Always perform public key validation before using peer's public key + if (sike_p434_r3_publickey_validation(PKB, A) == 1) { + return 1; + } + /* Retrieve kernel point */ decode_to_digits(PrivateKeyB, SecretKeyB, S2N_SIKE_P434_R3_SECRETKEY_B_BYTES, S2N_SIKE_P434_R3_NWORDS_ORDER); LADDER3PT(&PKB[0], &PKB[1], &PKB[2], SecretKeyB, S2N_SIKE_P434_R3_BOB, R, A); diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c index bbc37e475a..067a9d3eaf 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_client_supported_versions.c @@ -115,7 +115,8 @@ static int s2n_extensions_client_supported_versions_process(struct s2n_connectio conn->actual_protocol_version = MAX(client_version, conn->actual_protocol_version); } - S2N_ERROR_IF(conn->actual_protocol_version == s2n_unknown_protocol_version, S2N_ERR_UNKNOWN_PROTOCOL_VERSION); + POSIX_ENSURE(conn->client_protocol_version != s2n_unknown_protocol_version, S2N_ERR_UNKNOWN_PROTOCOL_VERSION); + POSIX_ENSURE(conn->actual_protocol_version != s2n_unknown_protocol_version, S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); return S2N_SUCCESS; } @@ -126,10 +127,12 @@ static int s2n_client_supported_versions_recv(struct s2n_connection *conn, struc return S2N_SUCCESS; } - if (s2n_extensions_client_supported_versions_process(conn, in) < 0) { + int result = s2n_extensions_client_supported_versions_process(conn, in); + if (result != S2N_SUCCESS) { s2n_queue_reader_unsupported_protocol_version_alert(conn); - POSIX_BAIL(S2N_ERR_BAD_MESSAGE); + POSIX_ENSURE(s2n_errno != S2N_ERR_SAFETY, S2N_ERR_BAD_MESSAGE); } + POSIX_GUARD(result); return S2N_SUCCESS; } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c index 1c808f1d8c..4e4aa5d3bc 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_extension_type.c @@ -147,6 +147,12 @@ int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_conn *# If the original session did not use the "extended_master_secret" *# extension but the new ServerHello contains the extension, the *# client MUST abort the handshake. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# As with the ServerHello, a HelloRetryRequest MUST NOT contain any + *# extensions that were not first offered by the client in its + *# ClientHello, with the exception of optionally the "cookie" (see + *# Section 4.2.2) extension. **/ if (extension_type->is_response && !S2N_CBIT_TEST(conn->extension_requests_sent, extension_id)) { @@ -161,7 +167,9 @@ int s2n_extension_recv(const s2n_extension_type *extension_type, struct s2n_conn POSIX_GUARD(extension_type->recv(conn, in)); /* Set request bit flag */ - if (!extension_type->is_response) { + if (extension_type->is_response) { + S2N_CBIT_SET(conn->extension_responses_received, extension_id); + } else { S2N_CBIT_SET(conn->extension_requests_received, extension_id); } diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c index 46f5deb1d5..02fa59ac3e 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_key_share.c @@ -28,7 +28,7 @@ static int s2n_server_key_share_recv(struct s2n_connection *conn, struct s2n_stu const s2n_extension_type s2n_server_key_share_extension = { .iana_value = TLS_EXTENSION_KEY_SHARE, .minimum_version = S2N_TLS13, - .is_response = false, + .is_response = true, .send = s2n_server_key_share_send, .recv = s2n_server_key_share_recv, .should_send = s2n_extension_always_send, diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c index 9a36caff9f..09e525fa93 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_psk.c @@ -60,9 +60,9 @@ static int s2n_server_psk_recv(struct s2n_connection *conn, struct s2n_stuffer * * Any other mode selected by the server is invalid because it was not offered by the client. * A key_share extension MUST have been received in order to use a pre-shared key in (EC)DHE key exchange mode. */ - s2n_extension_type_id key_share_ext_id; + s2n_extension_type_id key_share_ext_id = s2n_unsupported_extension; POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_KEY_SHARE, &key_share_ext_id)); - POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_requests_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); + POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_responses_received, key_share_ext_id), S2N_ERR_MISSING_EXTENSION); /* From RFC section: https://tools.ietf.org/html/rfc8446#section-4.2.8.1 * Any future values that are allocated must ensure that the transmitted protocol messages diff --git a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c index 53e387d8cc..55a3e4ebd2 100644 --- a/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c +++ b/contrib/restricted/aws/s2n/tls/extensions/s2n_server_supported_versions.c @@ -70,6 +70,18 @@ static int s2n_extensions_server_supported_versions_process(struct s2n_connectio uint16_t server_version = (server_version_parts[0] * 10) + server_version_parts[1]; + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# The value of selected_version in the HelloRetryRequest + *# "supported_versions" extension MUST be retained in the ServerHello, + *# and a client MUST abort the handshake with an "illegal_parameter" + *# alert if the value changes. + **/ + if (s2n_is_hello_retry_handshake(conn) && !s2n_is_hello_retry_message(conn)) { + POSIX_ENSURE(conn->server_protocol_version == server_version, + S2N_ERR_BAD_MESSAGE); + } + POSIX_ENSURE_GTE(server_version, S2N_TLS13); POSIX_ENSURE_LTE(server_version, highest_supported_version); POSIX_ENSURE_GTE(server_version, minimum_supported_version); diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c index 10407f487a..b7268e55f5 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.c @@ -82,6 +82,33 @@ const struct s2n_cipher_preferences cipher_preferences_20210831 = { .suites = cipher_suites_20210831, }; +/* + * These cipher suites were chosen based on the following specification: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf + */ +struct s2n_cipher_suite *cipher_suites_default_fips[] = { + /* tls1.2 with ECDSA */ + &s2n_ecdhe_ecdsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_ecdsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_ecdsa_with_aes_256_cbc_sha384, + + /* tls1.2 with RSA */ + &s2n_ecdhe_rsa_with_aes_128_gcm_sha256, + &s2n_ecdhe_rsa_with_aes_256_gcm_sha384, + &s2n_ecdhe_rsa_with_aes_128_cbc_sha256, + &s2n_ecdhe_rsa_with_aes_256_cbc_sha384, + &s2n_dhe_rsa_with_aes_128_cbc_sha256, + &s2n_dhe_rsa_with_aes_256_cbc_sha256, + &s2n_dhe_rsa_with_aes_128_gcm_sha256, + &s2n_dhe_rsa_with_aes_256_gcm_sha384, +}; + +const struct s2n_cipher_preferences cipher_preferences_default_fips = { + .count = s2n_array_len(cipher_suites_default_fips), + .suites = cipher_suites_default_fips, +}; + /* s2n's list of cipher suites, in order of preference, as of 2014-06-01 */ struct s2n_cipher_suite *cipher_suites_20140601[] = { &s2n_dhe_rsa_with_aes_128_cbc_sha256, diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h index 7156c68185..c7305a3908 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_preferences.h @@ -51,6 +51,7 @@ extern const struct s2n_cipher_preferences cipher_preferences_20210816_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20210825; extern const struct s2n_cipher_preferences cipher_preferences_20210825_gcm; extern const struct s2n_cipher_preferences cipher_preferences_20210831; +extern const struct s2n_cipher_preferences cipher_preferences_default_fips; extern const struct s2n_cipher_preferences cipher_preferences_test_all; diff --git a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c index cf82b7c6f4..e18efb0c87 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c +++ b/contrib/restricted/aws/s2n/tls/s2n_cipher_suites.c @@ -1124,6 +1124,23 @@ int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_C POSIX_GUARD(s2n_connection_get_security_policy(conn, &security_policy)); POSIX_ENSURE_REF(security_policy); + /** + * Ensure that the wire cipher suite is contained in the security + * policy, and thus was offered by the client. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.3 + *# A client which receives a + *# cipher suite that was not offered MUST abort the handshake with an + *# "illegal_parameter" alert. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# A client which receives a cipher suite that was not offered MUST + *# abort the handshake. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Upon receipt of a HelloRetryRequest, the client MUST check the + *# legacy_version, legacy_session_id_echo, cipher_suite + **/ struct s2n_cipher_suite *cipher_suite = NULL; for (size_t i = 0; i < security_policy->cipher_preferences->count; i++) { const uint8_t *ours = security_policy->cipher_preferences->suites[i]->iana_value; @@ -1133,6 +1150,7 @@ int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_C } } POSIX_ENSURE(cipher_suite != NULL, S2N_ERR_CIPHER_NOT_SUPPORTED); + POSIX_ENSURE(cipher_suite->available, S2N_ERR_CIPHER_NOT_SUPPORTED); /** Clients MUST verify @@ -1145,7 +1163,13 @@ int s2n_set_cipher_as_client(struct s2n_connection *conn, uint8_t wire[S2N_TLS_C S2N_ERR_CIPHER_NOT_SUPPORTED); } - /* Verify cipher suite sent in server hello is the same as sent in hello retry */ + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Upon receiving + *# the ServerHello, clients MUST check that the cipher suite supplied in + *# the ServerHello is the same as that in the HelloRetryRequest and + *# otherwise abort the handshake with an "illegal_parameter" alert. + **/ if (s2n_is_hello_retry_handshake(conn) && !s2n_is_hello_retry_message(conn)) { POSIX_ENSURE(conn->secure.cipher_suite->iana_value == cipher_suite->iana_value, S2N_ERR_CIPHER_NOT_SUPPORTED); return S2N_SUCCESS; diff --git a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c index 149f4d4b53..0553d1fe14 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_client_hello.c +++ b/contrib/restricted/aws/s2n/tls/s2n_client_hello.c @@ -433,9 +433,28 @@ int s2n_process_client_hello(struct s2n_connection *conn) /* Find potential certificate matches before we choose the cipher. */ POSIX_GUARD(s2n_conn_find_name_matching_certs(conn)); + /* Save the previous cipher suite */ + uint8_t previous_cipher_suite_iana[S2N_TLS_CIPHER_SUITE_LEN] = { 0 }; + POSIX_CHECKED_MEMCPY(previous_cipher_suite_iana, conn->secure.cipher_suite->iana_value, S2N_TLS_CIPHER_SUITE_LEN); + /* Now choose the ciphers we have certs for. */ POSIX_GUARD(s2n_set_cipher_as_tls_server(conn, client_hello->cipher_suites.data, client_hello->cipher_suites.size / 2)); + /* Check if this is the second client hello in a hello retry handshake */ + if (s2n_is_hello_retry_handshake(conn) && + conn->handshake.message_number > 0) { + + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Servers MUST ensure that they negotiate the + *# same cipher suite when receiving a conformant updated ClientHello (if + *# the server selects the cipher suite as the first step in the + *# negotiation, then this will happen automatically). + **/ + POSIX_ENSURE(s2n_constant_time_equals(previous_cipher_suite_iana, conn->secure.cipher_suite->iana_value, + S2N_TLS_CIPHER_SUITE_LEN),S2N_ERR_BAD_MESSAGE); + } + /* If we're using a PSK, we don't need to choose a signature algorithm or certificate, * because no additional auth is required. */ if (conn->psk_params.chosen_psk != NULL) { diff --git a/contrib/restricted/aws/s2n/tls/s2n_connection.h b/contrib/restricted/aws/s2n/tls/s2n_connection.h index 09e1f19724..be375551b1 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_connection.h +++ b/contrib/restricted/aws/s2n/tls/s2n_connection.h @@ -144,7 +144,7 @@ struct s2n_connection { void *send_io_context; void *recv_io_context; - /* Track request extensions to ensure correct response extension behavior. + /* Track request/response extensions to ensure correct response extension behavior. * * We need to track client and server extensions separately because some * extensions (like request_status and other Certificate extensions) can @@ -152,6 +152,7 @@ struct s2n_connection { */ s2n_extension_bitfield extension_requests_sent; s2n_extension_bitfield extension_requests_received; + s2n_extension_bitfield extension_responses_received; /* Is this connection a client or a server connection */ s2n_mode mode; diff --git a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c index f1632a0a53..53b9e95a13 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c +++ b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.c @@ -33,6 +33,15 @@ const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20200310[] = { &s2n_ecc_curve_secp384r1, }; +/* + * These curves were chosen based on the following specification: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf + */ +const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_default_fips[] = { + &s2n_ecc_curve_secp256r1, + &s2n_ecc_curve_secp384r1, +}; + const struct s2n_ecc_named_curve *const s2n_ecc_pref_list_20201021[] = { &s2n_ecc_curve_secp256r1, &s2n_ecc_curve_secp384r1, @@ -62,6 +71,11 @@ const struct s2n_ecc_preferences s2n_ecc_preferences_20200310 = { .ecc_curves = s2n_ecc_pref_list_20200310, }; +const struct s2n_ecc_preferences s2n_ecc_preferences_default_fips = { + .count = s2n_array_len(s2n_ecc_pref_list_default_fips), + .ecc_curves = s2n_ecc_pref_list_default_fips, +}; + const struct s2n_ecc_preferences s2n_ecc_preferences_20201021 = { .count = s2n_array_len(s2n_ecc_pref_list_20201021), .ecc_curves = s2n_ecc_pref_list_20201021, @@ -92,10 +106,10 @@ int s2n_check_ecc_preferences_curves_list(const struct s2n_ecc_preferences *ecc_ for (size_t j = 0; j < s2n_all_supported_curves_list_len; j++) { if (named_curve->iana_id == s2n_all_supported_curves_list[j]->iana_id) { curve_found = 1; - break; + break; } } - check *= curve_found; + check *= curve_found; if (check == 0) { POSIX_BAIL(S2N_ERR_ECDHE_UNSUPPORTED_CURVE); } diff --git a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h index 564d722726..3d4a168264 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h +++ b/contrib/restricted/aws/s2n/tls/s2n_ecc_preferences.h @@ -27,6 +27,7 @@ struct s2n_ecc_preferences { }; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20140601; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20200310; +extern const struct s2n_ecc_preferences s2n_ecc_preferences_default_fips; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20201021; extern const struct s2n_ecc_preferences s2n_ecc_preferences_20210816; extern const struct s2n_ecc_preferences s2n_ecc_preferences_test_all; diff --git a/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c b/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c index 3c490212a7..a1f5c1215f 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c +++ b/contrib/restricted/aws/s2n/tls/s2n_handshake_io.c @@ -1365,6 +1365,11 @@ int s2n_negotiate_impl(struct s2n_connection *conn, s2n_blocked_status *blocked) /* Flush any pending I/O or alert messages */ POSIX_GUARD(s2n_flush(conn, blocked)); + /* If the connection is closed, the handshake will never complete. */ + if (conn->closed) { + POSIX_BAIL(S2N_ERR_CLOSED); + } + /* If the handshake was paused, retry the current message */ if (conn->handshake.paused) { *blocked = S2N_BLOCKED_ON_APPLICATION_INPUT; diff --git a/contrib/restricted/aws/s2n/tls/s2n_security_policies.c b/contrib/restricted/aws/s2n/tls/s2n_security_policies.c index 90c0cb16a3..d8a041aca5 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_security_policies.c +++ b/contrib/restricted/aws/s2n/tls/s2n_security_policies.c @@ -36,6 +36,21 @@ const struct s2n_security_policy security_policy_default_tls13 = { .ecc_preferences = &s2n_ecc_preferences_20200310, }; +/* + * This security policy is derived from the following specification: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf + * + * Supports TLS1.2 + */ +const struct s2n_security_policy security_policy_default_fips = { + .minimum_protocol_version = S2N_TLS12, + .cipher_preferences = &cipher_preferences_default_fips, + .kem_preferences = &kem_preferences_null, + .signature_preferences = &s2n_signature_preferences_default_fips, + .certificate_signature_preferences = &s2n_signature_preferences_default_fips, + .ecc_preferences = &s2n_ecc_preferences_default_fips, +}; + const struct s2n_security_policy security_policy_20190801 = { .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_20190801, @@ -362,7 +377,7 @@ const struct s2n_security_policy security_policy_kms_pq_tls_1_0_2020_02 = { }; const struct s2n_security_policy security_policy_pq_sike_test_tls_1_0_2019_11 = { - .minimum_protocol_version = S2N_TLS10, + .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_pq_sike_test_tls_1_0_2019_11, .kem_preferences = &kem_preferences_pq_sike_test_tls_1_0_2019_11, .signature_preferences = &s2n_signature_preferences_20140601, @@ -370,7 +385,7 @@ const struct s2n_security_policy security_policy_pq_sike_test_tls_1_0_2019_11 = }; const struct s2n_security_policy security_policy_pq_sike_test_tls_1_0_2020_02 = { - .minimum_protocol_version = S2N_TLS10, + .minimum_protocol_version = S2N_TLS10, .cipher_preferences = &cipher_preferences_pq_sike_test_tls_1_0_2020_02, .kem_preferences = &kem_preferences_pq_sike_test_tls_1_0_2020_02, .signature_preferences = &s2n_signature_preferences_20140601, @@ -734,7 +749,7 @@ const struct s2n_security_policy security_policy_null = { struct s2n_security_policy_selection security_policy_selection[] = { { .version="default", .security_policy=&security_policy_20170210, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="default_tls13", .security_policy=&security_policy_default_tls13, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="default_fips", .security_policy=&security_policy_20170405, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="default_fips", .security_policy=&security_policy_default_fips, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="ELBSecurityPolicy-TLS-1-0-2015-04", .security_policy=&security_policy_elb_2015_04, .ecc_extension_required=0, .pq_kem_extension_required=0 }, /* Not a mistake. TLS-1-0-2015-05 and 2016-08 are equivalent */ { .version="ELBSecurityPolicy-TLS-1-0-2015-05", .security_policy=&security_policy_elb_2016_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, @@ -743,9 +758,9 @@ struct s2n_security_policy_selection security_policy_selection[] = { { .version="ELBSecurityPolicy-TLS-1-2-2017-01", .security_policy=&security_policy_elb_tls_1_2_2017_01, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="ELBSecurityPolicy-TLS-1-2-Ext-2018-06", .security_policy=&security_policy_elb_tls_1_2_ext_2018_06, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="ELBSecurityPolicy-FS-2018-06", .security_policy=&security_policy_elb_fs_2018_06, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="ELBSecurityPolicy-FS-1-2-2019-08", .security_policy=&security_policy_elb_fs_1_2_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="ELBSecurityPolicy-FS-1-1-2019-08", .security_policy=&security_policy_elb_fs_1_1_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, - { .version="ELBSecurityPolicy-FS-1-2-Res-2019-08", .security_policy=&security_policy_elb_fs_1_2_Res_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="ELBSecurityPolicy-FS-1-2-2019-08", .security_policy=&security_policy_elb_fs_1_2_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="ELBSecurityPolicy-FS-1-1-2019-08", .security_policy=&security_policy_elb_fs_1_1_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, + { .version="ELBSecurityPolicy-FS-1-2-Res-2019-08", .security_policy=&security_policy_elb_fs_1_2_Res_2019_08, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="CloudFront-Upstream", .security_policy=&security_policy_cloudfront_upstream, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="CloudFront-Upstream-TLS-1-0", .security_policy=&security_policy_cloudfront_upstream_tls10, .ecc_extension_required=0, .pq_kem_extension_required=0 }, { .version="CloudFront-Upstream-TLS-1-1", .security_policy=&security_policy_cloudfront_upstream_tls11, .ecc_extension_required=0, .pq_kem_extension_required=0 }, diff --git a/contrib/restricted/aws/s2n/tls/s2n_security_policies.h b/contrib/restricted/aws/s2n/tls/s2n_security_policies.h index be28fb584a..e4fec2c492 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_security_policies.h +++ b/contrib/restricted/aws/s2n/tls/s2n_security_policies.h @@ -63,6 +63,7 @@ extern const struct s2n_security_policy security_policy_20190214_gcm; extern const struct s2n_security_policy security_policy_20190801; extern const struct s2n_security_policy security_policy_20190802; extern const struct s2n_security_policy security_policy_default_tls13; +extern const struct s2n_security_policy security_policy_default_fips; extern const struct s2n_security_policy security_policy_test_all; extern const struct s2n_security_policy security_policy_test_all_tls12; diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c b/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c index b604556009..f0cb6d6d39 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_extensions.c @@ -58,13 +58,20 @@ int s2n_server_extensions_recv(struct s2n_connection *conn, struct s2n_stuffer * s2n_parsed_extensions_list parsed_extension_list = { 0 }; POSIX_GUARD(s2n_extension_list_parse(in, &parsed_extension_list)); - /* Process supported_versions first so that we know which extensions list to use. + /** + * Process supported_versions first so that we know which extensions list to use. * - If the supported_versions extension exists, then it will set server_protocol_version. * - If the supported_versions extension does not exist, then the server_protocol_version will remain - * unknown and we will use the default list of allowed extension types. */ + * unknown and we will use the default list of allowed extension types. + **/ POSIX_GUARD(s2n_extension_process(&s2n_server_supported_versions_extension, conn, &parsed_extension_list)); if (s2n_is_hello_retry_message(conn)) { + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Otherwise, the client MUST process all extensions in the + *# HelloRetryRequest + */ POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_HELLO_RETRY_REQUEST, conn, &parsed_extension_list)); } else if (conn->server_protocol_version >= S2N_TLS13) { POSIX_GUARD(s2n_extension_list_process(S2N_EXTENSION_LIST_SERVER_HELLO_TLS13, conn, &parsed_extension_list)); diff --git a/contrib/restricted/aws/s2n/tls/s2n_server_hello.c b/contrib/restricted/aws/s2n/tls/s2n_server_hello.c index 632f745478..efe4c08114 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_server_hello.c +++ b/contrib/restricted/aws/s2n/tls/s2n_server_hello.c @@ -37,6 +37,7 @@ #include "utils/s2n_safety.h" #include "utils/s2n_random.h" +#include "utils/s2n_bitmap.h" /* From RFC5246 7.4.1.2. */ #define S2N_TLS_COMPRESSION_METHOD_NULL 0 @@ -51,7 +52,7 @@ const uint8_t tls11_downgrade_protection_bytes[] = { 0x44, 0x4F, 0x57, 0x4E, 0x47, 0x52, 0x44, 0x00 }; -static int s2n_hello_retry_validate(struct s2n_connection *conn) { +static int s2n_random_value_is_hello_retry(struct s2n_connection *conn) { POSIX_ENSURE_REF(conn); POSIX_ENSURE(memcmp(hello_retry_req_random, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN) == 0, @@ -107,9 +108,32 @@ static int s2n_server_hello_parse(struct s2n_connection *conn) POSIX_GUARD(s2n_stuffer_read_bytes(in, protocol_version, S2N_TLS_PROTOCOL_VERSION_LEN)); POSIX_GUARD(s2n_stuffer_read_bytes(in, conn->handshake_params.server_random, S2N_TLS_RANDOM_DATA_LEN)); - /* If the client receives a second HelloRetryRequest in the same connection, it MUST send an error. */ - if (s2n_hello_retry_validate(conn) == S2N_SUCCESS) { + uint8_t legacy_version = (uint8_t)(protocol_version[0] * 10) + protocol_version[1]; + + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.3 + *# Upon receiving a message with type server_hello, implementations MUST + *# first examine the Random value and, if it matches this value, process + *# it as described in Section 4.1.4). + **/ + if (s2n_random_value_is_hello_retry(conn) == S2N_SUCCESS) { + + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# If a client receives a second + *# HelloRetryRequest in the same connection (i.e., where the ClientHello + *# was itself in response to a HelloRetryRequest), it MUST abort the + *# handshake with an "unexpected_message" alert. + **/ POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn), S2N_ERR_INVALID_HELLO_RETRY); + + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Upon receipt of a HelloRetryRequest, the client MUST check the + *# legacy_version + **/ + POSIX_ENSURE(legacy_version == S2N_TLS12, S2N_ERR_INVALID_HELLO_RETRY); + POSIX_GUARD(s2n_set_hello_retry_required(conn)); } @@ -121,6 +145,17 @@ static int s2n_server_hello_parse(struct s2n_connection *conn) POSIX_ENSURE_REF(cipher_suite_wire); POSIX_GUARD(s2n_stuffer_read_uint8(in, &compression_method)); + + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.3 + *# legacy_compression_method: A single byte which MUST have the + *# value 0. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Upon receipt of a HelloRetryRequest, the client MUST check the + *# legacy_version, legacy_session_id_echo, cipher_suite, and + *# legacy_compression_method + **/ S2N_ERROR_IF(compression_method != S2N_TLS_COMPRESSION_METHOD_NULL, S2N_ERR_BAD_MESSAGE); bool session_ids_match = session_id_len != 0 && session_id_len == conn->session_id_len @@ -131,16 +166,43 @@ static int s2n_server_hello_parse(struct s2n_connection *conn) POSIX_GUARD(s2n_server_extensions_recv(conn, in)); + /** + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# The server's extensions MUST contain "supported_versions". + **/ + if (s2n_is_hello_retry_message(conn)) { + s2n_extension_type_id supported_versions_id = s2n_unsupported_extension; + POSIX_GUARD(s2n_extension_supported_iana_value_to_id(TLS_EXTENSION_SUPPORTED_VERSIONS, &supported_versions_id)); + POSIX_ENSURE(S2N_CBIT_TEST(conn->extension_responses_received, supported_versions_id), + S2N_ERR_MISSING_EXTENSION); + } + if (conn->server_protocol_version >= S2N_TLS13) { + + /** + *= https://www.rfc-editor.org/rfc/rfc8446#section-4.1.3 + *# A client which + *# receives a legacy_session_id_echo field that does not match what + *# it sent in the ClientHello MUST abort the handshake with an + *# "illegal_parameter" alert. + * + *= https://tools.ietf.org/rfc/rfc8446#4.1.4 + *# Upon receipt of a HelloRetryRequest, the client MUST check the + *# legacy_version, legacy_session_id_echo + **/ POSIX_ENSURE(session_ids_match || (session_id_len == 0 && conn->session_id_len == 0), S2N_ERR_BAD_MESSAGE); + conn->actual_protocol_version = conn->server_protocol_version; POSIX_GUARD(s2n_set_cipher_as_client(conn, cipher_suite_wire)); } else { - conn->server_protocol_version = (uint8_t)(protocol_version[0] * 10) + protocol_version[1]; + conn->server_protocol_version = legacy_version; POSIX_ENSURE(!s2n_client_detect_downgrade_mechanism(conn), S2N_ERR_PROTOCOL_DOWNGRADE_DETECTED); POSIX_ENSURE(!s2n_connection_is_quic_enabled(conn), S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED); + /* Hello retries are only supported in >=TLS1.3. */ + POSIX_ENSURE(!s2n_is_hello_retry_handshake(conn), S2N_ERR_BAD_MESSAGE); + /* *= https://tools.ietf.org/rfc/rfc8446#appendix-D.3 *# A client that attempts to send 0-RTT data MUST fail a connection if diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c index 6ccddacab6..2ccc0fd651 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.c @@ -260,6 +260,28 @@ const struct s2n_signature_scheme* const s2n_sig_scheme_pref_list_20200207[] = { &s2n_ecdsa_sha1, }; +/* + * These signature schemes were chosen based on the following specification: + * https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-52r2.pdf + */ +const struct s2n_signature_scheme* const s2n_sig_scheme_pref_list_default_fips[] = { + /* RSA PKCS1 - TLS1.2 */ + &s2n_rsa_pkcs1_sha256, + &s2n_rsa_pkcs1_sha384, + &s2n_rsa_pkcs1_sha512, + + /* ECDSA - TLS 1.2 */ + &s2n_ecdsa_sha256, /* same iana value as TLS 1.3 s2n_ecdsa_secp256r1_sha256 */ + &s2n_ecdsa_sha384, /* same iana value as TLS 1.3 s2n_ecdsa_secp384r1_sha384 */ + &s2n_ecdsa_sha512, + &s2n_ecdsa_sha224, +}; + +const struct s2n_signature_preferences s2n_signature_preferences_default_fips = { + .count = s2n_array_len(s2n_sig_scheme_pref_list_default_fips), + .signature_schemes = s2n_sig_scheme_pref_list_default_fips, +}; + /* Add s2n_ecdsa_secp521r1_sha512 */ const struct s2n_signature_scheme* const s2n_sig_scheme_pref_list_20201021[] = { /* RSA PSS */ diff --git a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h index 3f78d8a500..d8eee975ab 100644 --- a/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h +++ b/contrib/restricted/aws/s2n/tls/s2n_signature_scheme.h @@ -77,6 +77,7 @@ extern const struct s2n_signature_preferences s2n_signature_preferences_20140601 extern const struct s2n_signature_preferences s2n_signature_preferences_20200207; extern const struct s2n_signature_preferences s2n_signature_preferences_20201021; extern const struct s2n_signature_preferences s2n_signature_preferences_20210816; +extern const struct s2n_signature_preferences s2n_signature_preferences_default_fips; extern const struct s2n_signature_preferences s2n_signature_preferences_null; extern const struct s2n_signature_preferences s2n_certificate_signature_preferences_20201110; diff --git a/contrib/restricted/aws/s2n/utils/s2n_random.c b/contrib/restricted/aws/s2n/utils/s2n_random.c index 295c87006f..9c0efc0f9f 100644 --- a/contrib/restricted/aws/s2n/utils/s2n_random.c +++ b/contrib/restricted/aws/s2n/utils/s2n_random.c @@ -14,6 +14,7 @@ */ #include <openssl/engine.h> +#include <openssl/rand.h> #include <sys/types.h> #include <sys/stat.h> @@ -28,25 +29,20 @@ #include <errno.h> #include <time.h> -#include "api/s2n.h" - #if defined(S2N_CPUID_AVAILABLE) #include <cpuid.h> #endif -#include "stuffer/s2n_stuffer.h" - +#include "api/s2n.h" #include "crypto/s2n_drbg.h" - #include "error/s2n_errno.h" - +#include "stuffer/s2n_stuffer.h" +#include "utils/s2n_fork_detection.h" #include "utils/s2n_result.h" #include "utils/s2n_safety.h" #include "utils/s2n_random.h" #include "utils/s2n_mem.h" -#include <openssl/rand.h> - #define ENTROPY_SOURCE "/dev/urandom" /* See https://en.wikipedia.org/wiki/CPUID */ @@ -60,14 +56,19 @@ static int entropy_fd = UNINITIALIZED_ENTROPY_FD; -static __thread struct s2n_drbg per_thread_private_drbg = {0}; -static __thread struct s2n_drbg per_thread_public_drbg = {0}; - -static void *zeroed_when_forked_page = NULL; -static int zero = 0; +struct s2n_rand_state { + uint64_t cached_fork_generation_number; + struct s2n_drbg public_drbg; + struct s2n_drbg private_drbg; + bool drbgs_initialized; +}; -static __thread void *zero_if_forked_ptr = &zero; -#define zero_if_forked (* (int *) zero_if_forked_ptr) +static __thread struct s2n_rand_state s2n_per_thread_rand_state = { + .cached_fork_generation_number = 0, + .public_drbg = {0}, + .private_drbg = {0}, + .drbgs_initialized = false +}; static int s2n_rand_init_impl(void); static int s2n_rand_cleanup_impl(void); @@ -79,6 +80,7 @@ static s2n_rand_cleanup_callback s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; static s2n_rand_seed_callback s2n_rand_seed_cb = s2n_rand_urandom_impl; static s2n_rand_mix_callback s2n_rand_mix_cb = s2n_rand_urandom_impl; +/* non-static for SAW proof */ bool s2n_cpu_supports_rdrand() { #if defined(S2N_CPUID_AVAILABLE) uint32_t eax, ebx, ecx, edx; @@ -128,65 +130,74 @@ S2N_RESULT s2n_get_mix_entropy(struct s2n_blob *blob) return S2N_RESULT_OK; } -void s2n_on_fork(void) -{ - zero_if_forked = 0; -} - -static inline S2N_RESULT s2n_defend_if_forked(void) +static S2N_RESULT s2n_init_drbgs(void) { uint8_t s2n_public_drbg[] = "s2n public drbg"; uint8_t s2n_private_drbg[] = "s2n private drbg"; - struct s2n_blob public = {.data = s2n_public_drbg,.size = sizeof(s2n_public_drbg) }; - struct s2n_blob private = {.data = s2n_private_drbg,.size = sizeof(s2n_private_drbg) }; + struct s2n_blob public = { .data = s2n_public_drbg, .size = sizeof(s2n_public_drbg) }; + struct s2n_blob private = { .data = s2n_private_drbg, .size = sizeof(s2n_private_drbg) }; - if (zero_if_forked == 0) { - /* Clean up the old drbg first */ - RESULT_GUARD(s2n_rand_cleanup_thread()); - /* Instantiate the new ones */ - RESULT_GUARD(s2n_drbg_instantiate(&per_thread_public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); - RESULT_GUARD(s2n_drbg_instantiate(&per_thread_private_drbg, &private, S2N_AES_128_CTR_NO_DF_PR)); - zero_if_forked_ptr = zeroed_when_forked_page; - zero_if_forked = 1; - } + RESULT_GUARD(s2n_drbg_instantiate(&s2n_per_thread_rand_state.public_drbg, &public, S2N_AES_128_CTR_NO_DF_PR)); + RESULT_GUARD(s2n_drbg_instantiate(&s2n_per_thread_rand_state.private_drbg, &private, S2N_AES_256_CTR_NO_DF_PR)); + + s2n_per_thread_rand_state.drbgs_initialized = true; return S2N_RESULT_OK; } -S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) +static S2N_RESULT s2n_ensure_initialized_drbgs(void) { - RESULT_GUARD(s2n_defend_if_forked()); + if (s2n_per_thread_rand_state.drbgs_initialized == false) { + RESULT_GUARD(s2n_init_drbgs()); - uint32_t offset = 0; - uint32_t remaining = blob->size; + /* Then cache the fork generation number. We just initialized the drbg + * states with new entropy and forking is not an external event. + */ + uint64_t returned_fork_generation_number = 0; + RESULT_GUARD(s2n_get_fork_generation_number(&returned_fork_generation_number)); + s2n_per_thread_rand_state.cached_fork_generation_number = returned_fork_generation_number; + } - while(remaining) { - struct s2n_blob slice = { 0 }; + return S2N_RESULT_OK; +} - RESULT_GUARD_POSIX(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; +/* s2n_ensure_uniqueness() implements defenses against uniqueness + * breaking events that might cause duplicated drbg states. Currently, only + * implements fork detection. + */ +static S2N_RESULT s2n_ensure_uniqueness(void) +{ + uint64_t returned_fork_generation_number = 0; + RESULT_GUARD(s2n_get_fork_generation_number(&returned_fork_generation_number)); - RESULT_GUARD(s2n_drbg_generate(&per_thread_public_drbg, &slice)); + if (returned_fork_generation_number != s2n_per_thread_rand_state.cached_fork_generation_number) { - remaining -= slice.size; - offset += slice.size; + /* This assumes that s2n_rand_cleanup_thread() doesn't mutate any other + * state than the drbg states and it resets the drbg initialization + * boolean to false. s2n_ensure_initialized_drbgs() will cache the new + * fork generation number in the per thread state. + */ + RESULT_GUARD(s2n_rand_cleanup_thread()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); } return S2N_RESULT_OK; } -S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) +static S2N_RESULT s2n_get_random_data(struct s2n_blob *out_blob, + struct s2n_drbg *drbg_state) { - RESULT_GUARD(s2n_defend_if_forked()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); + RESULT_GUARD(s2n_ensure_uniqueness()); uint32_t offset = 0; - uint32_t remaining = blob->size; + uint32_t remaining = out_blob->size; while(remaining) { struct s2n_blob slice = { 0 }; - RESULT_GUARD_POSIX(s2n_blob_slice(blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT)));; - - RESULT_GUARD(s2n_drbg_generate(&per_thread_private_drbg, &slice)); + RESULT_GUARD_POSIX(s2n_blob_slice(out_blob, &slice, offset, MIN(remaining, S2N_DRBG_GENERATE_LIMIT))); + RESULT_GUARD(s2n_drbg_generate(drbg_state, &slice)); remaining -= slice.size; offset += slice.size; @@ -195,15 +206,29 @@ S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) return S2N_RESULT_OK; } +S2N_RESULT s2n_get_public_random_data(struct s2n_blob *blob) +{ + RESULT_GUARD(s2n_get_random_data(blob, &s2n_per_thread_rand_state.public_drbg)); + + return S2N_RESULT_OK; +} + +S2N_RESULT s2n_get_private_random_data(struct s2n_blob *blob) +{ + RESULT_GUARD(s2n_get_random_data(blob, &s2n_per_thread_rand_state.private_drbg)); + + return S2N_RESULT_OK; +} + S2N_RESULT s2n_get_public_random_bytes_used(uint64_t *bytes_used) { - RESULT_GUARD(s2n_drbg_bytes_used(&per_thread_public_drbg, bytes_used)); + RESULT_GUARD(s2n_drbg_bytes_used(&s2n_per_thread_rand_state.public_drbg, bytes_used)); return S2N_RESULT_OK; } S2N_RESULT s2n_get_private_random_bytes_used(uint64_t *bytes_used) { - RESULT_GUARD(s2n_drbg_bytes_used(&per_thread_private_drbg, bytes_used)); + RESULT_GUARD(s2n_drbg_bytes_used(&s2n_per_thread_rand_state.private_drbg, bytes_used)); return S2N_RESULT_OK; } @@ -328,7 +353,7 @@ static int s2n_rand_init_impl(void) { OPEN: entropy_fd = open(ENTROPY_SOURCE, O_RDONLY); - if (entropy_fd == S2N_FAILURE) { + if (entropy_fd == -1) { if (errno == EINTR) { goto OPEN; } @@ -344,33 +369,9 @@ static int s2n_rand_init_impl(void) S2N_RESULT s2n_rand_init(void) { - uint32_t pagesize; - RESULT_GUARD_POSIX(s2n_rand_init_cb()); - pagesize = s2n_mem_get_page_size(); - - /* We need a single-aligned page for our protected memory region */ - RESULT_ENSURE(posix_memalign(&zeroed_when_forked_page, pagesize, pagesize) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - RESULT_ENSURE(zeroed_when_forked_page != NULL, S2N_ERR_OPEN_RANDOM); - - /* Initialized to zero to ensure that we seed our DRBGs */ - zero_if_forked = 0; - - /* INHERIT_ZERO and WIPEONFORK reset a page to all-zeroes when a fork occurs */ -#if defined(MAP_INHERIT_ZERO) - RESULT_ENSURE(minherit(zeroed_when_forked_page, pagesize, MAP_INHERIT_ZERO) != S2N_FAILURE, S2N_ERR_OPEN_RANDOM); -#endif - -#if defined(MADV_WIPEONFORK) - RESULT_ENSURE(madvise(zeroed_when_forked_page, pagesize, MADV_WIPEONFORK) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); -#endif - - /* For defence in depth */ - RESULT_ENSURE(pthread_atfork(NULL, NULL, s2n_on_fork) == S2N_SUCCESS, S2N_ERR_OPEN_RANDOM); - - /* Seed everything */ - RESULT_GUARD(s2n_defend_if_forked()); + RESULT_GUARD(s2n_ensure_initialized_drbgs()); #if S2N_LIBCRYPTO_SUPPORTS_CUSTOM_RAND /* Create an engine */ @@ -423,12 +424,6 @@ S2N_RESULT s2n_rand_cleanup(void) } #endif - if (zeroed_when_forked_page != NULL) { - free(zeroed_when_forked_page); - zeroed_when_forked_page = NULL; - zero_if_forked_ptr = &zero; - } - s2n_rand_init_cb = s2n_rand_init_impl; s2n_rand_cleanup_cb = s2n_rand_cleanup_impl; s2n_rand_seed_cb = s2n_rand_urandom_impl; @@ -439,22 +434,29 @@ S2N_RESULT s2n_rand_cleanup(void) S2N_RESULT s2n_rand_cleanup_thread(void) { - RESULT_GUARD(s2n_drbg_wipe(&per_thread_private_drbg)); - RESULT_GUARD(s2n_drbg_wipe(&per_thread_public_drbg)); + /* Currently, it is only safe for this function to mutate the drbg states + * in the per thread rand state. See s2n_ensure_uniqueness(). + */ + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.private_drbg)); + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.public_drbg)); + + s2n_per_thread_rand_state.drbgs_initialized = false; return S2N_RESULT_OK; } -/* - * This must only be used for unit tests. Any real use is dangerous and will be overwritten in s2n_defend_if_forked if - * it is forked. This was added to support known answer tests that use OpenSSL and s2n_get_private_random_data directly. +/* This must only be used for unit tests. Any real use is dangerous and will be + * overwritten in s2n_ensure_uniqueness() if it is forked. This was added to + * support known answer tests that use OpenSSL and s2n_get_private_random_data + * directly. */ S2N_RESULT s2n_set_private_drbg_for_test(struct s2n_drbg drbg) { RESULT_ENSURE(s2n_in_unit_test(), S2N_ERR_NOT_IN_UNIT_TEST); - RESULT_GUARD(s2n_drbg_wipe(&per_thread_private_drbg)); + RESULT_GUARD(s2n_drbg_wipe(&s2n_per_thread_rand_state.private_drbg)); + + s2n_per_thread_rand_state.private_drbg = drbg; - per_thread_private_drbg = drbg; return S2N_RESULT_OK; } |